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
)