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 308
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.