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