18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#define _GNU_SOURCE 48c2ecf20Sopenharmony_ci#include <errno.h> 58c2ecf20Sopenharmony_ci#include <fcntl.h> 68c2ecf20Sopenharmony_ci#include <limits.h> 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <sched.h> 98c2ecf20Sopenharmony_ci#include <signal.h> 108c2ecf20Sopenharmony_ci#include <stdio.h> 118c2ecf20Sopenharmony_ci#include <stdlib.h> 128c2ecf20Sopenharmony_ci#include <string.h> 138c2ecf20Sopenharmony_ci#include <syscall.h> 148c2ecf20Sopenharmony_ci#include <sys/prctl.h> 158c2ecf20Sopenharmony_ci#include <sys/wait.h> 168c2ecf20Sopenharmony_ci#include <unistd.h> 178c2ecf20Sopenharmony_ci#include <sys/socket.h> 188c2ecf20Sopenharmony_ci#include <linux/kcmp.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "pidfd.h" 218c2ecf20Sopenharmony_ci#include "../kselftest_harness.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * UNKNOWN_FD is an fd number that should never exist in the child, as it is 258c2ecf20Sopenharmony_ci * used to check the negative case. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci#define UNKNOWN_FD 111 288c2ecf20Sopenharmony_ci#define UID_NOBODY 65535 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, 318c2ecf20Sopenharmony_ci unsigned long idx2) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int __child(int sk, int memfd) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci int ret; 398c2ecf20Sopenharmony_ci char buf; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* 428c2ecf20Sopenharmony_ci * Ensure we don't leave around a bunch of orphaned children if our 438c2ecf20Sopenharmony_ci * tests fail. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci ret = prctl(PR_SET_PDEATHSIG, SIGKILL); 468c2ecf20Sopenharmony_ci if (ret) { 478c2ecf20Sopenharmony_ci fprintf(stderr, "%s: Child could not set DEATHSIG\n", 488c2ecf20Sopenharmony_ci strerror(errno)); 498c2ecf20Sopenharmony_ci return -1; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci ret = send(sk, &memfd, sizeof(memfd), 0); 538c2ecf20Sopenharmony_ci if (ret != sizeof(memfd)) { 548c2ecf20Sopenharmony_ci fprintf(stderr, "%s: Child failed to send fd number\n", 558c2ecf20Sopenharmony_ci strerror(errno)); 568c2ecf20Sopenharmony_ci return -1; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* 608c2ecf20Sopenharmony_ci * The fixture setup is completed at this point. The tests will run. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * This blocking recv enables the parent to message the child. 638c2ecf20Sopenharmony_ci * Either we will read 'P' off of the sk, indicating that we need 648c2ecf20Sopenharmony_ci * to disable ptrace, or we will read a 0, indicating that the other 658c2ecf20Sopenharmony_ci * side has closed the sk. This occurs during fixture teardown time, 668c2ecf20Sopenharmony_ci * indicating that the child should exit. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci while ((ret = recv(sk, &buf, sizeof(buf), 0)) > 0) { 698c2ecf20Sopenharmony_ci if (buf == 'P') { 708c2ecf20Sopenharmony_ci ret = prctl(PR_SET_DUMPABLE, 0); 718c2ecf20Sopenharmony_ci if (ret < 0) { 728c2ecf20Sopenharmony_ci fprintf(stderr, 738c2ecf20Sopenharmony_ci "%s: Child failed to disable ptrace\n", 748c2ecf20Sopenharmony_ci strerror(errno)); 758c2ecf20Sopenharmony_ci return -1; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci } else { 788c2ecf20Sopenharmony_ci fprintf(stderr, "Child received unknown command %c\n", 798c2ecf20Sopenharmony_ci buf); 808c2ecf20Sopenharmony_ci return -1; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci ret = send(sk, &buf, sizeof(buf), 0); 838c2ecf20Sopenharmony_ci if (ret != 1) { 848c2ecf20Sopenharmony_ci fprintf(stderr, "%s: Child failed to ack\n", 858c2ecf20Sopenharmony_ci strerror(errno)); 868c2ecf20Sopenharmony_ci return -1; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci if (ret < 0) { 908c2ecf20Sopenharmony_ci fprintf(stderr, "%s: Child failed to read from socket\n", 918c2ecf20Sopenharmony_ci strerror(errno)); 928c2ecf20Sopenharmony_ci return -1; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int child(int sk) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci int memfd, ret; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci memfd = sys_memfd_create("test", 0); 1038c2ecf20Sopenharmony_ci if (memfd < 0) { 1048c2ecf20Sopenharmony_ci fprintf(stderr, "%s: Child could not create memfd\n", 1058c2ecf20Sopenharmony_ci strerror(errno)); 1068c2ecf20Sopenharmony_ci ret = -1; 1078c2ecf20Sopenharmony_ci } else { 1088c2ecf20Sopenharmony_ci ret = __child(sk, memfd); 1098c2ecf20Sopenharmony_ci close(memfd); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci close(sk); 1138c2ecf20Sopenharmony_ci return ret; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciFIXTURE(child) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * remote_fd is the number of the FD which we are trying to retrieve 1208c2ecf20Sopenharmony_ci * from the child. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci int remote_fd; 1238c2ecf20Sopenharmony_ci /* pid points to the child which we are fetching FDs from */ 1248c2ecf20Sopenharmony_ci pid_t pid; 1258c2ecf20Sopenharmony_ci /* pidfd is the pidfd of the child */ 1268c2ecf20Sopenharmony_ci int pidfd; 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * sk is our side of the socketpair used to communicate with the child. 1298c2ecf20Sopenharmony_ci * When it is closed, the child will exit. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci int sk; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciFIXTURE_SETUP(child) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci int ret, sk_pair[2]; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair)) { 1398c2ecf20Sopenharmony_ci TH_LOG("%s: failed to create socketpair", strerror(errno)); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci self->sk = sk_pair[0]; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci self->pid = fork(); 1448c2ecf20Sopenharmony_ci ASSERT_GE(self->pid, 0); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (self->pid == 0) { 1478c2ecf20Sopenharmony_ci close(sk_pair[0]); 1488c2ecf20Sopenharmony_ci if (child(sk_pair[1])) 1498c2ecf20Sopenharmony_ci _exit(EXIT_FAILURE); 1508c2ecf20Sopenharmony_ci _exit(EXIT_SUCCESS); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci close(sk_pair[1]); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci self->pidfd = sys_pidfd_open(self->pid, 0); 1568c2ecf20Sopenharmony_ci ASSERT_GE(self->pidfd, 0); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * Wait for the child to complete setup. It'll send the remote memfd's 1608c2ecf20Sopenharmony_ci * number when ready. 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci ret = recv(sk_pair[0], &self->remote_fd, sizeof(self->remote_fd), 0); 1638c2ecf20Sopenharmony_ci ASSERT_EQ(sizeof(self->remote_fd), ret); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ciFIXTURE_TEARDOWN(child) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci EXPECT_EQ(0, close(self->pidfd)); 1698c2ecf20Sopenharmony_ci EXPECT_EQ(0, close(self->sk)); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci EXPECT_EQ(0, wait_for_pid(self->pid)); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciTEST_F(child, disable_ptrace) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci int uid, fd; 1778c2ecf20Sopenharmony_ci char c; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * Turn into nobody if we're root, to avoid CAP_SYS_PTRACE 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * The tests should run in their own process, so even this test fails, 1838c2ecf20Sopenharmony_ci * it shouldn't result in subsequent tests failing. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci uid = getuid(); 1868c2ecf20Sopenharmony_ci if (uid == 0) 1878c2ecf20Sopenharmony_ci ASSERT_EQ(0, seteuid(UID_NOBODY)); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci ASSERT_EQ(1, send(self->sk, "P", 1, 0)); 1908c2ecf20Sopenharmony_ci ASSERT_EQ(1, recv(self->sk, &c, 1, 0)); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci fd = sys_pidfd_getfd(self->pidfd, self->remote_fd, 0); 1938c2ecf20Sopenharmony_ci EXPECT_EQ(-1, fd); 1948c2ecf20Sopenharmony_ci EXPECT_EQ(EPERM, errno); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (uid == 0) 1978c2ecf20Sopenharmony_ci ASSERT_EQ(0, seteuid(0)); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ciTEST_F(child, fetch_fd) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci int fd, ret; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci fd = sys_pidfd_getfd(self->pidfd, self->remote_fd, 0); 2058c2ecf20Sopenharmony_ci ASSERT_GE(fd, 0); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = sys_kcmp(getpid(), self->pid, KCMP_FILE, fd, self->remote_fd); 2088c2ecf20Sopenharmony_ci if (ret < 0 && errno == ENOSYS) 2098c2ecf20Sopenharmony_ci SKIP(return, "kcmp() syscall not supported"); 2108c2ecf20Sopenharmony_ci EXPECT_EQ(ret, 0); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ret = fcntl(fd, F_GETFD); 2138c2ecf20Sopenharmony_ci ASSERT_GE(ret, 0); 2148c2ecf20Sopenharmony_ci EXPECT_GE(ret & FD_CLOEXEC, 0); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci close(fd); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciTEST_F(child, test_unknown_fd) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci int fd; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci fd = sys_pidfd_getfd(self->pidfd, UNKNOWN_FD, 0); 2248c2ecf20Sopenharmony_ci EXPECT_EQ(-1, fd) { 2258c2ecf20Sopenharmony_ci TH_LOG("getfd succeeded while fetching unknown fd"); 2268c2ecf20Sopenharmony_ci }; 2278c2ecf20Sopenharmony_ci EXPECT_EQ(EBADF, errno) { 2288c2ecf20Sopenharmony_ci TH_LOG("%s: getfd did not get EBADF", strerror(errno)); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ciTEST(flags_set) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci ASSERT_EQ(-1, sys_pidfd_getfd(0, 0, 1)); 2358c2ecf20Sopenharmony_ci EXPECT_EQ(errno, EINVAL); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci#if __NR_pidfd_getfd == -1 2398c2ecf20Sopenharmony_ciint main(void) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci fprintf(stderr, "__NR_pidfd_getfd undefined. The pidfd_getfd syscall is unavailable. Test aborting\n"); 2428c2ecf20Sopenharmony_ci return KSFT_SKIP; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci#else 2458c2ecf20Sopenharmony_ciTEST_HARNESS_MAIN 2468c2ecf20Sopenharmony_ci#endif 247