Loading...
1// SPDX-License-Identifier: GPL-2.0
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <fcntl.h>
6#include <inttypes.h>
7#include <limits.h>
8#include <linux/types.h>
9#include <sched.h>
10#include <signal.h>
11#include <stdbool.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <syscall.h>
16#include <sys/ioctl.h>
17#include <sys/mount.h>
18#include <sys/prctl.h>
19#include <sys/wait.h>
20#include <unistd.h>
21
22#include "pidfd.h"
23#include "../kselftest.h"
24
25#ifndef PIDFS_IOCTL_MAGIC
26#define PIDFS_IOCTL_MAGIC 0xFF
27#endif
28
29#ifndef PIDFD_GET_INFO
30#define PIDFD_GET_INFO _IOWR(PIDFS_IOCTL_MAGIC, 11, struct pidfd_info)
31#define PIDFD_INFO_CGROUPID (1UL << 0)
32
33struct pidfd_info {
34 __u64 request_mask;
35 __u64 cgroupid;
36 __u32 pid;
37 __u32 tgid;
38 __u32 ppid;
39 __u32 ruid;
40 __u32 rgid;
41 __u32 euid;
42 __u32 egid;
43 __u32 suid;
44 __u32 sgid;
45 __u32 fsuid;
46 __u32 fsgid;
47 __u32 spare0[1];
48};
49#endif
50
51static int safe_int(const char *numstr, int *converted)
52{
53 char *err = NULL;
54 long sli;
55
56 errno = 0;
57 sli = strtol(numstr, &err, 0);
58 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
59 return -ERANGE;
60
61 if (errno != 0 && sli == 0)
62 return -EINVAL;
63
64 if (err == numstr || *err != '\0')
65 return -EINVAL;
66
67 if (sli > INT_MAX || sli < INT_MIN)
68 return -ERANGE;
69
70 *converted = (int)sli;
71 return 0;
72}
73
74static int char_left_gc(const char *buffer, size_t len)
75{
76 size_t i;
77
78 for (i = 0; i < len; i++) {
79 if (buffer[i] == ' ' ||
80 buffer[i] == '\t')
81 continue;
82
83 return i;
84 }
85
86 return 0;
87}
88
89static int char_right_gc(const char *buffer, size_t len)
90{
91 int i;
92
93 for (i = len - 1; i >= 0; i--) {
94 if (buffer[i] == ' ' ||
95 buffer[i] == '\t' ||
96 buffer[i] == '\n' ||
97 buffer[i] == '\0')
98 continue;
99
100 return i + 1;
101 }
102
103 return 0;
104}
105
106static char *trim_whitespace_in_place(char *buffer)
107{
108 buffer += char_left_gc(buffer, strlen(buffer));
109 buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
110 return buffer;
111}
112
113static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen)
114{
115 int ret;
116 char path[512];
117 FILE *f;
118 size_t n = 0;
119 pid_t result = -1;
120 char *line = NULL;
121
122 snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
123
124 f = fopen(path, "re");
125 if (!f)
126 return -1;
127
128 while (getline(&line, &n, f) != -1) {
129 char *numstr;
130
131 if (strncmp(line, key, keylen))
132 continue;
133
134 numstr = trim_whitespace_in_place(line + 4);
135 ret = safe_int(numstr, &result);
136 if (ret < 0)
137 goto out;
138
139 break;
140 }
141
142out:
143 free(line);
144 fclose(f);
145 return result;
146}
147
148int main(int argc, char **argv)
149{
150 struct pidfd_info info = {
151 .request_mask = PIDFD_INFO_CGROUPID,
152 };
153 int pidfd = -1, ret = 1;
154 pid_t pid;
155
156 ksft_set_plan(4);
157
158 pidfd = sys_pidfd_open(-1, 0);
159 if (pidfd >= 0) {
160 ksft_print_msg(
161 "%s - succeeded to open pidfd for invalid pid -1\n",
162 strerror(errno));
163 goto on_error;
164 }
165 ksft_test_result_pass("do not allow invalid pid test: passed\n");
166
167 pidfd = sys_pidfd_open(getpid(), 1);
168 if (pidfd >= 0) {
169 ksft_print_msg(
170 "%s - succeeded to open pidfd with invalid flag value specified\n",
171 strerror(errno));
172 goto on_error;
173 }
174 ksft_test_result_pass("do not allow invalid flag test: passed\n");
175
176 pidfd = sys_pidfd_open(getpid(), 0);
177 if (pidfd < 0) {
178 ksft_print_msg("%s - failed to open pidfd\n", strerror(errno));
179 goto on_error;
180 }
181 ksft_test_result_pass("open a new pidfd test: passed\n");
182
183 pid = get_pid_from_fdinfo_file(pidfd, "Pid:", sizeof("Pid:") - 1);
184 ksft_print_msg("pidfd %d refers to process with pid %d\n", pidfd, pid);
185
186 if (ioctl(pidfd, PIDFD_GET_INFO, &info) < 0) {
187 ksft_print_msg("%s - failed to get info from pidfd\n", strerror(errno));
188 goto on_error;
189 }
190 if (info.pid != pid) {
191 ksft_print_msg("pid from fdinfo file %d does not match pid from ioctl %d\n",
192 pid, info.pid);
193 goto on_error;
194 }
195 if (info.ppid != getppid()) {
196 ksft_print_msg("ppid %d does not match ppid from ioctl %d\n",
197 pid, info.pid);
198 goto on_error;
199 }
200 if (info.ruid != getuid()) {
201 ksft_print_msg("uid %d does not match uid from ioctl %d\n",
202 getuid(), info.ruid);
203 goto on_error;
204 }
205 if (info.rgid != getgid()) {
206 ksft_print_msg("gid %d does not match gid from ioctl %d\n",
207 getgid(), info.rgid);
208 goto on_error;
209 }
210 if (info.euid != geteuid()) {
211 ksft_print_msg("euid %d does not match euid from ioctl %d\n",
212 geteuid(), info.euid);
213 goto on_error;
214 }
215 if (info.egid != getegid()) {
216 ksft_print_msg("egid %d does not match egid from ioctl %d\n",
217 getegid(), info.egid);
218 goto on_error;
219 }
220 if (info.suid != geteuid()) {
221 ksft_print_msg("suid %d does not match suid from ioctl %d\n",
222 geteuid(), info.suid);
223 goto on_error;
224 }
225 if (info.sgid != getegid()) {
226 ksft_print_msg("sgid %d does not match sgid from ioctl %d\n",
227 getegid(), info.sgid);
228 goto on_error;
229 }
230 if ((info.request_mask & PIDFD_INFO_CGROUPID) && info.cgroupid == 0) {
231 ksft_print_msg("cgroupid should not be 0 when PIDFD_INFO_CGROUPID is set\n");
232 goto on_error;
233 }
234 ksft_test_result_pass("get info from pidfd test: passed\n");
235
236 ret = 0;
237
238on_error:
239 if (pidfd >= 0)
240 close(pidfd);
241
242 if (ret)
243 ksft_exit_fail();
244 ksft_exit_pass();
245}
1// SPDX-License-Identifier: GPL-2.0
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <fcntl.h>
6#include <inttypes.h>
7#include <limits.h>
8#include <linux/types.h>
9#include <linux/wait.h>
10#include <sched.h>
11#include <signal.h>
12#include <stdbool.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <syscall.h>
17#include <sys/mount.h>
18#include <sys/prctl.h>
19#include <sys/wait.h>
20#include <unistd.h>
21
22#include "pidfd.h"
23#include "../kselftest.h"
24
25static int safe_int(const char *numstr, int *converted)
26{
27 char *err = NULL;
28 long sli;
29
30 errno = 0;
31 sli = strtol(numstr, &err, 0);
32 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
33 return -ERANGE;
34
35 if (errno != 0 && sli == 0)
36 return -EINVAL;
37
38 if (err == numstr || *err != '\0')
39 return -EINVAL;
40
41 if (sli > INT_MAX || sli < INT_MIN)
42 return -ERANGE;
43
44 *converted = (int)sli;
45 return 0;
46}
47
48static int char_left_gc(const char *buffer, size_t len)
49{
50 size_t i;
51
52 for (i = 0; i < len; i++) {
53 if (buffer[i] == ' ' ||
54 buffer[i] == '\t')
55 continue;
56
57 return i;
58 }
59
60 return 0;
61}
62
63static int char_right_gc(const char *buffer, size_t len)
64{
65 int i;
66
67 for (i = len - 1; i >= 0; i--) {
68 if (buffer[i] == ' ' ||
69 buffer[i] == '\t' ||
70 buffer[i] == '\n' ||
71 buffer[i] == '\0')
72 continue;
73
74 return i + 1;
75 }
76
77 return 0;
78}
79
80static char *trim_whitespace_in_place(char *buffer)
81{
82 buffer += char_left_gc(buffer, strlen(buffer));
83 buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
84 return buffer;
85}
86
87static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen)
88{
89 int ret;
90 char path[512];
91 FILE *f;
92 size_t n = 0;
93 pid_t result = -1;
94 char *line = NULL;
95
96 snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
97
98 f = fopen(path, "re");
99 if (!f)
100 return -1;
101
102 while (getline(&line, &n, f) != -1) {
103 char *numstr;
104
105 if (strncmp(line, key, keylen))
106 continue;
107
108 numstr = trim_whitespace_in_place(line + 4);
109 ret = safe_int(numstr, &result);
110 if (ret < 0)
111 goto out;
112
113 break;
114 }
115
116out:
117 free(line);
118 fclose(f);
119 return result;
120}
121
122int main(int argc, char **argv)
123{
124 int pidfd = -1, ret = 1;
125 pid_t pid;
126
127 ksft_set_plan(3);
128
129 pidfd = sys_pidfd_open(-1, 0);
130 if (pidfd >= 0) {
131 ksft_print_msg(
132 "%s - succeeded to open pidfd for invalid pid -1\n",
133 strerror(errno));
134 goto on_error;
135 }
136 ksft_test_result_pass("do not allow invalid pid test: passed\n");
137
138 pidfd = sys_pidfd_open(getpid(), 1);
139 if (pidfd >= 0) {
140 ksft_print_msg(
141 "%s - succeeded to open pidfd with invalid flag value specified\n",
142 strerror(errno));
143 goto on_error;
144 }
145 ksft_test_result_pass("do not allow invalid flag test: passed\n");
146
147 pidfd = sys_pidfd_open(getpid(), 0);
148 if (pidfd < 0) {
149 ksft_print_msg("%s - failed to open pidfd\n", strerror(errno));
150 goto on_error;
151 }
152 ksft_test_result_pass("open a new pidfd test: passed\n");
153
154 pid = get_pid_from_fdinfo_file(pidfd, "Pid:", sizeof("Pid:") - 1);
155 ksft_print_msg("pidfd %d refers to process with pid %d\n", pidfd, pid);
156
157 ret = 0;
158
159on_error:
160 if (pidfd >= 0)
161 close(pidfd);
162
163 return !ret ? ksft_exit_pass() : ksft_exit_fail();
164}