12def297eSChristian Kellner // SPDX-License-Identifier: GPL-2.0 22def297eSChristian Kellner 32def297eSChristian Kellner #define _GNU_SOURCE 42def297eSChristian Kellner #include <assert.h> 52def297eSChristian Kellner #include <errno.h> 62def297eSChristian Kellner #include <fcntl.h> 72def297eSChristian Kellner #include <linux/types.h> 82def297eSChristian Kellner #include <sched.h> 92def297eSChristian Kellner #include <signal.h> 102def297eSChristian Kellner #include <stdio.h> 112def297eSChristian Kellner #include <stdlib.h> 122def297eSChristian Kellner #include <string.h> 132def297eSChristian Kellner #include <syscall.h> 142def297eSChristian Kellner #include <sys/wait.h> 152def297eSChristian Kellner 162def297eSChristian Kellner #include "pidfd.h" 172def297eSChristian Kellner #include "../kselftest.h" 182def297eSChristian Kellner 192def297eSChristian Kellner struct error { 202def297eSChristian Kellner int code; 212def297eSChristian Kellner char msg[512]; 222def297eSChristian Kellner }; 232def297eSChristian Kellner 242def297eSChristian Kellner static int error_set(struct error *err, int code, const char *fmt, ...) 252def297eSChristian Kellner { 262def297eSChristian Kellner va_list args; 272def297eSChristian Kellner int r; 282def297eSChristian Kellner 292def297eSChristian Kellner if (code == PIDFD_PASS || !err || err->code != PIDFD_PASS) 302def297eSChristian Kellner return code; 312def297eSChristian Kellner 322def297eSChristian Kellner err->code = code; 332def297eSChristian Kellner va_start(args, fmt); 342def297eSChristian Kellner r = vsnprintf(err->msg, sizeof(err->msg), fmt, args); 352def297eSChristian Kellner assert((size_t)r < sizeof(err->msg)); 362def297eSChristian Kellner va_end(args); 372def297eSChristian Kellner 382def297eSChristian Kellner return code; 392def297eSChristian Kellner } 402def297eSChristian Kellner 412def297eSChristian Kellner static void error_report(struct error *err, const char *test_name) 422def297eSChristian Kellner { 432def297eSChristian Kellner switch (err->code) { 442def297eSChristian Kellner case PIDFD_ERROR: 452def297eSChristian Kellner ksft_exit_fail_msg("%s test: Fatal: %s\n", test_name, err->msg); 462def297eSChristian Kellner break; 472def297eSChristian Kellner 482def297eSChristian Kellner case PIDFD_FAIL: 492def297eSChristian Kellner /* will be: not ok %d # error %s test: %s */ 502def297eSChristian Kellner ksft_test_result_error("%s test: %s\n", test_name, err->msg); 512def297eSChristian Kellner break; 522def297eSChristian Kellner 532def297eSChristian Kellner case PIDFD_SKIP: 542def297eSChristian Kellner /* will be: not ok %d # SKIP %s test: %s */ 552def297eSChristian Kellner ksft_test_result_skip("%s test: %s\n", test_name, err->msg); 562def297eSChristian Kellner break; 572def297eSChristian Kellner 582def297eSChristian Kellner case PIDFD_XFAIL: 592def297eSChristian Kellner ksft_test_result_pass("%s test: Expected failure: %s\n", 602def297eSChristian Kellner test_name, err->msg); 612def297eSChristian Kellner break; 622def297eSChristian Kellner 632def297eSChristian Kellner case PIDFD_PASS: 642def297eSChristian Kellner ksft_test_result_pass("%s test: Passed\n"); 652def297eSChristian Kellner break; 662def297eSChristian Kellner 672def297eSChristian Kellner default: 682def297eSChristian Kellner ksft_exit_fail_msg("%s test: Unknown code: %d %s\n", 692def297eSChristian Kellner test_name, err->code, err->msg); 702def297eSChristian Kellner break; 712def297eSChristian Kellner } 722def297eSChristian Kellner } 732def297eSChristian Kellner 742def297eSChristian Kellner static inline int error_check(struct error *err, const char *test_name) 752def297eSChristian Kellner { 762def297eSChristian Kellner /* In case of error we bail out and terminate the test program */ 772def297eSChristian Kellner if (err->code == PIDFD_ERROR) 782def297eSChristian Kellner error_report(err, test_name); 792def297eSChristian Kellner 802def297eSChristian Kellner return err->code; 812def297eSChristian Kellner } 822def297eSChristian Kellner 832def297eSChristian Kellner struct child { 842def297eSChristian Kellner pid_t pid; 852def297eSChristian Kellner int fd; 862def297eSChristian Kellner }; 872def297eSChristian Kellner 882def297eSChristian Kellner static struct child clone_newns(int (*fn)(void *), void *args, 892def297eSChristian Kellner struct error *err) 902def297eSChristian Kellner { 912def297eSChristian Kellner static int flags = CLONE_PIDFD | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD; 922def297eSChristian Kellner size_t stack_size = 1024; 932def297eSChristian Kellner char *stack[1024] = { 0 }; 942def297eSChristian Kellner struct child ret; 952def297eSChristian Kellner 962def297eSChristian Kellner if (!(flags & CLONE_NEWUSER) && geteuid() != 0) 972def297eSChristian Kellner flags |= CLONE_NEWUSER; 982def297eSChristian Kellner 992def297eSChristian Kellner #ifdef __ia64__ 1002def297eSChristian Kellner ret.pid = __clone2(fn, stack, stack_size, flags, args, &ret.fd); 1012def297eSChristian Kellner #else 1022def297eSChristian Kellner ret.pid = clone(fn, stack + stack_size, flags, args, &ret.fd); 1032def297eSChristian Kellner #endif 1042def297eSChristian Kellner 1052def297eSChristian Kellner if (ret.pid < 0) { 1062def297eSChristian Kellner error_set(err, PIDFD_ERROR, "clone failed (ret %d, errno %d)", 1072def297eSChristian Kellner ret.fd, errno); 1082def297eSChristian Kellner return ret; 1092def297eSChristian Kellner } 1102def297eSChristian Kellner 1112def297eSChristian Kellner ksft_print_msg("New child: %d, fd: %d\n", ret.pid, ret.fd); 1122def297eSChristian Kellner 1132def297eSChristian Kellner return ret; 1142def297eSChristian Kellner } 1152def297eSChristian Kellner 1162def297eSChristian Kellner static inline int child_join(struct child *child, struct error *err) 1172def297eSChristian Kellner { 1182def297eSChristian Kellner int r; 1192def297eSChristian Kellner 1202def297eSChristian Kellner (void)close(child->fd); 1212def297eSChristian Kellner r = wait_for_pid(child->pid); 1222def297eSChristian Kellner if (r < 0) 1232def297eSChristian Kellner error_set(err, PIDFD_ERROR, "waitpid failed (ret %d, errno %d)", 1242def297eSChristian Kellner r, errno); 1252def297eSChristian Kellner else if (r > 0) 1262def297eSChristian Kellner error_set(err, r, "child %d reported: %d", child->pid, r); 1272def297eSChristian Kellner 1282def297eSChristian Kellner return r; 1292def297eSChristian Kellner } 1302def297eSChristian Kellner 1312def297eSChristian Kellner static inline void trim_newline(char *str) 1322def297eSChristian Kellner { 1332def297eSChristian Kellner char *pos = strrchr(str, '\n'); 1342def297eSChristian Kellner 1352def297eSChristian Kellner if (pos) 1362def297eSChristian Kellner *pos = '\0'; 1372def297eSChristian Kellner } 1382def297eSChristian Kellner 1392def297eSChristian Kellner static int verify_fdinfo_nspid(int pidfd, struct error *err, 1402def297eSChristian Kellner const char *expect, ...) 1412def297eSChristian Kellner { 1422def297eSChristian Kellner char buffer[512] = {0, }; 1432def297eSChristian Kellner char path[512] = {0, }; 1442def297eSChristian Kellner va_list args; 1452def297eSChristian Kellner FILE *f; 1462def297eSChristian Kellner char *line = NULL; 1472def297eSChristian Kellner size_t n = 0; 1482def297eSChristian Kellner int found = 0; 1492def297eSChristian Kellner int r; 1502def297eSChristian Kellner 1512def297eSChristian Kellner va_start(args, expect); 1522def297eSChristian Kellner r = vsnprintf(buffer, sizeof(buffer), expect, args); 1532def297eSChristian Kellner assert((size_t)r < sizeof(buffer)); 1542def297eSChristian Kellner va_end(args); 1552def297eSChristian Kellner 1562def297eSChristian Kellner snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd); 1572def297eSChristian Kellner f = fopen(path, "re"); 1582def297eSChristian Kellner if (!f) 1592def297eSChristian Kellner return error_set(err, PIDFD_ERROR, "fdinfo open failed for %d", 1602def297eSChristian Kellner pidfd); 1612def297eSChristian Kellner 1622def297eSChristian Kellner while (getline(&line, &n, f) != -1) { 1632def297eSChristian Kellner if (strncmp(line, "NSpid:", 6)) 1642def297eSChristian Kellner continue; 1652def297eSChristian Kellner 1662def297eSChristian Kellner found = 1; 1672def297eSChristian Kellner 1682def297eSChristian Kellner r = strcmp(line + 6, buffer); 1692def297eSChristian Kellner if (r != 0) { 1702def297eSChristian Kellner trim_newline(line); 1712def297eSChristian Kellner trim_newline(buffer); 1722def297eSChristian Kellner error_set(err, PIDFD_FAIL, "NSpid: '%s' != '%s'", 1732def297eSChristian Kellner line + 6, buffer); 1742def297eSChristian Kellner } 1752def297eSChristian Kellner break; 1762def297eSChristian Kellner } 1772def297eSChristian Kellner 1782def297eSChristian Kellner free(line); 1792def297eSChristian Kellner fclose(f); 1802def297eSChristian Kellner 1812def297eSChristian Kellner if (found == 0) 1822def297eSChristian Kellner return error_set(err, PIDFD_FAIL, "NSpid not found for fd %d", 1832def297eSChristian Kellner pidfd); 1842def297eSChristian Kellner 1852def297eSChristian Kellner return PIDFD_PASS; 1862def297eSChristian Kellner } 1872def297eSChristian Kellner 1882def297eSChristian Kellner static int child_fdinfo_nspid_test(void *args) 1892def297eSChristian Kellner { 1902def297eSChristian Kellner struct error err; 1912def297eSChristian Kellner int pidfd; 1922def297eSChristian Kellner int r; 1932def297eSChristian Kellner 1942def297eSChristian Kellner /* if we got no fd for the sibling, we are done */ 1952def297eSChristian Kellner if (!args) 1962def297eSChristian Kellner return PIDFD_PASS; 1972def297eSChristian Kellner 1982def297eSChristian Kellner /* verify that we can not resolve the pidfd for a process 1992def297eSChristian Kellner * in a sibling pid namespace, i.e. a pid namespace it is 2002def297eSChristian Kellner * not in our or a descended namespace 2012def297eSChristian Kellner */ 2022def297eSChristian Kellner r = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); 2032def297eSChristian Kellner if (r < 0) { 2042def297eSChristian Kellner ksft_print_msg("Failed to remount / private\n"); 2052def297eSChristian Kellner return PIDFD_ERROR; 2062def297eSChristian Kellner } 2072def297eSChristian Kellner 2082def297eSChristian Kellner (void)umount2("/proc", MNT_DETACH); 2092def297eSChristian Kellner r = mount("proc", "/proc", "proc", 0, NULL); 2102def297eSChristian Kellner if (r < 0) { 2112def297eSChristian Kellner ksft_print_msg("Failed to remount /proc\n"); 2122def297eSChristian Kellner return PIDFD_ERROR; 2132def297eSChristian Kellner } 2142def297eSChristian Kellner 2152def297eSChristian Kellner pidfd = *(int *)args; 2162def297eSChristian Kellner r = verify_fdinfo_nspid(pidfd, &err, "\t0\n"); 2172def297eSChristian Kellner 2182def297eSChristian Kellner if (r != PIDFD_PASS) 2192def297eSChristian Kellner ksft_print_msg("NSpid fdinfo check failed: %s\n", err.msg); 2202def297eSChristian Kellner 2212def297eSChristian Kellner return r; 2222def297eSChristian Kellner } 2232def297eSChristian Kellner 2242def297eSChristian Kellner static void test_pidfd_fdinfo_nspid(void) 2252def297eSChristian Kellner { 2262def297eSChristian Kellner struct child a, b; 2272def297eSChristian Kellner struct error err = {0, }; 2282def297eSChristian Kellner const char *test_name = "pidfd check for NSpid in fdinfo"; 2292def297eSChristian Kellner 2302def297eSChristian Kellner /* Create a new child in a new pid and mount namespace */ 2312def297eSChristian Kellner a = clone_newns(child_fdinfo_nspid_test, NULL, &err); 2322def297eSChristian Kellner error_check(&err, test_name); 2332def297eSChristian Kellner 2342def297eSChristian Kellner /* Pass the pidfd representing the first child to the 2352def297eSChristian Kellner * second child, which will be in a sibling pid namespace, 2362def297eSChristian Kellner * which means that the fdinfo NSpid entry for the pidfd 2372def297eSChristian Kellner * should only contain '0'. 2382def297eSChristian Kellner */ 2392def297eSChristian Kellner b = clone_newns(child_fdinfo_nspid_test, &a.fd, &err); 2402def297eSChristian Kellner error_check(&err, test_name); 2412def297eSChristian Kellner 2422def297eSChristian Kellner /* The children will have pid 1 in the new pid namespace, 2432def297eSChristian Kellner * so the line must be 'NSPid:\t<pid>\t1'. 2442def297eSChristian Kellner */ 2452def297eSChristian Kellner verify_fdinfo_nspid(a.fd, &err, "\t%d\t%d\n", a.pid, 1); 2462def297eSChristian Kellner verify_fdinfo_nspid(b.fd, &err, "\t%d\t%d\n", b.pid, 1); 2472def297eSChristian Kellner 2482def297eSChristian Kellner /* wait for the process, check the exit status and set 2492def297eSChristian Kellner * 'err' accordingly, if it is not already set. 2502def297eSChristian Kellner */ 2512def297eSChristian Kellner child_join(&a, &err); 2522def297eSChristian Kellner child_join(&b, &err); 2532def297eSChristian Kellner 2542def297eSChristian Kellner error_report(&err, test_name); 2552def297eSChristian Kellner } 2562def297eSChristian Kellner 2572def297eSChristian Kellner int main(int argc, char **argv) 2582def297eSChristian Kellner { 2592def297eSChristian Kellner ksft_print_header(); 2602def297eSChristian Kellner ksft_set_plan(1); 2612def297eSChristian Kellner 2622def297eSChristian Kellner test_pidfd_fdinfo_nspid(); 2632def297eSChristian Kellner 2642def297eSChristian Kellner return ksft_exit_pass(); 2652def297eSChristian Kellner } 266