Skip to content

Commit e63008f

Browse files
committed
Process: if exec(3) fails with "Argument list too long", truncate the input
starting with the longest strings until it's small enough. This way no string gets discarted completely in favor of a longer one before it. Also, the computation happens only if necessary and in the already fork(2)ed child process. The pragmatic implementation doesn't even try to mimic kernels' limits perfectly.
1 parent 76b460c commit e63008f

File tree

1 file changed

+44
-9
lines changed

1 file changed

+44
-9
lines changed

lib/base/process.cpp

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@
1111
#include "base/utility.hpp"
1212
#include "base/scriptglobal.hpp"
1313
#include "base/json.hpp"
14+
#include <algorithm>
15+
#include <cmath>
1416
#include <boost/algorithm/string/join.hpp>
1517
#include <boost/thread/once.hpp>
1618
#include <thread>
1719
#include <iostream>
1820

1921
#ifndef _WIN32
22+
# include <errno.h>
2023
# include <execvpe.h>
2124
# include <poll.h>
2225
# include <string.h>
@@ -174,16 +177,48 @@ static Value ProcessSpawnImpl(struct msghdr *msgh, const Dictionary::Ptr& reques
174177
sigemptyset(&mask);
175178
sigprocmask(SIG_SETMASK, &mask, nullptr);
176179

177-
if (icinga2_execvpe(argv[0], argv, envp) < 0) {
178-
char errmsg[512];
179-
strcpy(errmsg, "execvpe(");
180-
strncat(errmsg, argv[0], sizeof(errmsg) - strlen(errmsg) - 1);
181-
strncat(errmsg, ") failed", sizeof(errmsg) - strlen(errmsg) - 1);
182-
errmsg[sizeof(errmsg) - 1] = '\0';
183-
perror(errmsg);
184-
}
180+
for (;;) {
181+
if (icinga2_execvpe(argv[0], argv, envp) < 0) {
182+
if (errno == E2BIG) {
183+
size_t longest = 0;
184+
185+
for (auto strings : {argv, envp}) {
186+
for (auto s (strings); *s; ++s) {
187+
longest = std::max(longest, strlen(*s));
188+
}
189+
}
190+
191+
if (longest) {
192+
size_t cutoff = exp2(floor(log2(longest)));
193+
194+
while (cutoff >= longest) {
195+
cutoff /= 2u;
196+
}
197+
198+
for (auto strings : {argv, envp}) {
199+
for (auto s (strings); *s; ++s) {
200+
auto str (*s);
201+
202+
if (strlen(str) > cutoff) {
203+
str[cutoff] = 0;
204+
}
205+
}
206+
}
185207

186-
_exit(128);
208+
continue;
209+
}
210+
}
211+
212+
char errmsg[512];
213+
strcpy(errmsg, "execvpe(");
214+
strncat(errmsg, argv[0], sizeof(errmsg) - strlen(errmsg) - 1);
215+
strncat(errmsg, ") failed", sizeof(errmsg) - strlen(errmsg) - 1);
216+
errmsg[sizeof(errmsg) - 1] = '\0';
217+
perror(errmsg);
218+
}
219+
220+
_exit(128);
221+
}
187222
}
188223

189224
(void)close(fds[0]);

0 commit comments

Comments
 (0)