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.
This commit is contained in:
Lennart Poettering
2018-02-12 11:34:00 +01:00
parent 004c7f169e
commit 36b5119a0c
2 changed files with 48 additions and 20 deletions
+44 -20
View File
@@ -398,37 +398,61 @@ use_saved_argv:
}
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);
/* Skip preceeding whitespace */
l = strspn(q, WHITESPACE);
if (l < 1)
return -EINVAL;
q += l;
count = fread(&c, 1, 1, f);
eof = feof(f);
fclose(f);
/* Truncate the rest */
l = strcspn(q, WHITESPACE);
if (l < 1)
return -EINVAL;
q[l] = 0;
/* Kernel threads have an empty cmdline */
r = safe_atollu(q, &flags);
if (r < 0)
return r;
if (count <= 0)
return eof ? 1 : -errno;
return 0;
return !!(flags & PF_KTHREAD);
}
int get_process_capeff(pid_t pid, char **capeff) {