162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#define _GNU_SOURCE 462306a36Sopenharmony_ci#include <errno.h> 562306a36Sopenharmony_ci#include <fcntl.h> 662306a36Sopenharmony_ci#include <limits.h> 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <sched.h> 962306a36Sopenharmony_ci#include <signal.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <stdlib.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <syscall.h> 1462306a36Sopenharmony_ci#include <sys/prctl.h> 1562306a36Sopenharmony_ci#include <sys/wait.h> 1662306a36Sopenharmony_ci#include <unistd.h> 1762306a36Sopenharmony_ci#include <sys/socket.h> 1862306a36Sopenharmony_ci#include <linux/kcmp.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "pidfd.h" 2162306a36Sopenharmony_ci#include "../kselftest_harness.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * UNKNOWN_FD is an fd number that should never exist in the child, as it is 2562306a36Sopenharmony_ci * used to check the negative case. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci#define UNKNOWN_FD 111 2862306a36Sopenharmony_ci#define UID_NOBODY 65535 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, 3162306a36Sopenharmony_ci unsigned long idx2) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int __child(int sk, int memfd) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci int ret; 3962306a36Sopenharmony_ci char buf; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* 4262306a36Sopenharmony_ci * Ensure we don't leave around a bunch of orphaned children if our 4362306a36Sopenharmony_ci * tests fail. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci ret = prctl(PR_SET_PDEATHSIG, SIGKILL); 4662306a36Sopenharmony_ci if (ret) { 4762306a36Sopenharmony_ci fprintf(stderr, "%s: Child could not set DEATHSIG\n", 4862306a36Sopenharmony_ci strerror(errno)); 4962306a36Sopenharmony_ci return -1; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci ret = send(sk, &memfd, sizeof(memfd), 0); 5362306a36Sopenharmony_ci if (ret != sizeof(memfd)) { 5462306a36Sopenharmony_ci fprintf(stderr, "%s: Child failed to send fd number\n", 5562306a36Sopenharmony_ci strerror(errno)); 5662306a36Sopenharmony_ci return -1; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* 6062306a36Sopenharmony_ci * The fixture setup is completed at this point. The tests will run. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * This blocking recv enables the parent to message the child. 6362306a36Sopenharmony_ci * Either we will read 'P' off of the sk, indicating that we need 6462306a36Sopenharmony_ci * to disable ptrace, or we will read a 0, indicating that the other 6562306a36Sopenharmony_ci * side has closed the sk. This occurs during fixture teardown time, 6662306a36Sopenharmony_ci * indicating that the child should exit. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci while ((ret = recv(sk, &buf, sizeof(buf), 0)) > 0) { 6962306a36Sopenharmony_ci if (buf == 'P') { 7062306a36Sopenharmony_ci ret = prctl(PR_SET_DUMPABLE, 0); 7162306a36Sopenharmony_ci if (ret < 0) { 7262306a36Sopenharmony_ci fprintf(stderr, 7362306a36Sopenharmony_ci "%s: Child failed to disable ptrace\n", 7462306a36Sopenharmony_ci strerror(errno)); 7562306a36Sopenharmony_ci return -1; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci } else { 7862306a36Sopenharmony_ci fprintf(stderr, "Child received unknown command %c\n", 7962306a36Sopenharmony_ci buf); 8062306a36Sopenharmony_ci return -1; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci ret = send(sk, &buf, sizeof(buf), 0); 8362306a36Sopenharmony_ci if (ret != 1) { 8462306a36Sopenharmony_ci fprintf(stderr, "%s: Child failed to ack\n", 8562306a36Sopenharmony_ci strerror(errno)); 8662306a36Sopenharmony_ci return -1; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci if (ret < 0) { 9062306a36Sopenharmony_ci fprintf(stderr, "%s: Child failed to read from socket\n", 9162306a36Sopenharmony_ci strerror(errno)); 9262306a36Sopenharmony_ci return -1; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int child(int sk) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci int memfd, ret; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci memfd = sys_memfd_create("test", 0); 10362306a36Sopenharmony_ci if (memfd < 0) { 10462306a36Sopenharmony_ci fprintf(stderr, "%s: Child could not create memfd\n", 10562306a36Sopenharmony_ci strerror(errno)); 10662306a36Sopenharmony_ci ret = -1; 10762306a36Sopenharmony_ci } else { 10862306a36Sopenharmony_ci ret = __child(sk, memfd); 10962306a36Sopenharmony_ci close(memfd); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci close(sk); 11362306a36Sopenharmony_ci return ret; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciFIXTURE(child) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * remote_fd is the number of the FD which we are trying to retrieve 12062306a36Sopenharmony_ci * from the child. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci int remote_fd; 12362306a36Sopenharmony_ci /* pid points to the child which we are fetching FDs from */ 12462306a36Sopenharmony_ci pid_t pid; 12562306a36Sopenharmony_ci /* pidfd is the pidfd of the child */ 12662306a36Sopenharmony_ci int pidfd; 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * sk is our side of the socketpair used to communicate with the child. 12962306a36Sopenharmony_ci * When it is closed, the child will exit. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci int sk; 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciFIXTURE_SETUP(child) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci int ret, sk_pair[2]; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair)) { 13962306a36Sopenharmony_ci TH_LOG("%s: failed to create socketpair", strerror(errno)); 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci self->sk = sk_pair[0]; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci self->pid = fork(); 14462306a36Sopenharmony_ci ASSERT_GE(self->pid, 0); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (self->pid == 0) { 14762306a36Sopenharmony_ci close(sk_pair[0]); 14862306a36Sopenharmony_ci if (child(sk_pair[1])) 14962306a36Sopenharmony_ci _exit(EXIT_FAILURE); 15062306a36Sopenharmony_ci _exit(EXIT_SUCCESS); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci close(sk_pair[1]); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci self->pidfd = sys_pidfd_open(self->pid, 0); 15662306a36Sopenharmony_ci ASSERT_GE(self->pidfd, 0); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* 15962306a36Sopenharmony_ci * Wait for the child to complete setup. It'll send the remote memfd's 16062306a36Sopenharmony_ci * number when ready. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci ret = recv(sk_pair[0], &self->remote_fd, sizeof(self->remote_fd), 0); 16362306a36Sopenharmony_ci ASSERT_EQ(sizeof(self->remote_fd), ret); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciFIXTURE_TEARDOWN(child) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci EXPECT_EQ(0, close(self->pidfd)); 16962306a36Sopenharmony_ci EXPECT_EQ(0, close(self->sk)); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci EXPECT_EQ(0, wait_for_pid(self->pid)); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciTEST_F(child, disable_ptrace) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci int uid, fd; 17762306a36Sopenharmony_ci char c; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* 18062306a36Sopenharmony_ci * Turn into nobody if we're root, to avoid CAP_SYS_PTRACE 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * The tests should run in their own process, so even this test fails, 18362306a36Sopenharmony_ci * it shouldn't result in subsequent tests failing. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ci uid = getuid(); 18662306a36Sopenharmony_ci if (uid == 0) 18762306a36Sopenharmony_ci ASSERT_EQ(0, seteuid(UID_NOBODY)); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci ASSERT_EQ(1, send(self->sk, "P", 1, 0)); 19062306a36Sopenharmony_ci ASSERT_EQ(1, recv(self->sk, &c, 1, 0)); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci fd = sys_pidfd_getfd(self->pidfd, self->remote_fd, 0); 19362306a36Sopenharmony_ci EXPECT_EQ(-1, fd); 19462306a36Sopenharmony_ci EXPECT_EQ(EPERM, errno); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (uid == 0) 19762306a36Sopenharmony_ci ASSERT_EQ(0, seteuid(0)); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ciTEST_F(child, fetch_fd) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci int fd, ret; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci fd = sys_pidfd_getfd(self->pidfd, self->remote_fd, 0); 20562306a36Sopenharmony_ci ASSERT_GE(fd, 0); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ret = sys_kcmp(getpid(), self->pid, KCMP_FILE, fd, self->remote_fd); 20862306a36Sopenharmony_ci if (ret < 0 && errno == ENOSYS) 20962306a36Sopenharmony_ci SKIP(return, "kcmp() syscall not supported"); 21062306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ret = fcntl(fd, F_GETFD); 21362306a36Sopenharmony_ci ASSERT_GE(ret, 0); 21462306a36Sopenharmony_ci EXPECT_GE(ret & FD_CLOEXEC, 0); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci close(fd); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ciTEST_F(child, test_unknown_fd) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci int fd; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci fd = sys_pidfd_getfd(self->pidfd, UNKNOWN_FD, 0); 22462306a36Sopenharmony_ci EXPECT_EQ(-1, fd) { 22562306a36Sopenharmony_ci TH_LOG("getfd succeeded while fetching unknown fd"); 22662306a36Sopenharmony_ci }; 22762306a36Sopenharmony_ci EXPECT_EQ(EBADF, errno) { 22862306a36Sopenharmony_ci TH_LOG("%s: getfd did not get EBADF", strerror(errno)); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ciTEST(flags_set) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci ASSERT_EQ(-1, sys_pidfd_getfd(0, 0, 1)); 23562306a36Sopenharmony_ci EXPECT_EQ(errno, EINVAL); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#if __NR_pidfd_getfd == -1 23962306a36Sopenharmony_ciint main(void) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci fprintf(stderr, "__NR_pidfd_getfd undefined. The pidfd_getfd syscall is unavailable. Test aborting\n"); 24262306a36Sopenharmony_ci return KSFT_SKIP; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci#else 24562306a36Sopenharmony_ciTEST_HARNESS_MAIN 24662306a36Sopenharmony_ci#endif 247