Skip to content

Commit ec02c76

Browse files
authored
Fix setproctitle related crashes. (redis#8150)
Makes spt_init more careful with assumptions about what memory regions may be overwritten. It will now only consider a contiguous block of argv and envp elements and mind any gaps.
1 parent 09b7f6c commit ec02c76

1 file changed

Lines changed: 39 additions & 4 deletions

File tree

src/setproctitle.c

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,16 @@ static int spt_copyargs(int argc, char *argv[]) {
178178
return 0;
179179
} /* spt_copyargs() */
180180

181-
181+
/* Initialize and populate SPT to allow a future setproctitle()
182+
* call.
183+
*
184+
* As setproctitle() basically needs to overwrite argv[0], we're
185+
* trying to determine what is the largest contiguous block
186+
* starting at argv[0] we can use for this purpose.
187+
*
188+
* As this range will overwrite some or all of the argv and environ
189+
* strings, a deep copy of these two arrays is performed.
190+
*/
182191
void spt_init(int argc, char *argv[]) {
183192
char **envp = environ;
184193
char *base, *end, *nul, *tmp;
@@ -187,24 +196,39 @@ void spt_init(int argc, char *argv[]) {
187196
if (!(base = argv[0]))
188197
return;
189198

199+
/* We start with end pointing at the end of argv[0] */
190200
nul = &base[strlen(base)];
191201
end = nul + 1;
192202

203+
/* Attempt to extend end as far as we can, while making sure
204+
* that the range between base and end is only allocated to
205+
* argv, or anything that immediately follows argv (presumably
206+
* envp).
207+
*/
193208
for (i = 0; i < argc || (i >= argc && argv[i]); i++) {
194209
if (!argv[i] || argv[i] < end)
195210
continue;
196211

197-
end = argv[i] + strlen(argv[i]) + 1;
212+
if (end >= argv[i] && end <= argv[i] + strlen(argv[i]))
213+
end = argv[i] + strlen(argv[i]) + 1;
198214
}
199215

216+
/* In case the envp array was not an immediate extension to argv,
217+
* scan it explicitly.
218+
*/
200219
for (i = 0; envp[i]; i++) {
201220
if (envp[i] < end)
202221
continue;
203222

204-
end = envp[i] + strlen(envp[i]) + 1;
223+
if (end >= envp[i] && end <= envp[i] + strlen(envp[i]))
224+
end = envp[i] + strlen(envp[i]) + 1;
205225
}
206226
envc = i;
207227

228+
/* We're going to deep copy argv[], but argv[0] will still point to
229+
* the old memory for the purpose of updating the title so we need
230+
* to keep the original value elsewhere.
231+
*/
208232
if (!(SPT.arg0 = strdup(argv[0])))
209233
goto syerr;
210234

@@ -225,7 +249,7 @@ void spt_init(int argc, char *argv[]) {
225249
setprogname(tmp);
226250
#endif
227251

228-
252+
/* Now make a full deep copy of the environment and argv[] */
229253
if ((error = spt_copyenv(envc, envp)))
230254
goto error;
231255

@@ -294,3 +318,14 @@ void setproctitle(const char *fmt, ...) {
294318

295319
#endif /* __linux || __APPLE__ */
296320
#endif /* !HAVE_SETPROCTITLE */
321+
322+
#ifdef SETPROCTITLE_TEST_MAIN
323+
int main(int argc, char *argv[]) {
324+
spt_init(argc, argv);
325+
326+
printf("SPT.arg0: [%p] '%s'\n", SPT.arg0, SPT.arg0);
327+
printf("SPT.base: [%p] '%s'\n", SPT.base, SPT.base);
328+
printf("SPT.end: [%p] (%d bytes after base)'\n", SPT.end, (int) (SPT.end - SPT.base));
329+
return 0;
330+
}
331+
#endif

0 commit comments

Comments
 (0)