From: Zbigniew Jędrzejewski-Szmek Date: Wed, 15 May 2019 09:55:59 +0000 (+0200) Subject: util-lib: do not truncate kernel comm names X-Git-Tag: v243-rc1~383^2~5 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fsystemd.git;a=commitdiff_plain;h=0e85cbcfc35d3a0f18f593e7ffbd6b98e778f401 util-lib: do not truncate kernel comm names It turns out that the kernel allows comm names higher than our expected limit of 16. $ wc -c /proc/*/comm|sort -g|tail -n3 35 /proc/1292317/comm 35 /proc/1293610/comm 36 /proc/1287112/comm $ cat /proc/1287112/comm kworker/u9:3-kcryptd/253:0 --- diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 4c05f16db52..8db7f462d75 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -46,6 +46,11 @@ #include "user-util.h" #include "utf8.h" +/* The kernel limits userspace processes to TASK_COMM_LEN (16 bytes), but allows higher values for its own + * workers, e.g. "kworker/u9:3-kcryptd/253:0". Let's pick a fixed smallish limit that will work for the kernel. + */ +#define COMM_MAX_LEN 128 + static int get_process_state(pid_t pid) { const char *p; char state; @@ -82,7 +87,7 @@ int get_process_comm(pid_t pid, char **ret) { assert(ret); assert(pid >= 0); - escaped = new(char, TASK_COMM_LEN); + escaped = new(char, COMM_MAX_LEN); if (!escaped) return -ENOMEM; @@ -95,7 +100,7 @@ int get_process_comm(pid_t pid, char **ret) { return r; /* Escape unprintable characters, just in case, but don't grow the string beyond the underlying size */ - cellescape(escaped, TASK_COMM_LEN, comm); + cellescape(escaped, COMM_MAX_LEN, comm); *ret = TAKE_PTR(escaped); return 0; @@ -209,7 +214,7 @@ int rename_process(const char name[]) { * can use PR_SET_NAME, which sets the thread name for the calling thread. */ if (prctl(PR_SET_NAME, name) < 0) log_debug_errno(errno, "PR_SET_NAME failed: %m"); - if (l >= TASK_COMM_LEN) /* Linux process names can be 15 chars at max */ + if (l >= TASK_COMM_LEN) /* Linux userspace process names can be 15 chars at max */ truncated = true; /* Second step, change glibc's ID of the process name. */ diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index aaa8041ec35..107d0b5d224 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -107,12 +107,12 @@ static void test_get_process_comm_escape(void) { test_get_process_comm_escape_one("foo", "foo"); test_get_process_comm_escape_one("012345678901234", "012345678901234"); test_get_process_comm_escape_one("0123456789012345", "012345678901234"); - test_get_process_comm_escape_one("äöüß", "\\303\\244\\303…"); - test_get_process_comm_escape_one("xäöüß", "x\\303\\244…"); - test_get_process_comm_escape_one("xxäöüß", "xx\\303\\244…"); - test_get_process_comm_escape_one("xxxäöüß", "xxx\\303\\244…"); - test_get_process_comm_escape_one("xxxxäöüß", "xxxx\\303\\244…"); - test_get_process_comm_escape_one("xxxxxäöüß", "xxxxx\\303…"); + test_get_process_comm_escape_one("äöüß", "\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xäöüß", "x\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xxäöüß", "xx\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xxxäöüß", "xxx\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237"); assert_se(prctl(PR_SET_NAME, saved) >= 0); } @@ -407,6 +407,8 @@ static void test_rename_process_now(const char *p, int ret) { assert_se(get_process_comm(0, &comm) >= 0); log_info("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, false, &cmdline); assert_se(r >= 0);