]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util-lib: do not truncate kernel comm names
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 15 May 2019 09:55:59 +0000 (11:55 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 22 May 2019 08:09:35 +0000 (10:09 +0200)
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

src/basic/process-util.c
src/test/test-process-util.c

index 4c05f16db5279a0c9093b278d6e7cf9cdcbfd3a3..8db7f462d75facdfeb89839fb9ae7a435d4f9efd 100644 (file)
 #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. */
index aaa8041ec354c4808f0fb56abd8bedbf26af6014..107d0b5d224722258f64bd9b8afd41c868a89090 100644 (file)
@@ -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);