1
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 inline int sys_pidfd_open(pid_t pid, unsigned int flags)
26{
27 return syscall(__NR_pidfd_open, pid, flags);
28}
29
30static int safe_int(const char *numstr, int *converted)
31{
32 char *err = NULL;
33 long sli;
34
35 errno = 0;
36 sli = strtol(numstr, &err, 0);
37 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
38 return -ERANGE;
39
40 if (errno != 0 && sli == 0)
41 return -EINVAL;
42
43 if (err == numstr || *err != '\0')
44 return -EINVAL;
45
46 if (sli > INT_MAX || sli < INT_MIN)
47 return -ERANGE;
48
49 *converted = (int)sli;
50 return 0;
51}
52
53static int char_left_gc(const char *buffer, size_t len)
54{
55 size_t i;
56
57 for (i = 0; i < len; i++) {
58 if (buffer[i] == ' ' ||
59 buffer[i] == '\t')
60 continue;
61
62 return i;
63 }
64
65 return 0;
66}
67
68static int char_right_gc(const char *buffer, size_t len)
69{
70 int i;
71
72 for (i = len - 1; i >= 0; i--) {
73 if (buffer[i] == ' ' ||
74 buffer[i] == '\t' ||
75 buffer[i] == '\n' ||
76 buffer[i] == '\0')
77 continue;
78
79 return i + 1;
80 }
81
82 return 0;
83}
84
85static char *trim_whitespace_in_place(char *buffer)
86{
87 buffer += char_left_gc(buffer, strlen(buffer));
88 buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
89 return buffer;
90}
91
92static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen)
93{
94 int ret;
95 char path[512];
96 FILE *f;
97 size_t n = 0;
98 pid_t result = -1;
99 char *line = NULL;
100
101 snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
102
103 f = fopen(path, "re");
104 if (!f)
105 return -1;
106
107 while (getline(&line, &n, f) != -1) {
108 char *numstr;
109
110 if (strncmp(line, key, keylen))
111 continue;
112
113 numstr = trim_whitespace_in_place(line + 4);
114 ret = safe_int(numstr, &result);
115 if (ret < 0)
116 goto out;
117
118 break;
119 }
120
121out:
122 free(line);
123 fclose(f);
124 return result;
125}
126
127int main(int argc, char **argv)
128{
129 int pidfd = -1, ret = 1;
130 pid_t pid;
131
132 ksft_set_plan(3);
133
134 pidfd = sys_pidfd_open(-1, 0);
135 if (pidfd >= 0) {
136 ksft_print_msg(
137 "%s - succeeded to open pidfd for invalid pid -1\n",
138 strerror(errno));
139 goto on_error;
140 }
141 ksft_test_result_pass("do not allow invalid pid test: passed\n");
142
143 pidfd = sys_pidfd_open(getpid(), 1);
144 if (pidfd >= 0) {
145 ksft_print_msg(
146 "%s - succeeded to open pidfd with invalid flag value specified\n",
147 strerror(errno));
148 goto on_error;
149 }
150 ksft_test_result_pass("do not allow invalid flag test: passed\n");
151
152 pidfd = sys_pidfd_open(getpid(), 0);
153 if (pidfd < 0) {
154 ksft_print_msg("%s - failed to open pidfd\n", strerror(errno));
155 goto on_error;
156 }
157 ksft_test_result_pass("open a new pidfd test: passed\n");
158
159 pid = get_pid_from_fdinfo_file(pidfd, "Pid:", sizeof("Pid:") - 1);
160 ksft_print_msg("pidfd %d refers to process with pid %d\n", pidfd, pid);
161
162 ret = 0;
163
164on_error:
165 if (pidfd >= 0)
166 close(pidfd);
167
168 return !ret ? ksft_exit_pass() : ksft_exit_fail();
169}
170