| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| |
| #include <sched.h> |
| #include <unistd.h> |
| |
| #if HAVE_VALGRIND_VALGRIND_H |
| # include <valgrind/valgrind.h> |
| #endif |
| |
| #include "argv-util.h" |
| #include "missing_sched.h" |
| #include "process-util.h" |
| #include "tests.h" |
| #include "virt.h" |
| |
| static void test_rename_process_now(const char *p, int ret) { |
| _cleanup_free_ char *comm = NULL, *cmdline = NULL; |
| int r; |
| |
| log_info("/* %s(%s) */", __func__, p); |
| |
| r = rename_process(p); |
| assert_se(r == ret || |
| (ret == 0 && r >= 0) || |
| (ret > 0 && r > 0)); |
| |
| log_debug_errno(r, "rename_process(%s): %m", p); |
| |
| if (r < 0) |
| return; |
| |
| #if HAVE_VALGRIND_VALGRIND_H |
| /* see above, valgrind is weird, we can't verify what we are doing here */ |
| if (RUNNING_ON_VALGRIND) |
| return; |
| #endif |
| |
| assert_se(get_process_comm(0, &comm) >= 0); |
| log_debug("comm = <%s>", comm); |
| assert_se(strneq(comm, p, TASK_COMM_LEN-1)); |
| /* We expect comm to be at most 16 bytes (TASK_COMM_LEN). The kernel may raise this limit in the |
| * future. We'd only check the initial part, at least until we recompile, but this will still pass. */ |
| |
| r = get_process_cmdline(0, SIZE_MAX, 0, &cmdline); |
| assert_se(r >= 0); |
| /* we cannot expect cmdline to be renamed properly without privileges */ |
| if (geteuid() == 0) { |
| if (r == 0 && detect_container() > 0) |
| log_info("cmdline = <%s> (not verified, Running in unprivileged container?)", cmdline); |
| else { |
| log_info("cmdline = <%s> (expected <%.*s>)", cmdline, (int) strlen("test-process-util"), p); |
| |
| bool skip = cmdline[0] == '"'; /* A shortcut to check if the string is quoted */ |
| |
| assert_se(strneq(cmdline + skip, p, strlen("test-process-util"))); |
| assert_se(startswith(cmdline + skip, p)); |
| } |
| } else |
| log_info("cmdline = <%s> (not verified)", cmdline); |
| } |
| |
| static void test_rename_process_one(const char *p, int ret) { |
| siginfo_t si; |
| pid_t pid; |
| |
| log_info("/* %s(%s) */", __func__, p); |
| |
| pid = fork(); |
| assert_se(pid >= 0); |
| |
| if (pid == 0) { |
| /* child */ |
| test_rename_process_now(p, ret); |
| _exit(EXIT_SUCCESS); |
| } |
| |
| assert_se(wait_for_terminate(pid, &si) >= 0); |
| assert_se(si.si_code == CLD_EXITED); |
| assert_se(si.si_status == EXIT_SUCCESS); |
| } |
| |
| TEST(rename_process_invalid) { |
| assert_se(rename_process(NULL) == -EINVAL); |
| assert_se(rename_process("") == -EINVAL); |
| } |
| |
| TEST(rename_process_multi) { |
| pid_t pid; |
| |
| pid = fork(); |
| assert_se(pid >= 0); |
| |
| if (pid > 0) { |
| siginfo_t si; |
| |
| assert_se(wait_for_terminate(pid, &si) >= 0); |
| assert_se(si.si_code == CLD_EXITED); |
| assert_se(si.si_status == EXIT_SUCCESS); |
| |
| return; |
| } |
| |
| /* child */ |
| test_rename_process_now("one", 1); |
| test_rename_process_now("more", 0); /* longer than "one", hence truncated */ |
| (void) setresuid(99, 99, 99); /* change uid when running privileged */ |
| test_rename_process_now("time!", 0); |
| test_rename_process_now("0", 1); /* shorter than "one", should fit */ |
| _exit(EXIT_SUCCESS); |
| } |
| |
| TEST(rename_process) { |
| test_rename_process_one("foo", 1); /* should always fit */ |
| test_rename_process_one("this is a really really long process name, followed by some more words", 0); /* unlikely to fit */ |
| test_rename_process_one("1234567", 1); /* should always fit */ |
| } |
| |
| static int intro(void) { |
| log_show_color(true); |
| return EXIT_SUCCESS; |
| } |
| |
| DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro); |