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

test: Add test for pidfd getfd

The following tests:
* Fetch FD, and then compare via kcmp
* Make sure getfd can be blocked by blocking ptrace_may_access
* Making sure fetching bad FDs fails
* Make sure trying to set flags to non-zero results in an EINVAL

Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/r/20200107175927.4558-5-sargun@sargun.me
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>

authored by

Sargun Dhillon and committed by
Christian Brauner
873dfd78 9a2cef09

+260 -1
+1
tools/testing/selftests/pidfd/.gitignore
··· 2 2 pidfd_poll_test 3 3 pidfd_test 4 4 pidfd_wait 5 + pidfd_getfd_test
+1 -1
tools/testing/selftests/pidfd/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 CFLAGS += -g -I../../../../usr/include/ -pthread 3 3 4 - TEST_GEN_PROGS := pidfd_test pidfd_fdinfo_test pidfd_open_test pidfd_poll_test pidfd_wait 4 + TEST_GEN_PROGS := pidfd_test pidfd_fdinfo_test pidfd_open_test pidfd_poll_test pidfd_wait pidfd_getfd_test 5 5 6 6 include ../lib.mk 7 7
+9
tools/testing/selftests/pidfd/pidfd.h
··· 36 36 #define __NR_clone3 -1 37 37 #endif 38 38 39 + #ifndef __NR_pidfd_getfd 40 + #define __NR_pidfd_getfd -1 41 + #endif 42 + 39 43 /* 40 44 * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c 41 45 * That means, when it wraps around any pid < 300 will be skipped. ··· 86 82 unsigned int flags) 87 83 { 88 84 return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 85 + } 86 + 87 + static inline int sys_pidfd_getfd(int pidfd, int fd, int flags) 88 + { 89 + return syscall(__NR_pidfd_getfd, pidfd, fd, flags); 89 90 } 90 91 91 92 #endif /* __PIDFD_H */
+249
tools/testing/selftests/pidfd/pidfd_getfd_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #define _GNU_SOURCE 4 + #include <errno.h> 5 + #include <fcntl.h> 6 + #include <limits.h> 7 + #include <linux/types.h> 8 + #include <sched.h> 9 + #include <signal.h> 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + #include <syscall.h> 14 + #include <sys/prctl.h> 15 + #include <sys/wait.h> 16 + #include <unistd.h> 17 + #include <sys/socket.h> 18 + #include <linux/kcmp.h> 19 + 20 + #include "pidfd.h" 21 + #include "../kselftest.h" 22 + #include "../kselftest_harness.h" 23 + 24 + /* 25 + * UNKNOWN_FD is an fd number that should never exist in the child, as it is 26 + * used to check the negative case. 27 + */ 28 + #define UNKNOWN_FD 111 29 + #define UID_NOBODY 65535 30 + 31 + static int sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, 32 + unsigned long idx2) 33 + { 34 + return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); 35 + } 36 + 37 + static int sys_memfd_create(const char *name, unsigned int flags) 38 + { 39 + return syscall(__NR_memfd_create, name, flags); 40 + } 41 + 42 + static int __child(int sk, int memfd) 43 + { 44 + int ret; 45 + char buf; 46 + 47 + /* 48 + * Ensure we don't leave around a bunch of orphaned children if our 49 + * tests fail. 50 + */ 51 + ret = prctl(PR_SET_PDEATHSIG, SIGKILL); 52 + if (ret) { 53 + fprintf(stderr, "%s: Child could not set DEATHSIG\n", 54 + strerror(errno)); 55 + return -1; 56 + } 57 + 58 + ret = send(sk, &memfd, sizeof(memfd), 0); 59 + if (ret != sizeof(memfd)) { 60 + fprintf(stderr, "%s: Child failed to send fd number\n", 61 + strerror(errno)); 62 + return -1; 63 + } 64 + 65 + /* 66 + * The fixture setup is completed at this point. The tests will run. 67 + * 68 + * This blocking recv enables the parent to message the child. 69 + * Either we will read 'P' off of the sk, indicating that we need 70 + * to disable ptrace, or we will read a 0, indicating that the other 71 + * side has closed the sk. This occurs during fixture teardown time, 72 + * indicating that the child should exit. 73 + */ 74 + while ((ret = recv(sk, &buf, sizeof(buf), 0)) > 0) { 75 + if (buf == 'P') { 76 + ret = prctl(PR_SET_DUMPABLE, 0); 77 + if (ret < 0) { 78 + fprintf(stderr, 79 + "%s: Child failed to disable ptrace\n", 80 + strerror(errno)); 81 + return -1; 82 + } 83 + } else { 84 + fprintf(stderr, "Child received unknown command %c\n", 85 + buf); 86 + return -1; 87 + } 88 + ret = send(sk, &buf, sizeof(buf), 0); 89 + if (ret != 1) { 90 + fprintf(stderr, "%s: Child failed to ack\n", 91 + strerror(errno)); 92 + return -1; 93 + } 94 + } 95 + if (ret < 0) { 96 + fprintf(stderr, "%s: Child failed to read from socket\n", 97 + strerror(errno)); 98 + return -1; 99 + } 100 + 101 + return 0; 102 + } 103 + 104 + static int child(int sk) 105 + { 106 + int memfd, ret; 107 + 108 + memfd = sys_memfd_create("test", 0); 109 + if (memfd < 0) { 110 + fprintf(stderr, "%s: Child could not create memfd\n", 111 + strerror(errno)); 112 + ret = -1; 113 + } else { 114 + ret = __child(sk, memfd); 115 + close(memfd); 116 + } 117 + 118 + close(sk); 119 + return ret; 120 + } 121 + 122 + FIXTURE(child) 123 + { 124 + /* 125 + * remote_fd is the number of the FD which we are trying to retrieve 126 + * from the child. 127 + */ 128 + int remote_fd; 129 + /* pid points to the child which we are fetching FDs from */ 130 + pid_t pid; 131 + /* pidfd is the pidfd of the child */ 132 + int pidfd; 133 + /* 134 + * sk is our side of the socketpair used to communicate with the child. 135 + * When it is closed, the child will exit. 136 + */ 137 + int sk; 138 + }; 139 + 140 + FIXTURE_SETUP(child) 141 + { 142 + int ret, sk_pair[2]; 143 + 144 + ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair)) { 145 + TH_LOG("%s: failed to create socketpair", strerror(errno)); 146 + } 147 + self->sk = sk_pair[0]; 148 + 149 + self->pid = fork(); 150 + ASSERT_GE(self->pid, 0); 151 + 152 + if (self->pid == 0) { 153 + close(sk_pair[0]); 154 + if (child(sk_pair[1])) 155 + _exit(EXIT_FAILURE); 156 + _exit(EXIT_SUCCESS); 157 + } 158 + 159 + close(sk_pair[1]); 160 + 161 + self->pidfd = sys_pidfd_open(self->pid, 0); 162 + ASSERT_GE(self->pidfd, 0); 163 + 164 + /* 165 + * Wait for the child to complete setup. It'll send the remote memfd's 166 + * number when ready. 167 + */ 168 + ret = recv(sk_pair[0], &self->remote_fd, sizeof(self->remote_fd), 0); 169 + ASSERT_EQ(sizeof(self->remote_fd), ret); 170 + } 171 + 172 + FIXTURE_TEARDOWN(child) 173 + { 174 + EXPECT_EQ(0, close(self->pidfd)); 175 + EXPECT_EQ(0, close(self->sk)); 176 + 177 + EXPECT_EQ(0, wait_for_pid(self->pid)); 178 + } 179 + 180 + TEST_F(child, disable_ptrace) 181 + { 182 + int uid, fd; 183 + char c; 184 + 185 + /* 186 + * Turn into nobody if we're root, to avoid CAP_SYS_PTRACE 187 + * 188 + * The tests should run in their own process, so even this test fails, 189 + * it shouldn't result in subsequent tests failing. 190 + */ 191 + uid = getuid(); 192 + if (uid == 0) 193 + ASSERT_EQ(0, seteuid(UID_NOBODY)); 194 + 195 + ASSERT_EQ(1, send(self->sk, "P", 1, 0)); 196 + ASSERT_EQ(1, recv(self->sk, &c, 1, 0)); 197 + 198 + fd = sys_pidfd_getfd(self->pidfd, self->remote_fd, 0); 199 + EXPECT_EQ(-1, fd); 200 + EXPECT_EQ(EPERM, errno); 201 + 202 + if (uid == 0) 203 + ASSERT_EQ(0, seteuid(0)); 204 + } 205 + 206 + TEST_F(child, fetch_fd) 207 + { 208 + int fd, ret; 209 + 210 + fd = sys_pidfd_getfd(self->pidfd, self->remote_fd, 0); 211 + ASSERT_GE(fd, 0); 212 + 213 + EXPECT_EQ(0, sys_kcmp(getpid(), self->pid, KCMP_FILE, fd, self->remote_fd)); 214 + 215 + ret = fcntl(fd, F_GETFD); 216 + ASSERT_GE(ret, 0); 217 + EXPECT_GE(ret & FD_CLOEXEC, 0); 218 + 219 + close(fd); 220 + } 221 + 222 + TEST_F(child, test_unknown_fd) 223 + { 224 + int fd; 225 + 226 + fd = sys_pidfd_getfd(self->pidfd, UNKNOWN_FD, 0); 227 + EXPECT_EQ(-1, fd) { 228 + TH_LOG("getfd succeeded while fetching unknown fd"); 229 + }; 230 + EXPECT_EQ(EBADF, errno) { 231 + TH_LOG("%s: getfd did not get EBADF", strerror(errno)); 232 + } 233 + } 234 + 235 + TEST(flags_set) 236 + { 237 + ASSERT_EQ(-1, sys_pidfd_getfd(0, 0, 1)); 238 + EXPECT_EQ(errno, EINVAL); 239 + } 240 + 241 + #if __NR_pidfd_getfd == -1 242 + int main(void) 243 + { 244 + fprintf(stderr, "__NR_pidfd_getfd undefined. The pidfd_getfd syscall is unavailable. Test aborting\n"); 245 + return KSFT_SKIP; 246 + } 247 + #else 248 + TEST_HARNESS_MAIN 249 + #endif