18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#define _GNU_SOURCE 48c2ecf20Sopenharmony_ci#include <assert.h> 58c2ecf20Sopenharmony_ci#include <errno.h> 68c2ecf20Sopenharmony_ci#include <fcntl.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/wait.h> 158c2ecf20Sopenharmony_ci#include <sys/mman.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "pidfd.h" 188c2ecf20Sopenharmony_ci#include "../kselftest.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct error { 218c2ecf20Sopenharmony_ci int code; 228c2ecf20Sopenharmony_ci char msg[512]; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int error_set(struct error *err, int code, const char *fmt, ...) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci va_list args; 288c2ecf20Sopenharmony_ci int r; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (code == PIDFD_PASS || !err || err->code != PIDFD_PASS) 318c2ecf20Sopenharmony_ci return code; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci err->code = code; 348c2ecf20Sopenharmony_ci va_start(args, fmt); 358c2ecf20Sopenharmony_ci r = vsnprintf(err->msg, sizeof(err->msg), fmt, args); 368c2ecf20Sopenharmony_ci assert((size_t)r < sizeof(err->msg)); 378c2ecf20Sopenharmony_ci va_end(args); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci return code; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void error_report(struct error *err, const char *test_name) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci switch (err->code) { 458c2ecf20Sopenharmony_ci case PIDFD_ERROR: 468c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Fatal: %s\n", test_name, err->msg); 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci case PIDFD_FAIL: 508c2ecf20Sopenharmony_ci /* will be: not ok %d # error %s test: %s */ 518c2ecf20Sopenharmony_ci ksft_test_result_error("%s test: %s\n", test_name, err->msg); 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci case PIDFD_SKIP: 558c2ecf20Sopenharmony_ci /* will be: not ok %d # SKIP %s test: %s */ 568c2ecf20Sopenharmony_ci ksft_test_result_skip("%s test: %s\n", test_name, err->msg); 578c2ecf20Sopenharmony_ci break; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci case PIDFD_XFAIL: 608c2ecf20Sopenharmony_ci ksft_test_result_pass("%s test: Expected failure: %s\n", 618c2ecf20Sopenharmony_ci test_name, err->msg); 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci case PIDFD_PASS: 658c2ecf20Sopenharmony_ci ksft_test_result_pass("%s test: Passed\n", test_name); 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci default: 698c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Unknown code: %d %s\n", 708c2ecf20Sopenharmony_ci test_name, err->code, err->msg); 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic inline int error_check(struct error *err, const char *test_name) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci /* In case of error we bail out and terminate the test program */ 788c2ecf20Sopenharmony_ci if (err->code == PIDFD_ERROR) 798c2ecf20Sopenharmony_ci error_report(err, test_name); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return err->code; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define CHILD_STACK_SIZE 8192 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistruct child { 878c2ecf20Sopenharmony_ci char *stack; 888c2ecf20Sopenharmony_ci pid_t pid; 898c2ecf20Sopenharmony_ci int fd; 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic struct child clone_newns(int (*fn)(void *), void *args, 938c2ecf20Sopenharmony_ci struct error *err) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci static int flags = CLONE_PIDFD | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD; 968c2ecf20Sopenharmony_ci struct child ret; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!(flags & CLONE_NEWUSER) && geteuid() != 0) 998c2ecf20Sopenharmony_ci flags |= CLONE_NEWUSER; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ret.stack = mmap(NULL, CHILD_STACK_SIZE, PROT_READ | PROT_WRITE, 1028c2ecf20Sopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 1038c2ecf20Sopenharmony_ci if (ret.stack == MAP_FAILED) { 1048c2ecf20Sopenharmony_ci error_set(err, -1, "mmap of stack failed (errno %d)", errno); 1058c2ecf20Sopenharmony_ci return ret; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#ifdef __ia64__ 1098c2ecf20Sopenharmony_ci ret.pid = __clone2(fn, ret.stack, CHILD_STACK_SIZE, flags, args, &ret.fd); 1108c2ecf20Sopenharmony_ci#else 1118c2ecf20Sopenharmony_ci ret.pid = clone(fn, ret.stack + CHILD_STACK_SIZE, flags, args, &ret.fd); 1128c2ecf20Sopenharmony_ci#endif 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (ret.pid < 0) { 1158c2ecf20Sopenharmony_ci error_set(err, PIDFD_ERROR, "clone failed (ret %d, errno %d)", 1168c2ecf20Sopenharmony_ci ret.fd, errno); 1178c2ecf20Sopenharmony_ci return ret; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ksft_print_msg("New child: %d, fd: %d\n", ret.pid, ret.fd); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return ret; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic inline void child_close(struct child *child) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci close(child->fd); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline int child_join(struct child *child, struct error *err) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci int r; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci r = wait_for_pid(child->pid); 1358c2ecf20Sopenharmony_ci if (r < 0) 1368c2ecf20Sopenharmony_ci error_set(err, PIDFD_ERROR, "waitpid failed (ret %d, errno %d)", 1378c2ecf20Sopenharmony_ci r, errno); 1388c2ecf20Sopenharmony_ci else if (r > 0) 1398c2ecf20Sopenharmony_ci error_set(err, r, "child %d reported: %d", child->pid, r); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (munmap(child->stack, CHILD_STACK_SIZE)) { 1428c2ecf20Sopenharmony_ci error_set(err, -1, "munmap of child stack failed (errno %d)", errno); 1438c2ecf20Sopenharmony_ci r = -1; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return r; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic inline int child_join_close(struct child *child, struct error *err) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci child_close(child); 1528c2ecf20Sopenharmony_ci return child_join(child, err); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic inline void trim_newline(char *str) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci char *pos = strrchr(str, '\n'); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (pos) 1608c2ecf20Sopenharmony_ci *pos = '\0'; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int verify_fdinfo(int pidfd, struct error *err, const char *prefix, 1648c2ecf20Sopenharmony_ci size_t prefix_len, const char *expect, ...) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci char buffer[512] = {0, }; 1678c2ecf20Sopenharmony_ci char path[512] = {0, }; 1688c2ecf20Sopenharmony_ci va_list args; 1698c2ecf20Sopenharmony_ci FILE *f; 1708c2ecf20Sopenharmony_ci char *line = NULL; 1718c2ecf20Sopenharmony_ci size_t n = 0; 1728c2ecf20Sopenharmony_ci int found = 0; 1738c2ecf20Sopenharmony_ci int r; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci va_start(args, expect); 1768c2ecf20Sopenharmony_ci r = vsnprintf(buffer, sizeof(buffer), expect, args); 1778c2ecf20Sopenharmony_ci assert((size_t)r < sizeof(buffer)); 1788c2ecf20Sopenharmony_ci va_end(args); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd); 1818c2ecf20Sopenharmony_ci f = fopen(path, "re"); 1828c2ecf20Sopenharmony_ci if (!f) 1838c2ecf20Sopenharmony_ci return error_set(err, PIDFD_ERROR, "fdinfo open failed for %d", 1848c2ecf20Sopenharmony_ci pidfd); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci while (getline(&line, &n, f) != -1) { 1878c2ecf20Sopenharmony_ci char *val; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (strncmp(line, prefix, prefix_len)) 1908c2ecf20Sopenharmony_ci continue; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci found = 1; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci val = line + prefix_len; 1958c2ecf20Sopenharmony_ci r = strcmp(val, buffer); 1968c2ecf20Sopenharmony_ci if (r != 0) { 1978c2ecf20Sopenharmony_ci trim_newline(line); 1988c2ecf20Sopenharmony_ci trim_newline(buffer); 1998c2ecf20Sopenharmony_ci error_set(err, PIDFD_FAIL, "%s '%s' != '%s'", 2008c2ecf20Sopenharmony_ci prefix, val, buffer); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci free(line); 2068c2ecf20Sopenharmony_ci fclose(f); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (found == 0) 2098c2ecf20Sopenharmony_ci return error_set(err, PIDFD_FAIL, "%s not found for fd %d", 2108c2ecf20Sopenharmony_ci prefix, pidfd); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return PIDFD_PASS; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int child_fdinfo_nspid_test(void *args) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct error err; 2188c2ecf20Sopenharmony_ci int pidfd; 2198c2ecf20Sopenharmony_ci int r; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* if we got no fd for the sibling, we are done */ 2228c2ecf20Sopenharmony_ci if (!args) 2238c2ecf20Sopenharmony_ci return PIDFD_PASS; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* verify that we can not resolve the pidfd for a process 2268c2ecf20Sopenharmony_ci * in a sibling pid namespace, i.e. a pid namespace it is 2278c2ecf20Sopenharmony_ci * not in our or a descended namespace 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci r = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); 2308c2ecf20Sopenharmony_ci if (r < 0) { 2318c2ecf20Sopenharmony_ci ksft_print_msg("Failed to remount / private\n"); 2328c2ecf20Sopenharmony_ci return PIDFD_ERROR; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci (void)umount2("/proc", MNT_DETACH); 2368c2ecf20Sopenharmony_ci r = mount("proc", "/proc", "proc", 0, NULL); 2378c2ecf20Sopenharmony_ci if (r < 0) { 2388c2ecf20Sopenharmony_ci ksft_print_msg("Failed to remount /proc\n"); 2398c2ecf20Sopenharmony_ci return PIDFD_ERROR; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci pidfd = *(int *)args; 2438c2ecf20Sopenharmony_ci r = verify_fdinfo(pidfd, &err, "NSpid:", 6, "\t0\n"); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (r != PIDFD_PASS) 2468c2ecf20Sopenharmony_ci ksft_print_msg("NSpid fdinfo check failed: %s\n", err.msg); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return r; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void test_pidfd_fdinfo_nspid(void) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct child a, b; 2548c2ecf20Sopenharmony_ci struct error err = {0, }; 2558c2ecf20Sopenharmony_ci const char *test_name = "pidfd check for NSpid in fdinfo"; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Create a new child in a new pid and mount namespace */ 2588c2ecf20Sopenharmony_ci a = clone_newns(child_fdinfo_nspid_test, NULL, &err); 2598c2ecf20Sopenharmony_ci error_check(&err, test_name); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* Pass the pidfd representing the first child to the 2628c2ecf20Sopenharmony_ci * second child, which will be in a sibling pid namespace, 2638c2ecf20Sopenharmony_ci * which means that the fdinfo NSpid entry for the pidfd 2648c2ecf20Sopenharmony_ci * should only contain '0'. 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci b = clone_newns(child_fdinfo_nspid_test, &a.fd, &err); 2678c2ecf20Sopenharmony_ci error_check(&err, test_name); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* The children will have pid 1 in the new pid namespace, 2708c2ecf20Sopenharmony_ci * so the line must be 'NSPid:\t<pid>\t1'. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci verify_fdinfo(a.fd, &err, "NSpid:", 6, "\t%d\t%d\n", a.pid, 1); 2738c2ecf20Sopenharmony_ci verify_fdinfo(b.fd, &err, "NSpid:", 6, "\t%d\t%d\n", b.pid, 1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* wait for the process, check the exit status and set 2768c2ecf20Sopenharmony_ci * 'err' accordingly, if it is not already set. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci child_join_close(&a, &err); 2798c2ecf20Sopenharmony_ci child_join_close(&b, &err); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci error_report(&err, test_name); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic void test_pidfd_dead_fdinfo(void) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct child a; 2878c2ecf20Sopenharmony_ci struct error err = {0, }; 2888c2ecf20Sopenharmony_ci const char *test_name = "pidfd check fdinfo for dead process"; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Create a new child in a new pid and mount namespace */ 2918c2ecf20Sopenharmony_ci a = clone_newns(child_fdinfo_nspid_test, NULL, &err); 2928c2ecf20Sopenharmony_ci error_check(&err, test_name); 2938c2ecf20Sopenharmony_ci child_join(&a, &err); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci verify_fdinfo(a.fd, &err, "Pid:", 4, "\t-1\n"); 2968c2ecf20Sopenharmony_ci verify_fdinfo(a.fd, &err, "NSpid:", 6, "\t-1\n"); 2978c2ecf20Sopenharmony_ci child_close(&a); 2988c2ecf20Sopenharmony_ci error_report(&err, test_name); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ciint main(int argc, char **argv) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci ksft_print_header(); 3048c2ecf20Sopenharmony_ci ksft_set_plan(2); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci test_pidfd_fdinfo_nspid(); 3078c2ecf20Sopenharmony_ci test_pidfd_dead_fdinfo(); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return ksft_exit_pass(); 3108c2ecf20Sopenharmony_ci} 311