0001
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
0051 ksft_test_result_error("%s test: %s\n", test_name, err->msg);
0052 break;
0053
0054 case PIDFD_SKIP:
0055
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
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
0222 if (!args)
0223 return PIDFD_PASS;
0224
0225
0226
0227
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
0258 a = clone_newns(child_fdinfo_nspid_test, NULL, &err);
0259 error_check(&err, test_name);
0260
0261
0262
0263
0264
0265
0266 b = clone_newns(child_fdinfo_nspid_test, &a.fd, &err);
0267 error_check(&err, test_name);
0268
0269
0270
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
0276
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
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 }