Skip to content

Commit a93e2f6

Browse files
authored
Merge pull request systemd#6518 from joukewitteveen/process-rename
process-util: update the end pointer of the process name on rename
2 parents 785889e + 049c884 commit a93e2f6

File tree

2 files changed

+69
-34
lines changed

2 files changed

+69
-34
lines changed

src/basic/process-util.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -312,19 +312,18 @@ int rename_process(const char name[]) {
312312
/* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but
313313
* has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at
314314
* the end. This is the best option for changing /proc/self/cmdline. */
315-
if (mm_size < l+1) {
315+
316+
/* Let's not bother with this if we don't have euid == 0. Strictly speaking we should check for the
317+
* CAP_SYS_RESOURCE capability which is independent of the euid. In our own code the capability generally is
318+
* present only for euid == 0, hence let's use this as quick bypass check, to avoid calling mmap() if
319+
* PR_SET_MM_ARG_{START,END} fails with EPERM later on anyway. After all geteuid() is dead cheap to call, but
320+
* mmap() is not. */
321+
if (geteuid() != 0)
322+
log_debug("Skipping PR_SET_MM, as we don't have privileges.");
323+
else if (mm_size < l+1) {
316324
size_t nn_size;
317325
char *nn;
318326

319-
/* Let's not bother with this if we don't have euid == 0. Strictly speaking if people do weird stuff
320-
* with capabilities this could work even for euid != 0, but our own code generally doesn't do that,
321-
* hence let's use this as quick bypass check, to avoid calling mmap() if PR_SET_MM_ARG_START fails
322-
* with EPERM later on anyway. After all geteuid() is dead cheap to call, but mmap() is not. */
323-
if (geteuid() != 0) {
324-
log_debug("Skipping PR_SET_MM_ARG_START, as we don't have privileges.");
325-
goto use_saved_argv;
326-
}
327-
328327
nn_size = PAGE_ALIGN(l+1);
329328
nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
330329
if (nn == MAP_FAILED) {
@@ -351,9 +350,14 @@ int rename_process(const char name[]) {
351350

352351
mm = nn;
353352
mm_size = nn_size;
354-
} else
353+
} else {
355354
strncpy(mm, name, mm_size);
356355

356+
/* Update the end pointer, continuing regardless of any failure. */
357+
if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0)
358+
log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
359+
}
360+
357361
use_saved_argv:
358362
/* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if
359363
* it still looks here */

src/test/test-process-util.c

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -355,50 +355,80 @@ static void test_get_process_cmdline_harder(void) {
355355
_exit(0);
356356
}
357357

358-
static void test_rename_process_one(const char *p, int ret) {
358+
static void test_rename_process_now(const char *p, int ret) {
359359
_cleanup_free_ char *comm = NULL, *cmdline = NULL;
360-
pid_t pid;
361360
int r;
362361

363-
pid = fork();
364-
assert_se(pid >= 0);
365-
366-
if (pid > 0) {
367-
siginfo_t si;
368-
369-
assert_se(wait_for_terminate(pid, &si) >= 0);
370-
assert_se(si.si_code == CLD_EXITED);
371-
assert_se(si.si_status == EXIT_SUCCESS);
372-
373-
return;
374-
}
375-
376-
/* child */
377362
r = rename_process(p);
378-
379363
assert_se(r == ret ||
380364
(ret == 0 && r >= 0) ||
381365
(ret > 0 && r > 0));
382366

383367
if (r < 0)
384-
goto finish;
368+
return;
385369

386370
#ifdef HAVE_VALGRIND_VALGRIND_H
387371
/* see above, valgrind is weird, we can't verify what we are doing here */
388372
if (RUNNING_ON_VALGRIND)
389-
goto finish;
373+
return;
390374
#endif
391375

392376
assert_se(get_process_comm(0, &comm) >= 0);
393377
log_info("comm = <%s>", comm);
394378
assert_se(strneq(comm, p, 15));
395379

396380
assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0);
397-
log_info("cmdline = <%s>", cmdline);
398-
assert_se(strneq(p, cmdline, strlen("test-process-util")));
399-
assert_se(startswith(p, cmdline));
381+
/* we cannot expect cmdline to be renamed properly without privileges */
382+
if (geteuid() == 0) {
383+
log_info("cmdline = <%s>", cmdline);
384+
assert_se(strneq(p, cmdline, strlen("test-process-util")));
385+
assert_se(startswith(p, cmdline));
386+
} else
387+
log_info("cmdline = <%s> (not verified)", cmdline);
388+
}
400389

401-
finish:
390+
static void test_rename_process_one(const char *p, int ret) {
391+
siginfo_t si;
392+
pid_t pid;
393+
394+
pid = fork();
395+
assert_se(pid >= 0);
396+
397+
if (pid == 0) {
398+
/* child */
399+
test_rename_process_now(p, ret);
400+
_exit(EXIT_SUCCESS);
401+
}
402+
403+
assert_se(wait_for_terminate(pid, &si) >= 0);
404+
assert_se(si.si_code == CLD_EXITED);
405+
assert_se(si.si_status == EXIT_SUCCESS);
406+
}
407+
408+
static void test_rename_process_multi(void) {
409+
pid_t pid;
410+
411+
pid = fork();
412+
assert_se(pid >= 0);
413+
414+
if (pid > 0) {
415+
siginfo_t si;
416+
417+
assert_se(wait_for_terminate(pid, &si) >= 0);
418+
assert_se(si.si_code == CLD_EXITED);
419+
assert_se(si.si_status == EXIT_SUCCESS);
420+
421+
return;
422+
}
423+
424+
/* child */
425+
test_rename_process_now("one", 1);
426+
test_rename_process_now("more", 0); /* longer than "one", hence truncated */
427+
setresuid(99, 99, 99);
428+
test_rename_process_now("time!", 0);
429+
test_rename_process_now("0", 1); /* shorter than "one", should fit */
430+
test_rename_process_one("", -EINVAL);
431+
test_rename_process_one(NULL, -EINVAL);
402432
_exit(EXIT_SUCCESS);
403433
}
404434

@@ -408,6 +438,7 @@ static void test_rename_process(void) {
408438
test_rename_process_one("foo", 1); /* should always fit */
409439
test_rename_process_one("this is a really really long process name, followed by some more words", 0); /* unlikely to fit */
410440
test_rename_process_one("1234567", 1); /* should always fit */
441+
test_rename_process_multi(); /* multiple invocations and dropped privileges */
411442
}
412443

413444
static void test_getpid_cached(void) {

0 commit comments

Comments
 (0)