chiark / gitweb /
process-util: be more careful in is_kernel_thread()
authorLennart Poettering <lennart@poettering.net>
Tue, 6 Feb 2018 14:59:55 +0000 (15:59 +0100)
committerSven Eden <yamakuzure@gmx.net>
Wed, 30 May 2018 05:58:54 +0000 (07:58 +0200)
This reworks is_kernel_thread() a bit. Instead of checking whether
/proc/$pid/cmdline is entirely empty we now parse the 'flags' field from
/proc/$pid/stat and check the PF_KTHREAD flag, which directly encodes
whether something is a kernel thread.

Why all this? With current kernels userspace processes can set their
command line to empty too (through PR_SET_MM_ARG_START and friends), and
could potentially confuse us. Hence, let's use a more reliable way to
detect kernels like this.

src/basic/missing.h
src/basic/process-util.c

index c1168761d01df066b65b1378a2caf388e41fe558..bbddfe6fbd41d79807c0c1fd2f5b4ed0d5beebf9 100644 (file)
@@ -27,7 +27,6 @@
 #include <inttypes.h>
 #include <linux/audit.h>
 #include <linux/capability.h>
-//#include <linux/falloc.h>
 #include <linux/if_link.h>
 #include <linux/input.h>
 #include <linux/loop.h>
@@ -523,10 +522,6 @@ struct btrfs_ioctl_quota_ctl_args {
 #define BPF_FS_MAGIC 0xcafe4a11
 #endif
 
-#ifndef OCFS2_SUPER_MAGIC
-#define OCFS2_SUPER_MAGIC 0x7461636f
-#endif
-
 #ifndef MS_MOVE
 #define MS_MOVE 8192
 #endif
@@ -1369,12 +1364,8 @@ struct fib_rule_uid_range {
 #define NS_GET_NSTYPE _IO(0xb7, 0x3)
 #endif
 
-#ifndef FALLOC_FL_KEEP_SIZE
-#define FALLOC_FL_KEEP_SIZE 0x01
-#endif
-
-#ifndef FALLOC_FL_PUNCH_HOLE
-#define FALLOC_FL_PUNCH_HOLE 0x02
+#ifndef PF_KTHREAD
+#define PF_KTHREAD 0x00200000
 #endif
 
 #include "missing_syscall.h"
index ccf828389c2f07f6908db8778a91db0758edbc29..105b4fdc7ea7c5e54eef69ccf7880479e83b284e 100644 (file)
@@ -400,37 +400,61 @@ use_saved_argv:
 #endif // 0
 
 int is_kernel_thread(pid_t pid) {
+        _cleanup_free_ char *line = NULL;
+        unsigned long long flags;
+        size_t l, i;
         const char *p;
-        size_t count;
-        char c;
-        bool eof;
-        FILE *f;
+        char *q;
+        int r;
 
         if (IN_SET(pid, 0, 1) || pid == getpid_cached()) /* pid 1, and we ourselves certainly aren't a kernel thread */
                 return 0;
+        if (!pid_is_valid(pid))
+                return -EINVAL;
 
-        assert(pid > 1);
+        p = procfs_file_alloca(pid, "stat");
+        r = read_one_line_file(p, &line);
+        if (r == -ENOENT)
+                return -ESRCH;
+        if (r < 0)
+                return r;
 
-        p = procfs_file_alloca(pid, "cmdline");
-        f = fopen(p, "re");
-        if (!f) {
-                if (errno == ENOENT)
-                        return -ESRCH;
-                return -errno;
+        /* Skip past the comm field */
+        q = strrchr(line, ')');
+        if (!q)
+                return -EINVAL;
+        q++;
+
+        /* Skip 6 fields to reach the flags field */
+        for (i = 0; i < 6; i++) {
+                l = strspn(q, WHITESPACE);
+                if (l < 1)
+                        return -EINVAL;
+                q += l;
+
+                l = strcspn(q, WHITESPACE);
+                if (l < 1)
+                        return -EINVAL;
+                q += l;
         }
 
-        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
-        count = fread(&c, 1, 1, f);
-        eof = feof(f);
-        fclose(f);
+        /* Skip preceeding whitespace */
+        l = strspn(q, WHITESPACE);
+        if (l < 1)
+                return -EINVAL;
+        q += l;
 
-        /* Kernel threads have an empty cmdline */
+        /* Truncate the rest */
+        l = strcspn(q, WHITESPACE);
+        if (l < 1)
+                return -EINVAL;
+        q[l] = 0;
 
-        if (count <= 0)
-                return eof ? 1 : -errno;
+        r = safe_atollu(q, &flags);
+        if (r < 0)
+                return r;
 
-        return 0;
+        return !!(flags & PF_KTHREAD);
 }
 
 #if 0 /// UNNEEDED by elogind