Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 15FIXTURE(scm_rights)
 16{
 17	int fd[32];
 18};
 19
 20FIXTURE_VARIANT(scm_rights)
 21{
 22	char name[32];
 23	int type;
 24	int flags;
 25	bool test_listener;
 26};
 27
 28FIXTURE_VARIANT_ADD(scm_rights, dgram)
 29{
 30	.name = "UNIX ",
 31	.type = SOCK_DGRAM,
 32	.flags = 0,
 33	.test_listener = false,
 34};
 35
 36FIXTURE_VARIANT_ADD(scm_rights, stream)
 37{
 38	.name = "UNIX-STREAM ",
 39	.type = SOCK_STREAM,
 40	.flags = 0,
 41	.test_listener = false,
 42};
 43
 44FIXTURE_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
 52FIXTURE_VARIANT_ADD(scm_rights, stream_listener)
 53{
 54	.name = "UNIX-STREAM ",
 55	.type = SOCK_STREAM,
 56	.flags = 0,
 57	.test_listener = true,
 58};
 59
 60FIXTURE_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
 68static 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
101FIXTURE_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
112FIXTURE_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
122static 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
155static 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
170static 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	ASSERT_LE(n * 2, sizeof(self->fd) / sizeof(self->fd[0]));
176
177	if (variant->test_listener)
178		create_listeners(_metadata, self, n);
179	else
180		create_socketpairs(_metadata, self, variant, n);
181}
182
183static void __close_sockets(struct __test_metadata *_metadata,
184			    FIXTURE_DATA(scm_rights) *self,
185			    int n)
186{
187	int i, ret;
188
189	ASSERT_GE(sizeof(self->fd) / sizeof(int), n);
190
191	for (i = 0; i < n * 2; i++) {
192		ret = close(self->fd[i]);
193		ASSERT_EQ(0, ret);
194	}
195}
196
197void __send_fd(struct __test_metadata *_metadata,
198	       const FIXTURE_DATA(scm_rights) *self,
199	       const FIXTURE_VARIANT(scm_rights) *variant,
200	       int inflight, int receiver)
201{
202#define MSG "x"
203#define MSGLEN 1
204	struct {
205		struct cmsghdr cmsghdr;
206		int fd[2];
207	} cmsg = {
208		.cmsghdr = {
209			.cmsg_len = CMSG_LEN(sizeof(cmsg.fd)),
210			.cmsg_level = SOL_SOCKET,
211			.cmsg_type = SCM_RIGHTS,
212		},
213		.fd = {
214			self->fd[inflight * 2],
215			self->fd[inflight * 2],
216		},
217	};
218	struct iovec iov = {
219		.iov_base = MSG,
220		.iov_len = MSGLEN,
221	};
222	struct msghdr msg = {
223		.msg_name = NULL,
224		.msg_namelen = 0,
225		.msg_iov = &iov,
226		.msg_iovlen = 1,
227		.msg_control = &cmsg,
228		.msg_controllen = CMSG_SPACE(sizeof(cmsg.fd)),
229	};
230	int ret;
231
232	ret = sendmsg(self->fd[receiver * 2 + 1], &msg, variant->flags);
233	ASSERT_EQ(MSGLEN, ret);
234}
235
236#define create_sockets(n)					\
237	__create_sockets(_metadata, self, variant, n)
238#define close_sockets(n)					\
239	__close_sockets(_metadata, self, n)
240#define send_fd(inflight, receiver)				\
241	__send_fd(_metadata, self, variant, inflight, receiver)
242
243TEST_F(scm_rights, self_ref)
244{
245	create_sockets(2);
246
247	send_fd(0, 0);
248
249	send_fd(1, 1);
250
251	close_sockets(2);
252}
253
254TEST_F(scm_rights, triangle)
255{
256	create_sockets(6);
257
258	send_fd(0, 1);
259	send_fd(1, 2);
260	send_fd(2, 0);
261
262	send_fd(3, 4);
263	send_fd(4, 5);
264	send_fd(5, 3);
265
266	close_sockets(6);
267}
268
269TEST_F(scm_rights, cross_edge)
270{
271	create_sockets(8);
272
273	send_fd(0, 1);
274	send_fd(1, 2);
275	send_fd(2, 0);
276	send_fd(1, 3);
277	send_fd(3, 2);
278
279	send_fd(4, 5);
280	send_fd(5, 6);
281	send_fd(6, 4);
282	send_fd(5, 7);
283	send_fd(7, 6);
284
285	close_sockets(8);
286}
287
288TEST_F(scm_rights, backtrack_from_scc)
289{
290	create_sockets(10);
291
292	send_fd(0, 1);
293	send_fd(0, 4);
294	send_fd(1, 2);
295	send_fd(2, 3);
296	send_fd(3, 1);
297
298	send_fd(5, 6);
299	send_fd(5, 9);
300	send_fd(6, 7);
301	send_fd(7, 8);
302	send_fd(8, 6);
303
304	close_sockets(10);
305}
306
307TEST_HARNESS_MAIN