From: Lennart Poettering Date: Tue, 6 Feb 2018 14:59:55 +0000 (+0100) Subject: process-util: be more careful in is_kernel_thread() X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=0bdf2a3d4f8c159a36b9cf62ad69ee5eddc8e8b4;p=elogind.git process-util: be more careful in is_kernel_thread() 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. --- diff --git a/src/basic/missing.h b/src/basic/missing.h index c1168761d..bbddfe6fb 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -27,7 +27,6 @@ #include #include #include -//#include #include #include #include @@ -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" diff --git a/src/basic/process-util.c b/src/basic/process-util.c index ccf828389..105b4fdc7 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -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