chiark / gitweb /
process-util: also filter non-printable characters in get_process_com()
authorLennart Poettering <lennart@poettering.net>
Thu, 17 May 2018 01:50:35 +0000 (21:50 -0400)
committerSven Eden <yamakuzure@gmx.net>
Fri, 24 Aug 2018 14:47:08 +0000 (16:47 +0200)
We already do that in get_process_cmdline(), which is very similar in
behaviour otherwise. Hence, let's be safe and also filter them in
get_process_comm(). Let's try to retain as much information as we can
though and escape rather than suppress unprintable characters. Let's not
increase comm names beyond the kernel limit on such names however.

Also see discussion about this here:

https://marc.info/?l=linux-api&m=152649570404881&w=2

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

index f74eebd585c3e180be57ef2b3f3d919f20ca0098..b105add79b41622e3a09ee62d1799943d96a0c31 100644 (file)
@@ -76,20 +76,31 @@ int get_process_state(pid_t pid) {
         return (unsigned char) state;
 }
 
-int get_process_comm(pid_t pid, char **name) {
+int get_process_comm(pid_t pid, char **ret) {
+        _cleanup_free_ char *escaped = NULL, *comm = NULL;
         const char *p;
         int r;
 
-        assert(name);
+        assert(ret);
         assert(pid >= 0);
 
+        escaped = new(char, TASK_COMM_LEN);
+        if (!escaped)
+                return -ENOMEM;
+
         p = procfs_file_alloca(pid, "comm");
 
-        r = read_one_line_file(p, name);
+        r = read_one_line_file(p, &comm);
         if (r == -ENOENT)
                 return -ESRCH;
+        if (r < 0)
+                return r;
 
-        return r;
+        /* Escape unprintable characters, just in case, but don't grow the string beyond the underlying size */
+        cellescape(escaped, TASK_COMM_LEN, comm);
+
+        *ret = TAKE_PTR(escaped);
+        return 0;
 }
 
 int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
index 0d890fa468e65e8719d12506e88d3e2842ff9647..78048a57144bc5f547846a734e069e17e55b6bc3 100644 (file)
@@ -97,6 +97,38 @@ static void test_get_process_comm(pid_t pid) {
         log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
 }
 
+static void test_get_process_comm_escape_one(const char *input, const char *output) {
+        _cleanup_free_ char *n = NULL;
+
+        log_info("input: <%s> — output: <%s>", input, output);
+
+        assert_se(prctl(PR_SET_NAME, input) >= 0);
+        assert_se(get_process_comm(0, &n) >= 0);
+
+        log_info("got: <%s>", n);
+
+        assert_se(streq_ptr(n, output));
+}
+
+static void test_get_process_comm_escape(void) {
+        _cleanup_free_ char *saved = NULL;
+
+        assert_se(get_process_comm(0, &saved) >= 0);
+
+        test_get_process_comm_escape_one("", "");
+        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…");
+
+        assert_se(prctl(PR_SET_NAME, saved) >= 0);
+}
+
 static void test_pid_is_unwaited(void) {
         pid_t pid;
 
@@ -582,6 +614,7 @@ int main(int argc, char *argv[]) {
                 test_get_process_comm(getpid());
         }
 
+        test_get_process_comm_escape();
         test_pid_is_unwaited();
         test_pid_is_alive();
 #if 0 /// UNNEEDED by elogind