1 // SPDX-License-Identifier: GPL-2.0
7 #include <linux/types.h>
17 #include "../kselftest.h"
24 static int error_set(struct error
*err
, int code
, const char *fmt
, ...)
29 if (code
== PIDFD_PASS
|| !err
|| err
->code
!= PIDFD_PASS
)
34 r
= vsnprintf(err
->msg
, sizeof(err
->msg
), fmt
, args
);
35 assert((size_t)r
< sizeof(err
->msg
));
41 static void error_report(struct error
*err
, const char *test_name
)
45 ksft_exit_fail_msg("%s test: Fatal: %s\n", test_name
, err
->msg
);
49 /* will be: not ok %d # error %s test: %s */
50 ksft_test_result_error("%s test: %s\n", test_name
, err
->msg
);
54 /* will be: not ok %d # SKIP %s test: %s */
55 ksft_test_result_skip("%s test: %s\n", test_name
, err
->msg
);
59 ksft_test_result_pass("%s test: Expected failure: %s\n",
64 ksft_test_result_pass("%s test: Passed\n");
68 ksft_exit_fail_msg("%s test: Unknown code: %d %s\n",
69 test_name
, err
->code
, err
->msg
);
74 static inline int error_check(struct error
*err
, const char *test_name
)
76 /* In case of error we bail out and terminate the test program */
77 if (err
->code
== PIDFD_ERROR
)
78 error_report(err
, test_name
);
88 static struct child
clone_newns(int (*fn
)(void *), void *args
,
91 static int flags
= CLONE_PIDFD
| CLONE_NEWPID
| CLONE_NEWNS
| SIGCHLD
;
92 size_t stack_size
= 1024;
93 char *stack
[1024] = { 0 };
96 if (!(flags
& CLONE_NEWUSER
) && geteuid() != 0)
97 flags
|= CLONE_NEWUSER
;
100 ret
.pid
= __clone2(fn
, stack
, stack_size
, flags
, args
, &ret
.fd
);
102 ret
.pid
= clone(fn
, stack
+ stack_size
, flags
, args
, &ret
.fd
);
106 error_set(err
, PIDFD_ERROR
, "clone failed (ret %d, errno %d)",
111 ksft_print_msg("New child: %d, fd: %d\n", ret
.pid
, ret
.fd
);
116 static inline void child_close(struct child
*child
)
121 static inline int child_join(struct child
*child
, struct error
*err
)
125 r
= wait_for_pid(child
->pid
);
127 error_set(err
, PIDFD_ERROR
, "waitpid failed (ret %d, errno %d)",
130 error_set(err
, r
, "child %d reported: %d", child
->pid
, r
);
135 static inline int child_join_close(struct child
*child
, struct error
*err
)
138 return child_join(child
, err
);
141 static inline void trim_newline(char *str
)
143 char *pos
= strrchr(str
, '\n');
149 static int verify_fdinfo(int pidfd
, struct error
*err
, const char *prefix
,
150 size_t prefix_len
, const char *expect
, ...)
152 char buffer
[512] = {0, };
153 char path
[512] = {0, };
161 va_start(args
, expect
);
162 r
= vsnprintf(buffer
, sizeof(buffer
), expect
, args
);
163 assert((size_t)r
< sizeof(buffer
));
166 snprintf(path
, sizeof(path
), "/proc/self/fdinfo/%d", pidfd
);
167 f
= fopen(path
, "re");
169 return error_set(err
, PIDFD_ERROR
, "fdinfo open failed for %d",
172 while (getline(&line
, &n
, f
) != -1) {
175 if (strncmp(line
, prefix
, prefix_len
))
180 val
= line
+ prefix_len
;
181 r
= strcmp(val
, buffer
);
184 trim_newline(buffer
);
185 error_set(err
, PIDFD_FAIL
, "%s '%s' != '%s'",
186 prefix
, val
, buffer
);
195 return error_set(err
, PIDFD_FAIL
, "%s not found for fd %d",
201 static int child_fdinfo_nspid_test(void *args
)
207 /* if we got no fd for the sibling, we are done */
211 /* verify that we can not resolve the pidfd for a process
212 * in a sibling pid namespace, i.e. a pid namespace it is
213 * not in our or a descended namespace
215 r
= mount(NULL
, "/", NULL
, MS_REC
| MS_PRIVATE
, 0);
217 ksft_print_msg("Failed to remount / private\n");
221 (void)umount2("/proc", MNT_DETACH
);
222 r
= mount("proc", "/proc", "proc", 0, NULL
);
224 ksft_print_msg("Failed to remount /proc\n");
228 pidfd
= *(int *)args
;
229 r
= verify_fdinfo(pidfd
, &err
, "NSpid:", 6, "\t0\n");
232 ksft_print_msg("NSpid fdinfo check failed: %s\n", err
.msg
);
237 static void test_pidfd_fdinfo_nspid(void)
240 struct error err
= {0, };
241 const char *test_name
= "pidfd check for NSpid in fdinfo";
243 /* Create a new child in a new pid and mount namespace */
244 a
= clone_newns(child_fdinfo_nspid_test
, NULL
, &err
);
245 error_check(&err
, test_name
);
247 /* Pass the pidfd representing the first child to the
248 * second child, which will be in a sibling pid namespace,
249 * which means that the fdinfo NSpid entry for the pidfd
250 * should only contain '0'.
252 b
= clone_newns(child_fdinfo_nspid_test
, &a
.fd
, &err
);
253 error_check(&err
, test_name
);
255 /* The children will have pid 1 in the new pid namespace,
256 * so the line must be 'NSPid:\t<pid>\t1'.
258 verify_fdinfo(a
.fd
, &err
, "NSpid:", 6, "\t%d\t%d\n", a
.pid
, 1);
259 verify_fdinfo(b
.fd
, &err
, "NSpid:", 6, "\t%d\t%d\n", b
.pid
, 1);
261 /* wait for the process, check the exit status and set
262 * 'err' accordingly, if it is not already set.
264 child_join_close(&a
, &err
);
265 child_join_close(&b
, &err
);
267 error_report(&err
, test_name
);
270 static void test_pidfd_dead_fdinfo(void)
273 struct error err
= {0, };
274 const char *test_name
= "pidfd check fdinfo for dead process";
276 /* Create a new child in a new pid and mount namespace */
277 a
= clone_newns(child_fdinfo_nspid_test
, NULL
, &err
);
278 error_check(&err
, test_name
);
279 child_join(&a
, &err
);
281 verify_fdinfo(a
.fd
, &err
, "Pid:", 4, "\t-1\n");
282 verify_fdinfo(a
.fd
, &err
, "NSpid:", 6, "\t-1\n");
284 error_report(&err
, test_name
);
287 int main(int argc
, char **argv
)
292 test_pidfd_fdinfo_nspid();
293 test_pidfd_dead_fdinfo();
295 return ksft_exit_pass();