xref: /linux/tools/testing/selftests/net/af_unix/scm_rights.c (revision 001821b0e79716c4e17c71d8e053a23599a7a508)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright Amazon.com Inc. or its affiliates. */
3 #define _GNU_SOURCE
4 #include <sched.h>
5 
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <sys/un.h>
12 
13 #include "../../kselftest_harness.h"
14 
15 FIXTURE(scm_rights)
16 {
17 	int fd[16];
18 };
19 
20 FIXTURE_VARIANT(scm_rights)
21 {
22 	char name[16];
23 	int type;
24 	int flags;
25 	bool test_listener;
26 };
27 
28 FIXTURE_VARIANT_ADD(scm_rights, dgram)
29 {
30 	.name = "UNIX ",
31 	.type = SOCK_DGRAM,
32 	.flags = 0,
33 	.test_listener = false,
34 };
35 
36 FIXTURE_VARIANT_ADD(scm_rights, stream)
37 {
38 	.name = "UNIX-STREAM ",
39 	.type = SOCK_STREAM,
40 	.flags = 0,
41 	.test_listener = false,
42 };
43 
44 FIXTURE_VARIANT_ADD(scm_rights, stream_oob)
45 {
46 	.name = "UNIX-STREAM ",
47 	.type = SOCK_STREAM,
48 	.flags = MSG_OOB,
49 	.test_listener = false,
50 };
51 
52 FIXTURE_VARIANT_ADD(scm_rights, stream_listener)
53 {
54 	.name = "UNIX-STREAM ",
55 	.type = SOCK_STREAM,
56 	.flags = 0,
57 	.test_listener = true,
58 };
59 
60 FIXTURE_VARIANT_ADD(scm_rights, stream_listener_oob)
61 {
62 	.name = "UNIX-STREAM ",
63 	.type = SOCK_STREAM,
64 	.flags = MSG_OOB,
65 	.test_listener = true,
66 };
67 
68 static int count_sockets(struct __test_metadata *_metadata,
69 			 const FIXTURE_VARIANT(scm_rights) *variant)
70 {
71 	int sockets = -1, len, ret;
72 	char *line = NULL;
73 	size_t unused;
74 	FILE *f;
75 
76 	f = fopen("/proc/net/protocols", "r");
77 	ASSERT_NE(NULL, f);
78 
79 	len = strlen(variant->name);
80 
81 	while (getline(&line, &unused, f) != -1) {
82 		int unused2;
83 
84 		if (strncmp(line, variant->name, len))
85 			continue;
86 
87 		ret = sscanf(line + len, "%d %d", &unused2, &sockets);
88 		ASSERT_EQ(2, ret);
89 
90 		break;
91 	}
92 
93 	free(line);
94 
95 	ret = fclose(f);
96 	ASSERT_EQ(0, ret);
97 
98 	return sockets;
99 }
100 
101 FIXTURE_SETUP(scm_rights)
102 {
103 	int ret;
104 
105 	ret = unshare(CLONE_NEWNET);
106 	ASSERT_EQ(0, ret);
107 
108 	ret = count_sockets(_metadata, variant);
109 	ASSERT_EQ(0, ret);
110 }
111 
112 FIXTURE_TEARDOWN(scm_rights)
113 {
114 	int ret;
115 
116 	sleep(1);
117 
118 	ret = count_sockets(_metadata, variant);
119 	ASSERT_EQ(0, ret);
120 }
121 
122 static void create_listeners(struct __test_metadata *_metadata,
123 			     FIXTURE_DATA(scm_rights) *self,
124 			     int n)
125 {
126 	struct sockaddr_un addr = {
127 		.sun_family = AF_UNIX,
128 	};
129 	socklen_t addrlen;
130 	int i, ret;
131 
132 	for (i = 0; i < n * 2; i += 2) {
133 		self->fd[i] = socket(AF_UNIX, SOCK_STREAM, 0);
134 		ASSERT_LE(0, self->fd[i]);
135 
136 		addrlen = sizeof(addr.sun_family);
137 		ret = bind(self->fd[i], (struct sockaddr *)&addr, addrlen);
138 		ASSERT_EQ(0, ret);
139 
140 		ret = listen(self->fd[i], -1);
141 		ASSERT_EQ(0, ret);
142 
143 		addrlen = sizeof(addr);
144 		ret = getsockname(self->fd[i], (struct sockaddr *)&addr, &addrlen);
145 		ASSERT_EQ(0, ret);
146 
147 		self->fd[i + 1] = socket(AF_UNIX, SOCK_STREAM, 0);
148 		ASSERT_LE(0, self->fd[i + 1]);
149 
150 		ret = connect(self->fd[i + 1], (struct sockaddr *)&addr, addrlen);
151 		ASSERT_EQ(0, ret);
152 	}
153 }
154 
155 static void create_socketpairs(struct __test_metadata *_metadata,
156 			       FIXTURE_DATA(scm_rights) *self,
157 			       const FIXTURE_VARIANT(scm_rights) *variant,
158 			       int n)
159 {
160 	int i, ret;
161 
162 	ASSERT_GE(sizeof(self->fd) / sizeof(int), n);
163 
164 	for (i = 0; i < n * 2; i += 2) {
165 		ret = socketpair(AF_UNIX, variant->type, 0, self->fd + i);
166 		ASSERT_EQ(0, ret);
167 	}
168 }
169 
170 static void __create_sockets(struct __test_metadata *_metadata,
171 			     FIXTURE_DATA(scm_rights) *self,
172 			     const FIXTURE_VARIANT(scm_rights) *variant,
173 			     int n)
174 {
175 	if (variant->test_listener)
176 		create_listeners(_metadata, self, n);
177 	else
178 		create_socketpairs(_metadata, self, variant, n);
179 }
180 
181 static void __close_sockets(struct __test_metadata *_metadata,
182 			    FIXTURE_DATA(scm_rights) *self,
183 			    int n)
184 {
185 	int i, ret;
186 
187 	ASSERT_GE(sizeof(self->fd) / sizeof(int), n);
188 
189 	for (i = 0; i < n * 2; i++) {
190 		ret = close(self->fd[i]);
191 		ASSERT_EQ(0, ret);
192 	}
193 }
194 
195 void __send_fd(struct __test_metadata *_metadata,
196 	       const FIXTURE_DATA(scm_rights) *self,
197 	       const FIXTURE_VARIANT(scm_rights) *variant,
198 	       int inflight, int receiver)
199 {
200 #define MSG "x"
201 #define MSGLEN 1
202 	struct {
203 		struct cmsghdr cmsghdr;
204 		int fd[2];
205 	} cmsg = {
206 		.cmsghdr = {
207 			.cmsg_len = CMSG_LEN(sizeof(cmsg.fd)),
208 			.cmsg_level = SOL_SOCKET,
209 			.cmsg_type = SCM_RIGHTS,
210 		},
211 		.fd = {
212 			self->fd[inflight * 2],
213 			self->fd[inflight * 2],
214 		},
215 	};
216 	struct iovec iov = {
217 		.iov_base = MSG,
218 		.iov_len = MSGLEN,
219 	};
220 	struct msghdr msg = {
221 		.msg_name = NULL,
222 		.msg_namelen = 0,
223 		.msg_iov = &iov,
224 		.msg_iovlen = 1,
225 		.msg_control = &cmsg,
226 		.msg_controllen = CMSG_SPACE(sizeof(cmsg.fd)),
227 	};
228 	int ret;
229 
230 	ret = sendmsg(self->fd[receiver * 2 + 1], &msg, variant->flags);
231 	ASSERT_EQ(MSGLEN, ret);
232 }
233 
234 #define create_sockets(n)					\
235 	__create_sockets(_metadata, self, variant, n)
236 #define close_sockets(n)					\
237 	__close_sockets(_metadata, self, n)
238 #define send_fd(inflight, receiver)				\
239 	__send_fd(_metadata, self, variant, inflight, receiver)
240 
241 TEST_F(scm_rights, self_ref)
242 {
243 	create_sockets(2);
244 
245 	send_fd(0, 0);
246 
247 	send_fd(1, 1);
248 
249 	close_sockets(2);
250 }
251 
252 TEST_F(scm_rights, triangle)
253 {
254 	create_sockets(6);
255 
256 	send_fd(0, 1);
257 	send_fd(1, 2);
258 	send_fd(2, 0);
259 
260 	send_fd(3, 4);
261 	send_fd(4, 5);
262 	send_fd(5, 3);
263 
264 	close_sockets(6);
265 }
266 
267 TEST_F(scm_rights, cross_edge)
268 {
269 	create_sockets(8);
270 
271 	send_fd(0, 1);
272 	send_fd(1, 2);
273 	send_fd(2, 0);
274 	send_fd(1, 3);
275 	send_fd(3, 2);
276 
277 	send_fd(4, 5);
278 	send_fd(5, 6);
279 	send_fd(6, 4);
280 	send_fd(5, 7);
281 	send_fd(7, 6);
282 
283 	close_sockets(8);
284 }
285 
286 TEST_HARNESS_MAIN
287