]> Git Repo - linux.git/blob - tools/testing/selftests/net/af_unix/scm_rights.c
Linux 6.14-rc3
[linux.git] / tools / testing / selftests / net / af_unix / scm_rights.c
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[32];
18 };
19
20 FIXTURE_VARIANT(scm_rights)
21 {
22         char name[32];
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         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
183 static 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
197 void __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
243 TEST_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
254 TEST_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
269 TEST_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
288 TEST_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
307 TEST_HARNESS_MAIN
This page took 0.048571 seconds and 4 git commands to generate.