Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tests: add pidfd_open() tests

This adds testing for the new pidfd_open() syscalls. Specifically, we test:
- that no invalid flags can be passed to pidfd_open()
- that no invalid pid can be passed to pidfd_open()
- that a pidfd can be retrieved with pidfd_open()
- that the retrieved pidfd references the correct pid

Signed-off-by: Christian Brauner <christian@brauner.io>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Joel Fernandes (Google) <joel@joelfernandes.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jann Horn <jannh@google.com>
Cc: David Howells <dhowells@redhat.com>
Cc: "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com>
Cc: Andy Lutomirsky <luto@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: linux-api@vger.kernel.org

+234 -44
+1
tools/testing/selftests/pidfd/.gitignore
··· 1 + pidfd_open_test 1 2 pidfd_test
+2 -1
tools/testing/selftests/pidfd/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 1 2 CFLAGS += -g -I../../../../usr/include/ -lpthread 2 3 3 - TEST_GEN_PROGS := pidfd_test 4 + TEST_GEN_PROGS := pidfd_test pidfd_open_test 4 5 5 6 include ../lib.mk 6 7
+57
tools/testing/selftests/pidfd/pidfd.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __PIDFD_H 4 + #define __PIDFD_H 5 + 6 + #define _GNU_SOURCE 7 + #include <errno.h> 8 + #include <fcntl.h> 9 + #include <sched.h> 10 + #include <signal.h> 11 + #include <stdio.h> 12 + #include <stdlib.h> 13 + #include <string.h> 14 + #include <syscall.h> 15 + #include <sys/mount.h> 16 + 17 + #include "../kselftest.h" 18 + 19 + /* 20 + * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c 21 + * That means, when it wraps around any pid < 300 will be skipped. 22 + * So we need to use a pid > 300 in order to test recycling. 23 + */ 24 + #define PID_RECYCLE 1000 25 + 26 + /* 27 + * Define a few custom error codes for the child process to clearly indicate 28 + * what is happening. This way we can tell the difference between a system 29 + * error, a test error, etc. 30 + */ 31 + #define PIDFD_PASS 0 32 + #define PIDFD_FAIL 1 33 + #define PIDFD_ERROR 2 34 + #define PIDFD_SKIP 3 35 + #define PIDFD_XFAIL 4 36 + 37 + int wait_for_pid(pid_t pid) 38 + { 39 + int status, ret; 40 + 41 + again: 42 + ret = waitpid(pid, &status, 0); 43 + if (ret == -1) { 44 + if (errno == EINTR) 45 + goto again; 46 + 47 + return -1; 48 + } 49 + 50 + if (!WIFEXITED(status)) 51 + return -1; 52 + 53 + return WEXITSTATUS(status); 54 + } 55 + 56 + 57 + #endif /* __PIDFD_H */
+169
tools/testing/selftests/pidfd/pidfd_open_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #define _GNU_SOURCE 4 + #include <errno.h> 5 + #include <fcntl.h> 6 + #include <inttypes.h> 7 + #include <limits.h> 8 + #include <linux/types.h> 9 + #include <linux/wait.h> 10 + #include <sched.h> 11 + #include <signal.h> 12 + #include <stdbool.h> 13 + #include <stdio.h> 14 + #include <stdlib.h> 15 + #include <string.h> 16 + #include <syscall.h> 17 + #include <sys/mount.h> 18 + #include <sys/prctl.h> 19 + #include <sys/wait.h> 20 + #include <unistd.h> 21 + 22 + #include "pidfd.h" 23 + #include "../kselftest.h" 24 + 25 + static inline int sys_pidfd_open(pid_t pid, unsigned int flags) 26 + { 27 + return syscall(__NR_pidfd_open, pid, flags); 28 + } 29 + 30 + static int safe_int(const char *numstr, int *converted) 31 + { 32 + char *err = NULL; 33 + long sli; 34 + 35 + errno = 0; 36 + sli = strtol(numstr, &err, 0); 37 + if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) 38 + return -ERANGE; 39 + 40 + if (errno != 0 && sli == 0) 41 + return -EINVAL; 42 + 43 + if (err == numstr || *err != '\0') 44 + return -EINVAL; 45 + 46 + if (sli > INT_MAX || sli < INT_MIN) 47 + return -ERANGE; 48 + 49 + *converted = (int)sli; 50 + return 0; 51 + } 52 + 53 + static int char_left_gc(const char *buffer, size_t len) 54 + { 55 + size_t i; 56 + 57 + for (i = 0; i < len; i++) { 58 + if (buffer[i] == ' ' || 59 + buffer[i] == '\t') 60 + continue; 61 + 62 + return i; 63 + } 64 + 65 + return 0; 66 + } 67 + 68 + static int char_right_gc(const char *buffer, size_t len) 69 + { 70 + int i; 71 + 72 + for (i = len - 1; i >= 0; i--) { 73 + if (buffer[i] == ' ' || 74 + buffer[i] == '\t' || 75 + buffer[i] == '\n' || 76 + buffer[i] == '\0') 77 + continue; 78 + 79 + return i + 1; 80 + } 81 + 82 + return 0; 83 + } 84 + 85 + static char *trim_whitespace_in_place(char *buffer) 86 + { 87 + buffer += char_left_gc(buffer, strlen(buffer)); 88 + buffer[char_right_gc(buffer, strlen(buffer))] = '\0'; 89 + return buffer; 90 + } 91 + 92 + static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen) 93 + { 94 + int ret; 95 + char path[512]; 96 + FILE *f; 97 + size_t n = 0; 98 + pid_t result = -1; 99 + char *line = NULL; 100 + 101 + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd); 102 + 103 + f = fopen(path, "re"); 104 + if (!f) 105 + return -1; 106 + 107 + while (getline(&line, &n, f) != -1) { 108 + char *numstr; 109 + 110 + if (strncmp(line, key, keylen)) 111 + continue; 112 + 113 + numstr = trim_whitespace_in_place(line + 4); 114 + ret = safe_int(numstr, &result); 115 + if (ret < 0) 116 + goto out; 117 + 118 + break; 119 + } 120 + 121 + out: 122 + free(line); 123 + fclose(f); 124 + return result; 125 + } 126 + 127 + int main(int argc, char **argv) 128 + { 129 + int pidfd = -1, ret = 1; 130 + pid_t pid; 131 + 132 + ksft_set_plan(3); 133 + 134 + pidfd = sys_pidfd_open(-1, 0); 135 + if (pidfd >= 0) { 136 + ksft_print_msg( 137 + "%s - succeeded to open pidfd for invalid pid -1\n", 138 + strerror(errno)); 139 + goto on_error; 140 + } 141 + ksft_test_result_pass("do not allow invalid pid test: passed\n"); 142 + 143 + pidfd = sys_pidfd_open(getpid(), 1); 144 + if (pidfd >= 0) { 145 + ksft_print_msg( 146 + "%s - succeeded to open pidfd with invalid flag value specified\n", 147 + strerror(errno)); 148 + goto on_error; 149 + } 150 + ksft_test_result_pass("do not allow invalid flag test: passed\n"); 151 + 152 + pidfd = sys_pidfd_open(getpid(), 0); 153 + if (pidfd < 0) { 154 + ksft_print_msg("%s - failed to open pidfd\n", strerror(errno)); 155 + goto on_error; 156 + } 157 + ksft_test_result_pass("open a new pidfd test: passed\n"); 158 + 159 + pid = get_pid_from_fdinfo_file(pidfd, "Pid:", sizeof("Pid:") - 1); 160 + ksft_print_msg("pidfd %d refers to process with pid %d\n", pidfd, pid); 161 + 162 + ret = 0; 163 + 164 + on_error: 165 + if (pidfd >= 0) 166 + close(pidfd); 167 + 168 + return !ret ? ksft_exit_pass() : ksft_exit_fail(); 169 + }
+5 -43
tools/testing/selftests/pidfd/pidfd_test.c
··· 18 18 #include <time.h> 19 19 #include <unistd.h> 20 20 21 + #include "pidfd.h" 21 22 #include "../kselftest.h" 23 + 24 + #ifndef __NR_pidfd_send_signal 25 + #define __NR_pidfd_send_signal -1 26 + #endif 22 27 23 28 #define str(s) _str(s) 24 29 #define _str(s) #s 25 30 #define CHILD_THREAD_MIN_WAIT 3 /* seconds */ 26 31 27 32 #define MAX_EVENTS 5 28 - #ifndef __NR_pidfd_send_signal 29 - #define __NR_pidfd_send_signal 424 30 - #endif 31 33 32 34 #ifndef CLONE_PIDFD 33 35 #define CLONE_PIDFD 0x00001000 ··· 93 91 return 0; 94 92 } 95 93 96 - static int wait_for_pid(pid_t pid) 97 - { 98 - int status, ret; 99 - 100 - again: 101 - ret = waitpid(pid, &status, 0); 102 - if (ret == -1) { 103 - if (errno == EINTR) 104 - goto again; 105 - 106 - return -1; 107 - } 108 - 109 - if (ret != pid) 110 - goto again; 111 - 112 - if (!WIFEXITED(status)) 113 - return -1; 114 - 115 - return WEXITSTATUS(status); 116 - } 117 - 118 94 static int test_pidfd_send_signal_exited_fail(void) 119 95 { 120 96 int pidfd, ret, saved_errno; ··· 138 158 } 139 159 140 160 /* 141 - * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c 142 - * That means, when it wraps around any pid < 300 will be skipped. 143 - * So we need to use a pid > 300 in order to test recycling. 144 - */ 145 - #define PID_RECYCLE 1000 146 - 147 - /* 148 161 * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT. 149 162 * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of 150 163 * times then we skip the test to not go into an infinite loop or block for a 151 164 * long time. 152 165 */ 153 166 #define PIDFD_MAX_DEFAULT 0x8000 154 - 155 - /* 156 - * Define a few custom error codes for the child process to clearly indicate 157 - * what is happening. This way we can tell the difference between a system 158 - * error, a test error, etc. 159 - */ 160 - #define PIDFD_PASS 0 161 - #define PIDFD_FAIL 1 162 - #define PIDFD_ERROR 2 163 - #define PIDFD_SKIP 3 164 - #define PIDFD_XFAIL 4 165 167 166 168 static int test_pidfd_send_signal_recycled_pid_fail(void) 167 169 {