xref: /linux/tools/testing/selftests/pidfd/pidfd_open_test.c (revision 8795a739e5c72abeec51caf36b6df2b37e5720c5)
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 
25 static 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 
48 static 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 
63 static 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 
80 static 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 
87 static 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 
116 out:
117 	free(line);
118 	fclose(f);
119 	return result;
120 }
121 
122 int 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 
159 on_error:
160 	if (pidfd >= 0)
161 		close(pidfd);
162 
163 	return !ret ? ksft_exit_pass() : ksft_exit_fail();
164 }
165