^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Permission to use, copy, modify, and distribute this software for any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * purpose with or without fee is hereby granted, provided that the above
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * copyright notice and this permission notice appear in all copies.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) // Test that /proc/$KERNEL_THREAD/fd/ is empty.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #undef NDEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <sys/syscall.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <assert.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <dirent.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include "proc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define PF_KHTREAD 0x00200000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Test for kernel threadness atomically with openat().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Return /proc/$PID/fd descriptor if process is kernel thread.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * Return -1 if a process is userspace process.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int kernel_thread_fd(unsigned int pid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned int flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) char buf[4096];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int dir_fd, fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ssize_t rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) snprintf(buf, sizeof(buf), "/proc/%u", pid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) dir_fd = open(buf, O_RDONLY|O_DIRECTORY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (dir_fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * Believe it or not, struct task_struct::flags is directly exposed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * to userspace!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) fd = openat(dir_fd, "stat", O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (fd == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) close(dir_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) rv = read(fd, buf, sizeof(buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (0 < rv && rv <= sizeof(buf)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned long long flags_ull;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) char *p, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) assert(buf[rv - 1] == '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) buf[rv - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Search backwards: ->comm can contain whitespace and ')'. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) for (i = 0; i < 43; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) p = strrchr(buf, ' ');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) assert(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) *p = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) p = strrchr(buf, ' ');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) assert(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) flags_ull = xstrtoull(p + 1, &end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) assert(*end == '\0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) assert(flags_ull == (unsigned int)flags_ull);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) flags = flags_ull;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) fd = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (flags & PF_KHTREAD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) fd = openat(dir_fd, "fd", O_RDONLY|O_DIRECTORY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) close(dir_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static void test_readdir(int fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) DIR *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct dirent *de;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) d = fdopendir(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) assert(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) de = xreaddir(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) assert(streq(de->d_name, "."));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) assert(de->d_type == DT_DIR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) de = xreaddir(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) assert(streq(de->d_name, ".."));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) assert(de->d_type == DT_DIR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) de = xreaddir(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) assert(!de);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static inline int sys_statx(int dirfd, const char *pathname, int flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned int mask, void *stx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return syscall(SYS_statx, dirfd, pathname, flags, mask, stx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static void test_lookup_fail(int fd, const char *pathname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) char stx[256] __attribute__((aligned(8)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) rv = sys_statx(fd, pathname, AT_SYMLINK_NOFOLLOW, 0, (void *)stx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) assert(rv == -1 && errno == ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static void test_lookup(int fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) char buf[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) unsigned int u;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) for (i = INT_MIN; i < INT_MIN + 1024; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) snprintf(buf, sizeof(buf), "%d", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) test_lookup_fail(fd, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) for (i = -1024; i < 1024; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) snprintf(buf, sizeof(buf), "%d", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) test_lookup_fail(fd, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) for (u = INT_MAX - 1024; u < (unsigned int)INT_MAX + 1024; u++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) snprintf(buf, sizeof(buf), "%u", u);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) test_lookup_fail(fd, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) for (u = UINT_MAX - 1024; u != 0; u++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) snprintf(buf, sizeof(buf), "%u", u);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) test_lookup_fail(fd, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) int main(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) unsigned int pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * In theory this will loop indefinitely if kernel threads are exiled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * from /proc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * Start with kthreadd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) pid = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) while ((fd = kernel_thread_fd(pid)) == -1 && pid < 1024) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) pid++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /* EACCES if run as non-root. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (pid >= 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) test_readdir(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) test_lookup(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }