Skip to content

Commit 33ff948

Browse files
committed
PluginNotificationTask::ScriptFunc(): on Linux truncate output and comment
not to run into an exec(3) error E2BIG due to a too long argument. This sends a notification with truncated output instead of not sending.
1 parent 2d167cc commit 33ff948

File tree

3 files changed

+121
-1
lines changed

3 files changed

+121
-1
lines changed

lib/methods/pluginnotificationtask.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@
1212
#include "base/process.hpp"
1313
#include "base/convert.hpp"
1414

15+
#ifdef __linux__
16+
# include <linux/binfmts.h>
17+
# include <unistd.h>
18+
19+
# ifndef PAGE_SIZE
20+
# define PAGE_SIZE getpagesize()
21+
# endif /* PAGE_SIZE */
22+
23+
const static auto l_MaxOutLen = MAX_ARG_STRLEN * 3u / 4u;
24+
#endif /* __linux__ */
25+
1526
using namespace icinga;
1627

1728
REGISTER_FUNCTION_NONCONST(Internal, PluginNotification, &PluginNotificationTask::ScriptFunc, "notification:user:cr:itype:author:comment:resolvedMacros:useResolvedMacros");
@@ -33,7 +44,11 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification,
3344
Dictionary::Ptr notificationExtra = new Dictionary({
3445
{ "type", Notification::NotificationTypeToStringCompat(type) }, //TODO: Change that to our types.
3546
{ "author", author },
47+
#ifdef __linux__
48+
{ "comment", comment.SubStr(0, l_MaxOutLen) }
49+
#else /* __linux__ */
3650
{ "comment", comment }
51+
#endif /* __linux__ */
3752
});
3853

3954
Host::Ptr host;
@@ -48,8 +63,35 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification,
4863
resolvers.emplace_back("user", user);
4964
resolvers.emplace_back("notification", notificationExtra);
5065
resolvers.emplace_back("notification", notification);
51-
if (service)
66+
67+
if (service) {
68+
#ifdef __linux__
69+
auto cr (service->GetLastCheckResult());
70+
71+
if (cr) {
72+
auto output (cr->GetOutput());
73+
74+
if (output.GetLength() > l_MaxOutLen) {
75+
resolvers.emplace_back("service", new Dictionary({{"output", output.SubStr(0, l_MaxOutLen)}}));
76+
}
77+
}
78+
#endif /* __linux__ */
79+
5280
resolvers.emplace_back("service", service);
81+
}
82+
83+
#ifdef __linux__
84+
auto hcr (host->GetLastCheckResult());
85+
86+
if (hcr) {
87+
auto output (hcr->GetOutput());
88+
89+
if (output.GetLength() > l_MaxOutLen) {
90+
resolvers.emplace_back("host", new Dictionary({{"output", output.SubStr(0, l_MaxOutLen)}}));
91+
}
92+
}
93+
#endif /* __linux__ */
94+
5395
resolvers.emplace_back("host", host);
5496
resolvers.emplace_back("command", commandObj);
5597

test/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ set(base_test_SOURCES
3131
icinga-macros.cpp
3232
icinga-notification.cpp
3333
icinga-perfdata.cpp
34+
methods-pluginnotificationtask.cpp
3435
remote-configpackageutility.cpp
3536
remote-url.cpp
3637
${base_OBJS}
3738
$<TARGET_OBJECTS:config>
3839
$<TARGET_OBJECTS:remote>
3940
$<TARGET_OBJECTS:icinga>
41+
$<TARGET_OBJECTS:methods>
4042
)
4143

4244
if(ICINGA2_UNITY_BUILD)
@@ -156,6 +158,7 @@ add_boost_test(base
156158
icinga_perfdata/multi
157159
icinga_perfdata/scientificnotation
158160
icinga_perfdata/parse_edgecases
161+
methods_pluginnotificationtask/truncate_long_output
159162
remote_configpackageutility/ValidateName
160163
remote_url/id_and_path
161164
remote_url/parameters
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* Icinga 2 | (c) 2023 Icinga GmbH | GPLv2+ */
2+
3+
#include "base/array.hpp"
4+
#include "icinga/checkresult.hpp"
5+
#include "icinga/host.hpp"
6+
#include "icinga/notification.hpp"
7+
#include "icinga/notificationcommand.hpp"
8+
#include "icinga/service.hpp"
9+
#include "icinga/user.hpp"
10+
#include "methods/pluginnotificationtask.hpp"
11+
#include <BoostTestTargetConfig.h>
12+
#include <future>
13+
14+
using namespace icinga;
15+
16+
BOOST_AUTO_TEST_SUITE(methods_pluginnotificationtask)
17+
18+
BOOST_AUTO_TEST_CASE(truncate_long_output)
19+
{
20+
#ifdef __linux__
21+
Host::Ptr h = new Host();
22+
CheckResult::Ptr hcr = new CheckResult();
23+
CheckResult::Ptr scr = new CheckResult();
24+
Service::Ptr s = new Service();
25+
User::Ptr u = new User();
26+
NotificationCommand::Ptr nc = new NotificationCommand();
27+
Notification::Ptr n = new Notification();
28+
String placeHolder (1024 * 1024, 'x');
29+
std::promise<Value> promise;
30+
auto future (promise.get_future());
31+
32+
hcr->SetOutput("H" + placeHolder + "h", true);
33+
scr->SetOutput("S" + placeHolder + "s", true);
34+
35+
h->SetName("example.com", true);
36+
h->SetLastCheckResult(hcr, true);
37+
h->Register();
38+
39+
s->SetHostName("example.com", true);
40+
s->SetShortName("disk", true);
41+
s->SetLastCheckResult(scr, true);
42+
((ConfigObject*)s.get())->OnAllConfigLoaded(); // link Host
43+
44+
nc->SetName("mail", true);
45+
nc->SetCommandLine(new Array({"echo", "$host.output$", "$service.output$", "$notification.comment$"}), true);
46+
nc->Register();
47+
48+
n->SetFieldByName("host_name", "example.com", false, DebugInfo());
49+
n->SetFieldByName("service_name", "disk", false, DebugInfo());
50+
n->SetFieldByName("command", "mail", false, DebugInfo());
51+
((ConfigObject*)n.get())->OnAllConfigLoaded(); // link Service
52+
53+
Checkable::ExecuteCommandProcessFinishedHandler = [&promise](const Value& commandline, const ProcessResult&) {
54+
promise.set_value(commandline);
55+
};
56+
57+
PluginNotificationTask::ScriptFunc(n, u, nullptr, NotificationCustom, "jdoe", "C" + placeHolder + "c", nullptr, false);
58+
future.wait();
59+
60+
Checkable::ExecuteCommandProcessFinishedHandler = nullptr;
61+
h->Unregister();
62+
nc->Unregister();
63+
64+
String commandline = Array::Ptr(future.get())->Join(" ");
65+
66+
BOOST_CHECK(commandline.Contains("echo Hx"));
67+
BOOST_CHECK(!commandline.Contains("xh"));
68+
BOOST_CHECK(commandline.Contains("x Sx"));
69+
BOOST_CHECK(!commandline.Contains("xs"));
70+
BOOST_CHECK(commandline.Contains("x Cx"));
71+
BOOST_CHECK(!commandline.Contains("xc"));
72+
#endif /* __linux__ */
73+
}
74+
75+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)