1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright Amazon.com Inc. or its affiliates. */
10 #include <sys/socket.h>
13 #include "../../kselftest_harness.h"
20 FIXTURE_VARIANT(scm_rights)
28 FIXTURE_VARIANT_ADD(scm_rights, dgram)
33 .test_listener = false,
36 FIXTURE_VARIANT_ADD(scm_rights, stream)
38 .name = "UNIX-STREAM ",
41 .test_listener = false,
44 FIXTURE_VARIANT_ADD(scm_rights, stream_oob)
46 .name = "UNIX-STREAM ",
49 .test_listener = false,
52 FIXTURE_VARIANT_ADD(scm_rights, stream_listener)
54 .name = "UNIX-STREAM ",
57 .test_listener = true,
60 FIXTURE_VARIANT_ADD(scm_rights, stream_listener_oob)
62 .name = "UNIX-STREAM ",
65 .test_listener = true,
68 static int count_sockets(struct __test_metadata *_metadata,
69 const FIXTURE_VARIANT(scm_rights) *variant)
71 int sockets = -1, len, ret;
76 f = fopen("/proc/net/protocols", "r");
79 len = strlen(variant->name);
81 while (getline(&line, &unused, f) != -1) {
84 if (strncmp(line, variant->name, len))
87 ret = sscanf(line + len, "%d %d", &unused2, &sockets);
101 FIXTURE_SETUP(scm_rights)
105 ret = unshare(CLONE_NEWNET);
108 ret = count_sockets(_metadata, variant);
112 FIXTURE_TEARDOWN(scm_rights)
118 ret = count_sockets(_metadata, variant);
122 static void create_listeners(struct __test_metadata *_metadata,
123 FIXTURE_DATA(scm_rights) *self,
126 struct sockaddr_un addr = {
127 .sun_family = AF_UNIX,
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]);
136 addrlen = sizeof(addr.sun_family);
137 ret = bind(self->fd[i], (struct sockaddr *)&addr, addrlen);
140 ret = listen(self->fd[i], -1);
143 addrlen = sizeof(addr);
144 ret = getsockname(self->fd[i], (struct sockaddr *)&addr, &addrlen);
147 self->fd[i + 1] = socket(AF_UNIX, SOCK_STREAM, 0);
148 ASSERT_LE(0, self->fd[i + 1]);
150 ret = connect(self->fd[i + 1], (struct sockaddr *)&addr, addrlen);
155 static void create_socketpairs(struct __test_metadata *_metadata,
156 FIXTURE_DATA(scm_rights) *self,
157 const FIXTURE_VARIANT(scm_rights) *variant,
162 ASSERT_GE(sizeof(self->fd) / sizeof(int), n);
164 for (i = 0; i < n * 2; i += 2) {
165 ret = socketpair(AF_UNIX, variant->type, 0, self->fd + i);
170 static void __create_sockets(struct __test_metadata *_metadata,
171 FIXTURE_DATA(scm_rights) *self,
172 const FIXTURE_VARIANT(scm_rights) *variant,
175 ASSERT_LE(n * 2, sizeof(self->fd) / sizeof(self->fd[0]));
177 if (variant->test_listener)
178 create_listeners(_metadata, self, n);
180 create_socketpairs(_metadata, self, variant, n);
183 static void __close_sockets(struct __test_metadata *_metadata,
184 FIXTURE_DATA(scm_rights) *self,
189 ASSERT_GE(sizeof(self->fd) / sizeof(int), n);
191 for (i = 0; i < n * 2; i++) {
192 ret = close(self->fd[i]);
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)
205 struct cmsghdr cmsghdr;
209 .cmsg_len = CMSG_LEN(sizeof(cmsg.fd)),
210 .cmsg_level = SOL_SOCKET,
211 .cmsg_type = SCM_RIGHTS,
214 self->fd[inflight * 2],
215 self->fd[inflight * 2],
222 struct msghdr msg = {
227 .msg_control = &cmsg,
228 .msg_controllen = CMSG_SPACE(sizeof(cmsg.fd)),
232 ret = sendmsg(self->fd[receiver * 2 + 1], &msg, variant->flags);
233 ASSERT_EQ(MSGLEN, ret);
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)
243 TEST_F(scm_rights, self_ref)
254 TEST_F(scm_rights, triangle)
269 TEST_F(scm_rights, cross_edge)
288 TEST_F(scm_rights, backtrack_from_scc)