1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved.
4 * Author: Yang Xu <[email protected]>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Tests basic error handling of the pidfd_open syscall.
11 *
12 * - EBADF pidfd is not a valid PID file descriptor
13 * - EBADF targetfd is not an open file descriptor in the process referred
14 * to by pidfd
15 * - EINVAL flags is not 0
16 * - ESRCH the process referred to by pidfd does not exist (it has terminated
17 * and been waited on)
18 * - EPERM the calling process doesn't have PTRACE_MODE_ATTACH_REALCREDS permissions
19 * over the process referred to by pidfd
20 */
21
22 #include <stdlib.h>
23 #include <pwd.h>
24 #include "tst_test.h"
25 #include "tst_safe_macros.h"
26 #include "lapi/pidfd.h"
27
28 static int valid_pidfd = -1, invalid_pidfd = -1, pidfd = -1;
29 static uid_t uid;
30
31 static struct tcase {
32 char *name;
33 int *pidfd;
34 int targetfd;
35 int flags;
36 int exp_errno;
37 } tcases[] = {
38 {"invalid pidfd", &invalid_pidfd, 0, 0, EBADF},
39 {"invalid targetfd", &valid_pidfd, -1, 0, EBADF},
40 {"invalid flags", &valid_pidfd, 0, 1, EINVAL},
41 {"the process referred to by pidfd doesn't exist", NULL, 0, 0, ESRCH},
42 {"lack of required permission", &valid_pidfd, 0, 0, EPERM},
43 };
44
setup(void)45 static void setup(void)
46 {
47 pidfd_open_supported();
48 pidfd_getfd_supported();
49
50 struct passwd *pw;
51
52 pw = SAFE_GETPWNAM("nobody");
53 uid = pw->pw_uid;
54
55 valid_pidfd = SAFE_PIDFD_OPEN(getpid(), 0);
56 }
57
cleanup(void)58 static void cleanup(void)
59 {
60 if (valid_pidfd > -1)
61 SAFE_CLOSE(valid_pidfd);
62 if (pidfd > -1)
63 SAFE_CLOSE(pidfd);
64 }
65
run(unsigned int n)66 static void run(unsigned int n)
67 {
68 struct tcase *tc = &tcases[n];
69 int pid;
70
71 if (tc->exp_errno == EPERM) {
72 pid = SAFE_FORK();
73 if (!pid) {
74 SAFE_SETUID(uid);
75 TST_EXP_FAIL2(pidfd_getfd(valid_pidfd, tc->targetfd, tc->flags),
76 tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s",
77 valid_pidfd, tc->targetfd, tc->flags, tc->name);
78 TST_CHECKPOINT_WAKE(0);
79 exit(0);
80 }
81 TST_CHECKPOINT_WAIT(0);
82 SAFE_WAIT(NULL);
83 return;
84 } else if (tc->exp_errno == ESRCH) {
85 pid = SAFE_FORK();
86 if (!pid) {
87 TST_CHECKPOINT_WAIT(0);
88 exit(0);
89 }
90 pidfd = SAFE_PIDFD_OPEN(pid, 0);
91 TST_CHECKPOINT_WAKE(0);
92 SAFE_WAIT(NULL);
93 TST_EXP_FAIL2(pidfd_getfd(pidfd, tc->targetfd, tc->flags),
94 tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s",
95 pidfd, tc->targetfd, tc->flags, tc->name);
96 SAFE_CLOSE(pidfd);
97 } else {
98 TST_EXP_FAIL2(pidfd_getfd(*tc->pidfd, tc->targetfd, tc->flags),
99 tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s",
100 *tc->pidfd, tc->targetfd, tc->flags, tc->name);
101 }
102 }
103
104 static struct tst_test test = {
105 .tcnt = ARRAY_SIZE(tcases),
106 .test = run,
107 .setup = setup,
108 .cleanup = cleanup,
109 .needs_root = 1,
110 .forks_child = 1,
111 .needs_checkpoints = 1,
112 };
113