Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #define _GNU_SOURCE
0004 #include <assert.h>
0005 #include <errno.h>
0006 #include <fcntl.h>
0007 #include <linux/types.h>
0008 #include <sched.h>
0009 #include <signal.h>
0010 #include <stdio.h>
0011 #include <stdlib.h>
0012 #include <string.h>
0013 #include <syscall.h>
0014 #include <sys/wait.h>
0015 #include <sys/mman.h>
0016 
0017 #include "pidfd.h"
0018 #include "../kselftest.h"
0019 
0020 struct error {
0021     int  code;
0022     char msg[512];
0023 };
0024 
0025 static int error_set(struct error *err, int code, const char *fmt, ...)
0026 {
0027     va_list args;
0028     int r;
0029 
0030     if (code == PIDFD_PASS || !err || err->code != PIDFD_PASS)
0031         return code;
0032 
0033     err->code = code;
0034     va_start(args, fmt);
0035     r = vsnprintf(err->msg, sizeof(err->msg), fmt, args);
0036     assert((size_t)r < sizeof(err->msg));
0037     va_end(args);
0038 
0039     return code;
0040 }
0041 
0042 static void error_report(struct error *err, const char *test_name)
0043 {
0044     switch (err->code) {
0045     case PIDFD_ERROR:
0046         ksft_exit_fail_msg("%s test: Fatal: %s\n", test_name, err->msg);
0047         break;
0048 
0049     case PIDFD_FAIL:
0050         /* will be: not ok %d # error %s test: %s */
0051         ksft_test_result_error("%s test: %s\n", test_name, err->msg);
0052         break;
0053 
0054     case PIDFD_SKIP:
0055         /* will be: not ok %d # SKIP %s test: %s */
0056         ksft_test_result_skip("%s test: %s\n", test_name, err->msg);
0057         break;
0058 
0059     case PIDFD_XFAIL:
0060         ksft_test_result_pass("%s test: Expected failure: %s\n",
0061                       test_name, err->msg);
0062         break;
0063 
0064     case PIDFD_PASS:
0065         ksft_test_result_pass("%s test: Passed\n");
0066         break;
0067 
0068     default:
0069         ksft_exit_fail_msg("%s test: Unknown code: %d %s\n",
0070                    test_name, err->code, err->msg);
0071         break;
0072     }
0073 }
0074 
0075 static inline int error_check(struct error *err, const char *test_name)
0076 {
0077     /* In case of error we bail out and terminate the test program */
0078     if (err->code == PIDFD_ERROR)
0079         error_report(err, test_name);
0080 
0081     return err->code;
0082 }
0083 
0084 #define CHILD_STACK_SIZE 8192
0085 
0086 struct child {
0087     char *stack;
0088     pid_t pid;
0089     int   fd;
0090 };
0091 
0092 static struct child clone_newns(int (*fn)(void *), void *args,
0093                 struct error *err)
0094 {
0095     static int flags = CLONE_PIDFD | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD;
0096     struct child ret;
0097 
0098     if (!(flags & CLONE_NEWUSER) && geteuid() != 0)
0099         flags |= CLONE_NEWUSER;
0100 
0101     ret.stack = mmap(NULL, CHILD_STACK_SIZE, PROT_READ | PROT_WRITE,
0102              MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
0103     if (ret.stack == MAP_FAILED) {
0104         error_set(err, -1, "mmap of stack failed (errno %d)", errno);
0105         return ret;
0106     }
0107 
0108 #ifdef __ia64__
0109     ret.pid = __clone2(fn, ret.stack, CHILD_STACK_SIZE, flags, args, &ret.fd);
0110 #else
0111     ret.pid = clone(fn, ret.stack + CHILD_STACK_SIZE, flags, args, &ret.fd);
0112 #endif
0113 
0114     if (ret.pid < 0) {
0115         error_set(err, PIDFD_ERROR, "clone failed (ret %d, errno %d)",
0116               ret.fd, errno);
0117         return ret;
0118     }
0119 
0120     ksft_print_msg("New child: %d, fd: %d\n", ret.pid, ret.fd);
0121 
0122     return ret;
0123 }
0124 
0125 static inline void child_close(struct child *child)
0126 {
0127     close(child->fd);
0128 }
0129 
0130 static inline int child_join(struct child *child, struct error *err)
0131 {
0132     int r;
0133 
0134     r = wait_for_pid(child->pid);
0135     if (r < 0)
0136         error_set(err, PIDFD_ERROR, "waitpid failed (ret %d, errno %d)",
0137               r, errno);
0138     else if (r > 0)
0139         error_set(err, r, "child %d reported: %d", child->pid, r);
0140 
0141     if (munmap(child->stack, CHILD_STACK_SIZE)) {
0142         error_set(err, -1, "munmap of child stack failed (errno %d)", errno);
0143         r = -1;
0144     }
0145 
0146     return r;
0147 }
0148 
0149 static inline int child_join_close(struct child *child, struct error *err)
0150 {
0151     child_close(child);
0152     return child_join(child, err);
0153 }
0154 
0155 static inline void trim_newline(char *str)
0156 {
0157     char *pos = strrchr(str, '\n');
0158 
0159     if (pos)
0160         *pos = '\0';
0161 }
0162 
0163 static int verify_fdinfo(int pidfd, struct error *err, const char *prefix,
0164              size_t prefix_len, const char *expect, ...)
0165 {
0166     char buffer[512] = {0, };
0167     char path[512] = {0, };
0168     va_list args;
0169     FILE *f;
0170     char *line = NULL;
0171     size_t n = 0;
0172     int found = 0;
0173     int r;
0174 
0175     va_start(args, expect);
0176     r = vsnprintf(buffer, sizeof(buffer), expect, args);
0177     assert((size_t)r < sizeof(buffer));
0178     va_end(args);
0179 
0180     snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
0181     f = fopen(path, "re");
0182     if (!f)
0183         return error_set(err, PIDFD_ERROR, "fdinfo open failed for %d",
0184                  pidfd);
0185 
0186     while (getline(&line, &n, f) != -1) {
0187         char *val;
0188 
0189         if (strncmp(line, prefix, prefix_len))
0190             continue;
0191 
0192         found = 1;
0193 
0194         val = line + prefix_len;
0195         r = strcmp(val, buffer);
0196         if (r != 0) {
0197             trim_newline(line);
0198             trim_newline(buffer);
0199             error_set(err, PIDFD_FAIL, "%s '%s' != '%s'",
0200                   prefix, val, buffer);
0201         }
0202         break;
0203     }
0204 
0205     free(line);
0206     fclose(f);
0207 
0208     if (found == 0)
0209         return error_set(err, PIDFD_FAIL, "%s not found for fd %d",
0210                  prefix, pidfd);
0211 
0212     return PIDFD_PASS;
0213 }
0214 
0215 static int child_fdinfo_nspid_test(void *args)
0216 {
0217     struct error err;
0218     int pidfd;
0219     int r;
0220 
0221     /* if we got no fd for the sibling, we are done */
0222     if (!args)
0223         return PIDFD_PASS;
0224 
0225     /* verify that we can not resolve the pidfd for a process
0226      * in a sibling pid namespace, i.e. a pid namespace it is
0227      * not in our or a descended namespace
0228      */
0229     r = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
0230     if (r < 0) {
0231         ksft_print_msg("Failed to remount / private\n");
0232         return PIDFD_ERROR;
0233     }
0234 
0235     (void)umount2("/proc", MNT_DETACH);
0236     r = mount("proc", "/proc", "proc", 0, NULL);
0237     if (r < 0) {
0238         ksft_print_msg("Failed to remount /proc\n");
0239         return PIDFD_ERROR;
0240     }
0241 
0242     pidfd = *(int *)args;
0243     r = verify_fdinfo(pidfd, &err, "NSpid:", 6, "\t0\n");
0244 
0245     if (r != PIDFD_PASS)
0246         ksft_print_msg("NSpid fdinfo check failed: %s\n", err.msg);
0247 
0248     return r;
0249 }
0250 
0251 static void test_pidfd_fdinfo_nspid(void)
0252 {
0253     struct child a, b;
0254     struct error err = {0, };
0255     const char *test_name = "pidfd check for NSpid in fdinfo";
0256 
0257     /* Create a new child in a new pid and mount namespace */
0258     a = clone_newns(child_fdinfo_nspid_test, NULL, &err);
0259     error_check(&err, test_name);
0260 
0261     /* Pass the pidfd representing the first child to the
0262      * second child, which will be in a sibling pid namespace,
0263      * which means that the fdinfo NSpid entry for the pidfd
0264      * should only contain '0'.
0265      */
0266     b = clone_newns(child_fdinfo_nspid_test, &a.fd, &err);
0267     error_check(&err, test_name);
0268 
0269     /* The children will have pid 1 in the new pid namespace,
0270      * so the line must be 'NSPid:\t<pid>\t1'.
0271      */
0272     verify_fdinfo(a.fd, &err, "NSpid:", 6, "\t%d\t%d\n", a.pid, 1);
0273     verify_fdinfo(b.fd, &err, "NSpid:", 6, "\t%d\t%d\n", b.pid, 1);
0274 
0275     /* wait for the process, check the exit status and set
0276      * 'err' accordingly, if it is not already set.
0277      */
0278     child_join_close(&a, &err);
0279     child_join_close(&b, &err);
0280 
0281     error_report(&err, test_name);
0282 }
0283 
0284 static void test_pidfd_dead_fdinfo(void)
0285 {
0286     struct child a;
0287     struct error err = {0, };
0288     const char *test_name = "pidfd check fdinfo for dead process";
0289 
0290     /* Create a new child in a new pid and mount namespace */
0291     a = clone_newns(child_fdinfo_nspid_test, NULL, &err);
0292     error_check(&err, test_name);
0293     child_join(&a, &err);
0294 
0295     verify_fdinfo(a.fd, &err, "Pid:", 4, "\t-1\n");
0296     verify_fdinfo(a.fd, &err, "NSpid:", 6, "\t-1\n");
0297     child_close(&a);
0298     error_report(&err, test_name);
0299 }
0300 
0301 int main(int argc, char **argv)
0302 {
0303     ksft_print_header();
0304     ksft_set_plan(2);
0305 
0306     test_pidfd_fdinfo_nspid();
0307     test_pidfd_dead_fdinfo();
0308 
0309     return ksft_exit_pass();
0310 }