xref: /linux/tools/testing/selftests/net/af_unix/scm_pidfd.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1*ec80f488SAlexander Mikhalitsyn // SPDX-License-Identifier: GPL-2.0 OR MIT
2*ec80f488SAlexander Mikhalitsyn #define _GNU_SOURCE
3*ec80f488SAlexander Mikhalitsyn #include <error.h>
4*ec80f488SAlexander Mikhalitsyn #include <limits.h>
5*ec80f488SAlexander Mikhalitsyn #include <stddef.h>
6*ec80f488SAlexander Mikhalitsyn #include <stdio.h>
7*ec80f488SAlexander Mikhalitsyn #include <stdlib.h>
8*ec80f488SAlexander Mikhalitsyn #include <sys/socket.h>
9*ec80f488SAlexander Mikhalitsyn #include <linux/socket.h>
10*ec80f488SAlexander Mikhalitsyn #include <unistd.h>
11*ec80f488SAlexander Mikhalitsyn #include <string.h>
12*ec80f488SAlexander Mikhalitsyn #include <errno.h>
13*ec80f488SAlexander Mikhalitsyn #include <sys/un.h>
14*ec80f488SAlexander Mikhalitsyn #include <sys/signal.h>
15*ec80f488SAlexander Mikhalitsyn #include <sys/types.h>
16*ec80f488SAlexander Mikhalitsyn #include <sys/wait.h>
17*ec80f488SAlexander Mikhalitsyn 
18*ec80f488SAlexander Mikhalitsyn #include "../../kselftest_harness.h"
19*ec80f488SAlexander Mikhalitsyn 
20*ec80f488SAlexander Mikhalitsyn #define clean_errno() (errno == 0 ? "None" : strerror(errno))
21*ec80f488SAlexander Mikhalitsyn #define log_err(MSG, ...)                                                   \
22*ec80f488SAlexander Mikhalitsyn 	fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", __FILE__, __LINE__, \
23*ec80f488SAlexander Mikhalitsyn 		clean_errno(), ##__VA_ARGS__)
24*ec80f488SAlexander Mikhalitsyn 
25*ec80f488SAlexander Mikhalitsyn #ifndef SCM_PIDFD
26*ec80f488SAlexander Mikhalitsyn #define SCM_PIDFD 0x04
27*ec80f488SAlexander Mikhalitsyn #endif
28*ec80f488SAlexander Mikhalitsyn 
child_die()29*ec80f488SAlexander Mikhalitsyn static void child_die()
30*ec80f488SAlexander Mikhalitsyn {
31*ec80f488SAlexander Mikhalitsyn 	exit(1);
32*ec80f488SAlexander Mikhalitsyn }
33*ec80f488SAlexander Mikhalitsyn 
safe_int(const char * numstr,int * converted)34*ec80f488SAlexander Mikhalitsyn static int safe_int(const char *numstr, int *converted)
35*ec80f488SAlexander Mikhalitsyn {
36*ec80f488SAlexander Mikhalitsyn 	char *err = NULL;
37*ec80f488SAlexander Mikhalitsyn 	long sli;
38*ec80f488SAlexander Mikhalitsyn 
39*ec80f488SAlexander Mikhalitsyn 	errno = 0;
40*ec80f488SAlexander Mikhalitsyn 	sli = strtol(numstr, &err, 0);
41*ec80f488SAlexander Mikhalitsyn 	if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
42*ec80f488SAlexander Mikhalitsyn 		return -ERANGE;
43*ec80f488SAlexander Mikhalitsyn 
44*ec80f488SAlexander Mikhalitsyn 	if (errno != 0 && sli == 0)
45*ec80f488SAlexander Mikhalitsyn 		return -EINVAL;
46*ec80f488SAlexander Mikhalitsyn 
47*ec80f488SAlexander Mikhalitsyn 	if (err == numstr || *err != '\0')
48*ec80f488SAlexander Mikhalitsyn 		return -EINVAL;
49*ec80f488SAlexander Mikhalitsyn 
50*ec80f488SAlexander Mikhalitsyn 	if (sli > INT_MAX || sli < INT_MIN)
51*ec80f488SAlexander Mikhalitsyn 		return -ERANGE;
52*ec80f488SAlexander Mikhalitsyn 
53*ec80f488SAlexander Mikhalitsyn 	*converted = (int)sli;
54*ec80f488SAlexander Mikhalitsyn 	return 0;
55*ec80f488SAlexander Mikhalitsyn }
56*ec80f488SAlexander Mikhalitsyn 
char_left_gc(const char * buffer,size_t len)57*ec80f488SAlexander Mikhalitsyn static int char_left_gc(const char *buffer, size_t len)
58*ec80f488SAlexander Mikhalitsyn {
59*ec80f488SAlexander Mikhalitsyn 	size_t i;
60*ec80f488SAlexander Mikhalitsyn 
61*ec80f488SAlexander Mikhalitsyn 	for (i = 0; i < len; i++) {
62*ec80f488SAlexander Mikhalitsyn 		if (buffer[i] == ' ' || buffer[i] == '\t')
63*ec80f488SAlexander Mikhalitsyn 			continue;
64*ec80f488SAlexander Mikhalitsyn 
65*ec80f488SAlexander Mikhalitsyn 		return i;
66*ec80f488SAlexander Mikhalitsyn 	}
67*ec80f488SAlexander Mikhalitsyn 
68*ec80f488SAlexander Mikhalitsyn 	return 0;
69*ec80f488SAlexander Mikhalitsyn }
70*ec80f488SAlexander Mikhalitsyn 
char_right_gc(const char * buffer,size_t len)71*ec80f488SAlexander Mikhalitsyn static int char_right_gc(const char *buffer, size_t len)
72*ec80f488SAlexander Mikhalitsyn {
73*ec80f488SAlexander Mikhalitsyn 	int i;
74*ec80f488SAlexander Mikhalitsyn 
75*ec80f488SAlexander Mikhalitsyn 	for (i = len - 1; i >= 0; i--) {
76*ec80f488SAlexander Mikhalitsyn 		if (buffer[i] == ' ' || buffer[i] == '\t' ||
77*ec80f488SAlexander Mikhalitsyn 		    buffer[i] == '\n' || buffer[i] == '\0')
78*ec80f488SAlexander Mikhalitsyn 			continue;
79*ec80f488SAlexander Mikhalitsyn 
80*ec80f488SAlexander Mikhalitsyn 		return i + 1;
81*ec80f488SAlexander Mikhalitsyn 	}
82*ec80f488SAlexander Mikhalitsyn 
83*ec80f488SAlexander Mikhalitsyn 	return 0;
84*ec80f488SAlexander Mikhalitsyn }
85*ec80f488SAlexander Mikhalitsyn 
trim_whitespace_in_place(char * buffer)86*ec80f488SAlexander Mikhalitsyn static char *trim_whitespace_in_place(char *buffer)
87*ec80f488SAlexander Mikhalitsyn {
88*ec80f488SAlexander Mikhalitsyn 	buffer += char_left_gc(buffer, strlen(buffer));
89*ec80f488SAlexander Mikhalitsyn 	buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
90*ec80f488SAlexander Mikhalitsyn 	return buffer;
91*ec80f488SAlexander Mikhalitsyn }
92*ec80f488SAlexander Mikhalitsyn 
93*ec80f488SAlexander Mikhalitsyn /* borrowed (with all helpers) from pidfd/pidfd_open_test.c */
get_pid_from_fdinfo_file(int pidfd,const char * key,size_t keylen)94*ec80f488SAlexander Mikhalitsyn static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen)
95*ec80f488SAlexander Mikhalitsyn {
96*ec80f488SAlexander Mikhalitsyn 	int ret;
97*ec80f488SAlexander Mikhalitsyn 	char path[512];
98*ec80f488SAlexander Mikhalitsyn 	FILE *f;
99*ec80f488SAlexander Mikhalitsyn 	size_t n = 0;
100*ec80f488SAlexander Mikhalitsyn 	pid_t result = -1;
101*ec80f488SAlexander Mikhalitsyn 	char *line = NULL;
102*ec80f488SAlexander Mikhalitsyn 
103*ec80f488SAlexander Mikhalitsyn 	snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
104*ec80f488SAlexander Mikhalitsyn 
105*ec80f488SAlexander Mikhalitsyn 	f = fopen(path, "re");
106*ec80f488SAlexander Mikhalitsyn 	if (!f)
107*ec80f488SAlexander Mikhalitsyn 		return -1;
108*ec80f488SAlexander Mikhalitsyn 
109*ec80f488SAlexander Mikhalitsyn 	while (getline(&line, &n, f) != -1) {
110*ec80f488SAlexander Mikhalitsyn 		char *numstr;
111*ec80f488SAlexander Mikhalitsyn 
112*ec80f488SAlexander Mikhalitsyn 		if (strncmp(line, key, keylen))
113*ec80f488SAlexander Mikhalitsyn 			continue;
114*ec80f488SAlexander Mikhalitsyn 
115*ec80f488SAlexander Mikhalitsyn 		numstr = trim_whitespace_in_place(line + 4);
116*ec80f488SAlexander Mikhalitsyn 		ret = safe_int(numstr, &result);
117*ec80f488SAlexander Mikhalitsyn 		if (ret < 0)
118*ec80f488SAlexander Mikhalitsyn 			goto out;
119*ec80f488SAlexander Mikhalitsyn 
120*ec80f488SAlexander Mikhalitsyn 		break;
121*ec80f488SAlexander Mikhalitsyn 	}
122*ec80f488SAlexander Mikhalitsyn 
123*ec80f488SAlexander Mikhalitsyn out:
124*ec80f488SAlexander Mikhalitsyn 	free(line);
125*ec80f488SAlexander Mikhalitsyn 	fclose(f);
126*ec80f488SAlexander Mikhalitsyn 	return result;
127*ec80f488SAlexander Mikhalitsyn }
128*ec80f488SAlexander Mikhalitsyn 
cmsg_check(int fd)129*ec80f488SAlexander Mikhalitsyn static int cmsg_check(int fd)
130*ec80f488SAlexander Mikhalitsyn {
131*ec80f488SAlexander Mikhalitsyn 	struct msghdr msg = { 0 };
132*ec80f488SAlexander Mikhalitsyn 	struct cmsghdr *cmsg;
133*ec80f488SAlexander Mikhalitsyn 	struct iovec iov;
134*ec80f488SAlexander Mikhalitsyn 	struct ucred *ucred = NULL;
135*ec80f488SAlexander Mikhalitsyn 	int data = 0;
136*ec80f488SAlexander Mikhalitsyn 	char control[CMSG_SPACE(sizeof(struct ucred)) +
137*ec80f488SAlexander Mikhalitsyn 		     CMSG_SPACE(sizeof(int))] = { 0 };
138*ec80f488SAlexander Mikhalitsyn 	int *pidfd = NULL;
139*ec80f488SAlexander Mikhalitsyn 	pid_t parent_pid;
140*ec80f488SAlexander Mikhalitsyn 	int err;
141*ec80f488SAlexander Mikhalitsyn 
142*ec80f488SAlexander Mikhalitsyn 	iov.iov_base = &data;
143*ec80f488SAlexander Mikhalitsyn 	iov.iov_len = sizeof(data);
144*ec80f488SAlexander Mikhalitsyn 
145*ec80f488SAlexander Mikhalitsyn 	msg.msg_iov = &iov;
146*ec80f488SAlexander Mikhalitsyn 	msg.msg_iovlen = 1;
147*ec80f488SAlexander Mikhalitsyn 	msg.msg_control = control;
148*ec80f488SAlexander Mikhalitsyn 	msg.msg_controllen = sizeof(control);
149*ec80f488SAlexander Mikhalitsyn 
150*ec80f488SAlexander Mikhalitsyn 	err = recvmsg(fd, &msg, 0);
151*ec80f488SAlexander Mikhalitsyn 	if (err < 0) {
152*ec80f488SAlexander Mikhalitsyn 		log_err("recvmsg");
153*ec80f488SAlexander Mikhalitsyn 		return 1;
154*ec80f488SAlexander Mikhalitsyn 	}
155*ec80f488SAlexander Mikhalitsyn 
156*ec80f488SAlexander Mikhalitsyn 	if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
157*ec80f488SAlexander Mikhalitsyn 		log_err("recvmsg: truncated");
158*ec80f488SAlexander Mikhalitsyn 		return 1;
159*ec80f488SAlexander Mikhalitsyn 	}
160*ec80f488SAlexander Mikhalitsyn 
161*ec80f488SAlexander Mikhalitsyn 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
162*ec80f488SAlexander Mikhalitsyn 	     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
163*ec80f488SAlexander Mikhalitsyn 		if (cmsg->cmsg_level == SOL_SOCKET &&
164*ec80f488SAlexander Mikhalitsyn 		    cmsg->cmsg_type == SCM_PIDFD) {
165*ec80f488SAlexander Mikhalitsyn 			if (cmsg->cmsg_len < sizeof(*pidfd)) {
166*ec80f488SAlexander Mikhalitsyn 				log_err("CMSG parse: SCM_PIDFD wrong len");
167*ec80f488SAlexander Mikhalitsyn 				return 1;
168*ec80f488SAlexander Mikhalitsyn 			}
169*ec80f488SAlexander Mikhalitsyn 
170*ec80f488SAlexander Mikhalitsyn 			pidfd = (void *)CMSG_DATA(cmsg);
171*ec80f488SAlexander Mikhalitsyn 		}
172*ec80f488SAlexander Mikhalitsyn 
173*ec80f488SAlexander Mikhalitsyn 		if (cmsg->cmsg_level == SOL_SOCKET &&
174*ec80f488SAlexander Mikhalitsyn 		    cmsg->cmsg_type == SCM_CREDENTIALS) {
175*ec80f488SAlexander Mikhalitsyn 			if (cmsg->cmsg_len < sizeof(*ucred)) {
176*ec80f488SAlexander Mikhalitsyn 				log_err("CMSG parse: SCM_CREDENTIALS wrong len");
177*ec80f488SAlexander Mikhalitsyn 				return 1;
178*ec80f488SAlexander Mikhalitsyn 			}
179*ec80f488SAlexander Mikhalitsyn 
180*ec80f488SAlexander Mikhalitsyn 			ucred = (void *)CMSG_DATA(cmsg);
181*ec80f488SAlexander Mikhalitsyn 		}
182*ec80f488SAlexander Mikhalitsyn 	}
183*ec80f488SAlexander Mikhalitsyn 
184*ec80f488SAlexander Mikhalitsyn 	/* send(pfd, "x", sizeof(char), 0) */
185*ec80f488SAlexander Mikhalitsyn 	if (data != 'x') {
186*ec80f488SAlexander Mikhalitsyn 		log_err("recvmsg: data corruption");
187*ec80f488SAlexander Mikhalitsyn 		return 1;
188*ec80f488SAlexander Mikhalitsyn 	}
189*ec80f488SAlexander Mikhalitsyn 
190*ec80f488SAlexander Mikhalitsyn 	if (!pidfd) {
191*ec80f488SAlexander Mikhalitsyn 		log_err("CMSG parse: SCM_PIDFD not found");
192*ec80f488SAlexander Mikhalitsyn 		return 1;
193*ec80f488SAlexander Mikhalitsyn 	}
194*ec80f488SAlexander Mikhalitsyn 
195*ec80f488SAlexander Mikhalitsyn 	if (!ucred) {
196*ec80f488SAlexander Mikhalitsyn 		log_err("CMSG parse: SCM_CREDENTIALS not found");
197*ec80f488SAlexander Mikhalitsyn 		return 1;
198*ec80f488SAlexander Mikhalitsyn 	}
199*ec80f488SAlexander Mikhalitsyn 
200*ec80f488SAlexander Mikhalitsyn 	/* pidfd from SCM_PIDFD should point to the parent process PID */
201*ec80f488SAlexander Mikhalitsyn 	parent_pid =
202*ec80f488SAlexander Mikhalitsyn 		get_pid_from_fdinfo_file(*pidfd, "Pid:", sizeof("Pid:") - 1);
203*ec80f488SAlexander Mikhalitsyn 	if (parent_pid != getppid()) {
204*ec80f488SAlexander Mikhalitsyn 		log_err("wrong SCM_PIDFD %d != %d", parent_pid, getppid());
205*ec80f488SAlexander Mikhalitsyn 		return 1;
206*ec80f488SAlexander Mikhalitsyn 	}
207*ec80f488SAlexander Mikhalitsyn 
208*ec80f488SAlexander Mikhalitsyn 	return 0;
209*ec80f488SAlexander Mikhalitsyn }
210*ec80f488SAlexander Mikhalitsyn 
211*ec80f488SAlexander Mikhalitsyn struct sock_addr {
212*ec80f488SAlexander Mikhalitsyn 	char sock_name[32];
213*ec80f488SAlexander Mikhalitsyn 	struct sockaddr_un listen_addr;
214*ec80f488SAlexander Mikhalitsyn 	socklen_t addrlen;
215*ec80f488SAlexander Mikhalitsyn };
216*ec80f488SAlexander Mikhalitsyn 
FIXTURE(scm_pidfd)217*ec80f488SAlexander Mikhalitsyn FIXTURE(scm_pidfd)
218*ec80f488SAlexander Mikhalitsyn {
219*ec80f488SAlexander Mikhalitsyn 	int server;
220*ec80f488SAlexander Mikhalitsyn 	pid_t client_pid;
221*ec80f488SAlexander Mikhalitsyn 	int startup_pipe[2];
222*ec80f488SAlexander Mikhalitsyn 	struct sock_addr server_addr;
223*ec80f488SAlexander Mikhalitsyn 	struct sock_addr *client_addr;
224*ec80f488SAlexander Mikhalitsyn };
225*ec80f488SAlexander Mikhalitsyn 
FIXTURE_VARIANT(scm_pidfd)226*ec80f488SAlexander Mikhalitsyn FIXTURE_VARIANT(scm_pidfd)
227*ec80f488SAlexander Mikhalitsyn {
228*ec80f488SAlexander Mikhalitsyn 	int type;
229*ec80f488SAlexander Mikhalitsyn 	bool abstract;
230*ec80f488SAlexander Mikhalitsyn };
231*ec80f488SAlexander Mikhalitsyn 
FIXTURE_VARIANT_ADD(scm_pidfd,stream_pathname)232*ec80f488SAlexander Mikhalitsyn FIXTURE_VARIANT_ADD(scm_pidfd, stream_pathname)
233*ec80f488SAlexander Mikhalitsyn {
234*ec80f488SAlexander Mikhalitsyn 	.type = SOCK_STREAM,
235*ec80f488SAlexander Mikhalitsyn 	.abstract = 0,
236*ec80f488SAlexander Mikhalitsyn };
237*ec80f488SAlexander Mikhalitsyn 
FIXTURE_VARIANT_ADD(scm_pidfd,stream_abstract)238*ec80f488SAlexander Mikhalitsyn FIXTURE_VARIANT_ADD(scm_pidfd, stream_abstract)
239*ec80f488SAlexander Mikhalitsyn {
240*ec80f488SAlexander Mikhalitsyn 	.type = SOCK_STREAM,
241*ec80f488SAlexander Mikhalitsyn 	.abstract = 1,
242*ec80f488SAlexander Mikhalitsyn };
243*ec80f488SAlexander Mikhalitsyn 
FIXTURE_VARIANT_ADD(scm_pidfd,dgram_pathname)244*ec80f488SAlexander Mikhalitsyn FIXTURE_VARIANT_ADD(scm_pidfd, dgram_pathname)
245*ec80f488SAlexander Mikhalitsyn {
246*ec80f488SAlexander Mikhalitsyn 	.type = SOCK_DGRAM,
247*ec80f488SAlexander Mikhalitsyn 	.abstract = 0,
248*ec80f488SAlexander Mikhalitsyn };
249*ec80f488SAlexander Mikhalitsyn 
FIXTURE_VARIANT_ADD(scm_pidfd,dgram_abstract)250*ec80f488SAlexander Mikhalitsyn FIXTURE_VARIANT_ADD(scm_pidfd, dgram_abstract)
251*ec80f488SAlexander Mikhalitsyn {
252*ec80f488SAlexander Mikhalitsyn 	.type = SOCK_DGRAM,
253*ec80f488SAlexander Mikhalitsyn 	.abstract = 1,
254*ec80f488SAlexander Mikhalitsyn };
255*ec80f488SAlexander Mikhalitsyn 
FIXTURE_SETUP(scm_pidfd)256*ec80f488SAlexander Mikhalitsyn FIXTURE_SETUP(scm_pidfd)
257*ec80f488SAlexander Mikhalitsyn {
258*ec80f488SAlexander Mikhalitsyn 	self->client_addr = mmap(NULL, sizeof(*self->client_addr), PROT_READ | PROT_WRITE,
259*ec80f488SAlexander Mikhalitsyn 				 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
260*ec80f488SAlexander Mikhalitsyn 	ASSERT_NE(MAP_FAILED, self->client_addr);
261*ec80f488SAlexander Mikhalitsyn }
262*ec80f488SAlexander Mikhalitsyn 
FIXTURE_TEARDOWN(scm_pidfd)263*ec80f488SAlexander Mikhalitsyn FIXTURE_TEARDOWN(scm_pidfd)
264*ec80f488SAlexander Mikhalitsyn {
265*ec80f488SAlexander Mikhalitsyn 	close(self->server);
266*ec80f488SAlexander Mikhalitsyn 
267*ec80f488SAlexander Mikhalitsyn 	kill(self->client_pid, SIGKILL);
268*ec80f488SAlexander Mikhalitsyn 	waitpid(self->client_pid, NULL, 0);
269*ec80f488SAlexander Mikhalitsyn 
270*ec80f488SAlexander Mikhalitsyn 	if (!variant->abstract) {
271*ec80f488SAlexander Mikhalitsyn 		unlink(self->server_addr.sock_name);
272*ec80f488SAlexander Mikhalitsyn 		unlink(self->client_addr->sock_name);
273*ec80f488SAlexander Mikhalitsyn 	}
274*ec80f488SAlexander Mikhalitsyn }
275*ec80f488SAlexander Mikhalitsyn 
fill_sockaddr(struct sock_addr * addr,bool abstract)276*ec80f488SAlexander Mikhalitsyn static void fill_sockaddr(struct sock_addr *addr, bool abstract)
277*ec80f488SAlexander Mikhalitsyn {
278*ec80f488SAlexander Mikhalitsyn 	char *sun_path_buf = (char *)&addr->listen_addr.sun_path;
279*ec80f488SAlexander Mikhalitsyn 
280*ec80f488SAlexander Mikhalitsyn 	addr->listen_addr.sun_family = AF_UNIX;
281*ec80f488SAlexander Mikhalitsyn 	addr->addrlen = offsetof(struct sockaddr_un, sun_path);
282*ec80f488SAlexander Mikhalitsyn 	snprintf(addr->sock_name, sizeof(addr->sock_name), "scm_pidfd_%d", getpid());
283*ec80f488SAlexander Mikhalitsyn 	addr->addrlen += strlen(addr->sock_name);
284*ec80f488SAlexander Mikhalitsyn 	if (abstract) {
285*ec80f488SAlexander Mikhalitsyn 		*sun_path_buf = '\0';
286*ec80f488SAlexander Mikhalitsyn 		addr->addrlen++;
287*ec80f488SAlexander Mikhalitsyn 		sun_path_buf++;
288*ec80f488SAlexander Mikhalitsyn 	} else {
289*ec80f488SAlexander Mikhalitsyn 		unlink(addr->sock_name);
290*ec80f488SAlexander Mikhalitsyn 	}
291*ec80f488SAlexander Mikhalitsyn 	memcpy(sun_path_buf, addr->sock_name, strlen(addr->sock_name));
292*ec80f488SAlexander Mikhalitsyn }
293*ec80f488SAlexander Mikhalitsyn 
client(FIXTURE_DATA (scm_pidfd)* self,const FIXTURE_VARIANT (scm_pidfd)* variant)294*ec80f488SAlexander Mikhalitsyn static void client(FIXTURE_DATA(scm_pidfd) *self,
295*ec80f488SAlexander Mikhalitsyn 		   const FIXTURE_VARIANT(scm_pidfd) *variant)
296*ec80f488SAlexander Mikhalitsyn {
297*ec80f488SAlexander Mikhalitsyn 	int cfd;
298*ec80f488SAlexander Mikhalitsyn 	socklen_t len;
299*ec80f488SAlexander Mikhalitsyn 	struct ucred peer_cred;
300*ec80f488SAlexander Mikhalitsyn 	int peer_pidfd;
301*ec80f488SAlexander Mikhalitsyn 	pid_t peer_pid;
302*ec80f488SAlexander Mikhalitsyn 	int on = 0;
303*ec80f488SAlexander Mikhalitsyn 
304*ec80f488SAlexander Mikhalitsyn 	cfd = socket(AF_UNIX, variant->type, 0);
305*ec80f488SAlexander Mikhalitsyn 	if (cfd < 0) {
306*ec80f488SAlexander Mikhalitsyn 		log_err("socket");
307*ec80f488SAlexander Mikhalitsyn 		child_die();
308*ec80f488SAlexander Mikhalitsyn 	}
309*ec80f488SAlexander Mikhalitsyn 
310*ec80f488SAlexander Mikhalitsyn 	if (variant->type == SOCK_DGRAM) {
311*ec80f488SAlexander Mikhalitsyn 		fill_sockaddr(self->client_addr, variant->abstract);
312*ec80f488SAlexander Mikhalitsyn 
313*ec80f488SAlexander Mikhalitsyn 		if (bind(cfd, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen)) {
314*ec80f488SAlexander Mikhalitsyn 			log_err("bind");
315*ec80f488SAlexander Mikhalitsyn 			child_die();
316*ec80f488SAlexander Mikhalitsyn 		}
317*ec80f488SAlexander Mikhalitsyn 	}
318*ec80f488SAlexander Mikhalitsyn 
319*ec80f488SAlexander Mikhalitsyn 	if (connect(cfd, (struct sockaddr *)&self->server_addr.listen_addr,
320*ec80f488SAlexander Mikhalitsyn 		    self->server_addr.addrlen) != 0) {
321*ec80f488SAlexander Mikhalitsyn 		log_err("connect");
322*ec80f488SAlexander Mikhalitsyn 		child_die();
323*ec80f488SAlexander Mikhalitsyn 	}
324*ec80f488SAlexander Mikhalitsyn 
325*ec80f488SAlexander Mikhalitsyn 	on = 1;
326*ec80f488SAlexander Mikhalitsyn 	if (setsockopt(cfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
327*ec80f488SAlexander Mikhalitsyn 		log_err("Failed to set SO_PASSCRED");
328*ec80f488SAlexander Mikhalitsyn 		child_die();
329*ec80f488SAlexander Mikhalitsyn 	}
330*ec80f488SAlexander Mikhalitsyn 
331*ec80f488SAlexander Mikhalitsyn 	if (setsockopt(cfd, SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) {
332*ec80f488SAlexander Mikhalitsyn 		log_err("Failed to set SO_PASSPIDFD");
333*ec80f488SAlexander Mikhalitsyn 		child_die();
334*ec80f488SAlexander Mikhalitsyn 	}
335*ec80f488SAlexander Mikhalitsyn 
336*ec80f488SAlexander Mikhalitsyn 	close(self->startup_pipe[1]);
337*ec80f488SAlexander Mikhalitsyn 
338*ec80f488SAlexander Mikhalitsyn 	if (cmsg_check(cfd)) {
339*ec80f488SAlexander Mikhalitsyn 		log_err("cmsg_check failed");
340*ec80f488SAlexander Mikhalitsyn 		child_die();
341*ec80f488SAlexander Mikhalitsyn 	}
342*ec80f488SAlexander Mikhalitsyn 
343*ec80f488SAlexander Mikhalitsyn 	/* skip further for SOCK_DGRAM as it's not applicable */
344*ec80f488SAlexander Mikhalitsyn 	if (variant->type == SOCK_DGRAM)
345*ec80f488SAlexander Mikhalitsyn 		return;
346*ec80f488SAlexander Mikhalitsyn 
347*ec80f488SAlexander Mikhalitsyn 	len = sizeof(peer_cred);
348*ec80f488SAlexander Mikhalitsyn 	if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_cred, &len)) {
349*ec80f488SAlexander Mikhalitsyn 		log_err("Failed to get SO_PEERCRED");
350*ec80f488SAlexander Mikhalitsyn 		child_die();
351*ec80f488SAlexander Mikhalitsyn 	}
352*ec80f488SAlexander Mikhalitsyn 
353*ec80f488SAlexander Mikhalitsyn 	len = sizeof(peer_pidfd);
354*ec80f488SAlexander Mikhalitsyn 	if (getsockopt(cfd, SOL_SOCKET, SO_PEERPIDFD, &peer_pidfd, &len)) {
355*ec80f488SAlexander Mikhalitsyn 		log_err("Failed to get SO_PEERPIDFD");
356*ec80f488SAlexander Mikhalitsyn 		child_die();
357*ec80f488SAlexander Mikhalitsyn 	}
358*ec80f488SAlexander Mikhalitsyn 
359*ec80f488SAlexander Mikhalitsyn 	/* pid from SO_PEERCRED should point to the parent process PID */
360*ec80f488SAlexander Mikhalitsyn 	if (peer_cred.pid != getppid()) {
361*ec80f488SAlexander Mikhalitsyn 		log_err("peer_cred.pid != getppid(): %d != %d", peer_cred.pid, getppid());
362*ec80f488SAlexander Mikhalitsyn 		child_die();
363*ec80f488SAlexander Mikhalitsyn 	}
364*ec80f488SAlexander Mikhalitsyn 
365*ec80f488SAlexander Mikhalitsyn 	peer_pid = get_pid_from_fdinfo_file(peer_pidfd,
366*ec80f488SAlexander Mikhalitsyn 					    "Pid:", sizeof("Pid:") - 1);
367*ec80f488SAlexander Mikhalitsyn 	if (peer_pid != peer_cred.pid) {
368*ec80f488SAlexander Mikhalitsyn 		log_err("peer_pid != peer_cred.pid: %d != %d", peer_pid, peer_cred.pid);
369*ec80f488SAlexander Mikhalitsyn 		child_die();
370*ec80f488SAlexander Mikhalitsyn 	}
371*ec80f488SAlexander Mikhalitsyn }
372*ec80f488SAlexander Mikhalitsyn 
TEST_F(scm_pidfd,test)373*ec80f488SAlexander Mikhalitsyn TEST_F(scm_pidfd, test)
374*ec80f488SAlexander Mikhalitsyn {
375*ec80f488SAlexander Mikhalitsyn 	int err;
376*ec80f488SAlexander Mikhalitsyn 	int pfd;
377*ec80f488SAlexander Mikhalitsyn 	int child_status = 0;
378*ec80f488SAlexander Mikhalitsyn 
379*ec80f488SAlexander Mikhalitsyn 	self->server = socket(AF_UNIX, variant->type, 0);
380*ec80f488SAlexander Mikhalitsyn 	ASSERT_NE(-1, self->server);
381*ec80f488SAlexander Mikhalitsyn 
382*ec80f488SAlexander Mikhalitsyn 	fill_sockaddr(&self->server_addr, variant->abstract);
383*ec80f488SAlexander Mikhalitsyn 
384*ec80f488SAlexander Mikhalitsyn 	err = bind(self->server, (struct sockaddr *)&self->server_addr.listen_addr, self->server_addr.addrlen);
385*ec80f488SAlexander Mikhalitsyn 	ASSERT_EQ(0, err);
386*ec80f488SAlexander Mikhalitsyn 
387*ec80f488SAlexander Mikhalitsyn 	if (variant->type == SOCK_STREAM) {
388*ec80f488SAlexander Mikhalitsyn 		err = listen(self->server, 1);
389*ec80f488SAlexander Mikhalitsyn 		ASSERT_EQ(0, err);
390*ec80f488SAlexander Mikhalitsyn 	}
391*ec80f488SAlexander Mikhalitsyn 
392*ec80f488SAlexander Mikhalitsyn 	err = pipe(self->startup_pipe);
393*ec80f488SAlexander Mikhalitsyn 	ASSERT_NE(-1, err);
394*ec80f488SAlexander Mikhalitsyn 
395*ec80f488SAlexander Mikhalitsyn 	self->client_pid = fork();
396*ec80f488SAlexander Mikhalitsyn 	ASSERT_NE(-1, self->client_pid);
397*ec80f488SAlexander Mikhalitsyn 	if (self->client_pid == 0) {
398*ec80f488SAlexander Mikhalitsyn 		close(self->server);
399*ec80f488SAlexander Mikhalitsyn 		close(self->startup_pipe[0]);
400*ec80f488SAlexander Mikhalitsyn 		client(self, variant);
401*ec80f488SAlexander Mikhalitsyn 		exit(0);
402*ec80f488SAlexander Mikhalitsyn 	}
403*ec80f488SAlexander Mikhalitsyn 	close(self->startup_pipe[1]);
404*ec80f488SAlexander Mikhalitsyn 
405*ec80f488SAlexander Mikhalitsyn 	if (variant->type == SOCK_STREAM) {
406*ec80f488SAlexander Mikhalitsyn 		pfd = accept(self->server, NULL, NULL);
407*ec80f488SAlexander Mikhalitsyn 		ASSERT_NE(-1, pfd);
408*ec80f488SAlexander Mikhalitsyn 	} else {
409*ec80f488SAlexander Mikhalitsyn 		pfd = self->server;
410*ec80f488SAlexander Mikhalitsyn 	}
411*ec80f488SAlexander Mikhalitsyn 
412*ec80f488SAlexander Mikhalitsyn 	/* wait until the child arrives at checkpoint */
413*ec80f488SAlexander Mikhalitsyn 	read(self->startup_pipe[0], &err, sizeof(int));
414*ec80f488SAlexander Mikhalitsyn 	close(self->startup_pipe[0]);
415*ec80f488SAlexander Mikhalitsyn 
416*ec80f488SAlexander Mikhalitsyn 	if (variant->type == SOCK_DGRAM) {
417*ec80f488SAlexander Mikhalitsyn 		err = sendto(pfd, "x", sizeof(char), 0, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen);
418*ec80f488SAlexander Mikhalitsyn 		ASSERT_NE(-1, err);
419*ec80f488SAlexander Mikhalitsyn 	} else {
420*ec80f488SAlexander Mikhalitsyn 		err = send(pfd, "x", sizeof(char), 0);
421*ec80f488SAlexander Mikhalitsyn 		ASSERT_NE(-1, err);
422*ec80f488SAlexander Mikhalitsyn 	}
423*ec80f488SAlexander Mikhalitsyn 
424*ec80f488SAlexander Mikhalitsyn 	close(pfd);
425*ec80f488SAlexander Mikhalitsyn 	waitpid(self->client_pid, &child_status, 0);
426*ec80f488SAlexander Mikhalitsyn 	ASSERT_EQ(0, WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1);
427*ec80f488SAlexander Mikhalitsyn }
428*ec80f488SAlexander Mikhalitsyn 
429*ec80f488SAlexander Mikhalitsyn TEST_HARNESS_MAIN
430