1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2019 Bjoern A. Zeeb
5 * Copyright (c) 2024 Stormshield
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <sys/wait.h>
32
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35
36 #include <errno.h>
37 #include <poll.h>
38 #include <pwd.h>
39 #include <stdio.h>
40 #include <unistd.h>
41
42 #include <atf-c.h>
43
44 ATF_TC_WITHOUT_HEAD(basic);
ATF_TC_BODY(basic,tc)45 ATF_TC_BODY(basic, tc)
46 {
47 int sd;
48
49 sd = socket(PF_INET, SOCK_DGRAM, 0);
50 ATF_CHECK(sd >= 0);
51
52 close(sd);
53 }
54
55 ATF_TC_WITHOUT_HEAD(bind_zero);
ATF_TC_BODY(bind_zero,tc)56 ATF_TC_BODY(bind_zero, tc)
57 {
58 int sd, rc;
59 struct sockaddr_in sin;
60
61 sd = socket(PF_INET, SOCK_DGRAM, 0);
62 ATF_CHECK(sd >= 0);
63
64 bzero(&sin, sizeof(sin));
65 /*
66 * For AF_INET we do not check the family in in_pcbbind_setup(9),
67 * sa_len gets set from the syscall argument in getsockaddr(9),
68 * so we bind to 0:0.
69 */
70 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin));
71 ATF_CHECK_EQ(0, rc);
72
73 close(sd);
74 }
75
76 ATF_TC_WITHOUT_HEAD(bind_ok);
ATF_TC_BODY(bind_ok,tc)77 ATF_TC_BODY(bind_ok, tc)
78 {
79 int sd, rc;
80 struct sockaddr_in sin;
81
82 sd = socket(PF_INET, SOCK_DGRAM, 0);
83 ATF_CHECK(sd >= 0);
84
85 bzero(&sin, sizeof(sin));
86 sin.sin_family = AF_INET;
87 sin.sin_len = sizeof(sin);
88 sin.sin_port = htons(0);
89 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
90 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin));
91 ATF_CHECK_EQ(0, rc);
92
93 close(sd);
94 }
95
96 ATF_TC_WITHOUT_HEAD(poll_no_rdhup);
ATF_TC_BODY(poll_no_rdhup,tc)97 ATF_TC_BODY(poll_no_rdhup, tc)
98 {
99 int ss, ss2, cs, rc;
100 struct sockaddr_in sin;
101 socklen_t slen;
102 struct pollfd pfd;
103 int one = 1;
104
105 /* Verify that we don't expose POLLRDHUP if not requested. */
106
107 /* Server setup. */
108 ss = socket(PF_INET, SOCK_STREAM, 0);
109 ATF_CHECK(ss >= 0);
110 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
111 ATF_CHECK_EQ(0, rc);
112 bzero(&sin, sizeof(sin));
113 sin.sin_family = AF_INET;
114 sin.sin_len = sizeof(sin);
115 sin.sin_port = htons(0);
116 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
117 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin));
118 ATF_CHECK_EQ(0, rc);
119 rc = listen(ss, 1);
120 ATF_CHECK_EQ(0, rc);
121 slen = sizeof(sin);
122 rc = getsockname(ss, (struct sockaddr *)&sin, &slen);
123 ATF_CHECK_EQ(0, rc);
124
125 /* Client connects, server accepts. */
126 cs = socket(PF_INET, SOCK_STREAM, 0);
127 ATF_CHECK(cs >= 0);
128 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
129 ATF_CHECK_EQ(0, rc);
130 ss2 = accept(ss, NULL, NULL);
131 ATF_CHECK(ss2 >= 0);
132
133 /* Server can write, sees only POLLOUT. */
134 pfd.fd = ss2;
135 pfd.events = POLLIN | POLLOUT;
136 rc = poll(&pfd, 1, 0);
137 ATF_CHECK_EQ(1, rc);
138 ATF_CHECK_EQ(POLLOUT, pfd.revents);
139
140 /* Client closes socket! */
141 rc = close(cs);
142 ATF_CHECK_EQ(0, rc);
143
144 /*
145 * Server now sees POLLIN, but not POLLRDHUP because we didn't ask.
146 * Need non-zero timeout to wait for the FIN to arrive and trigger the
147 * socket to become readable.
148 */
149 pfd.fd = ss2;
150 pfd.events = POLLIN;
151 rc = poll(&pfd, 1, 60000);
152 ATF_CHECK_EQ(1, rc);
153 ATF_CHECK_EQ(POLLIN, pfd.revents);
154
155 close(ss2);
156 close(ss);
157 }
158
159 ATF_TC_WITHOUT_HEAD(poll_rdhup);
ATF_TC_BODY(poll_rdhup,tc)160 ATF_TC_BODY(poll_rdhup, tc)
161 {
162 int ss, ss2, cs, rc;
163 struct sockaddr_in sin;
164 socklen_t slen;
165 struct pollfd pfd;
166 char buffer;
167 int one = 1;
168
169 /* Verify that server sees POLLRDHUP if it asks for it. */
170
171 /* Server setup. */
172 ss = socket(PF_INET, SOCK_STREAM, 0);
173 ATF_CHECK(ss >= 0);
174 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
175 ATF_CHECK_EQ(0, rc);
176 bzero(&sin, sizeof(sin));
177 sin.sin_family = AF_INET;
178 sin.sin_len = sizeof(sin);
179 sin.sin_port = htons(0);
180 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
181 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin));
182 ATF_CHECK_EQ(0, rc);
183 rc = listen(ss, 1);
184 ATF_CHECK_EQ(0, rc);
185 slen = sizeof(sin);
186 rc = getsockname(ss, (struct sockaddr *)&sin, &slen);
187 ATF_CHECK_EQ(0, rc);
188
189 /* Client connects, server accepts. */
190 cs = socket(PF_INET, SOCK_STREAM, 0);
191 ATF_CHECK(cs >= 0);
192 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
193 ATF_CHECK_EQ(0, rc);
194 ss2 = accept(ss, NULL, NULL);
195 ATF_CHECK(ss2 >= 0);
196
197 /* Server can write, so sees POLLOUT. */
198 pfd.fd = ss2;
199 pfd.events = POLLIN | POLLOUT | POLLRDHUP;
200 rc = poll(&pfd, 1, 0);
201 ATF_CHECK_EQ(1, rc);
202 ATF_CHECK_EQ(POLLOUT, pfd.revents);
203
204 /* Client writes two bytes, server reads only one of them. */
205 rc = write(cs, "xx", 2);
206 ATF_CHECK_EQ(2, rc);
207 rc = read(ss2, &buffer, 1);
208 ATF_CHECK_EQ(1, rc);
209
210 /* Server can read, so sees POLLIN. */
211 pfd.fd = ss2;
212 pfd.events = POLLIN | POLLOUT | POLLRDHUP;
213 rc = poll(&pfd, 1, 0);
214 ATF_CHECK_EQ(1, rc);
215 ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents);
216
217 /* Client closes socket! */
218 rc = close(cs);
219 ATF_CHECK_EQ(0, rc);
220
221 /*
222 * Server sees Linux-style POLLRDHUP. Note that this is the case even
223 * though one byte of data remains unread.
224 *
225 * This races against the delivery of FIN caused by the close() above.
226 * Sometimes (more likely when run under truss or if another system
227 * call is added in between) it hits the path where sopoll_generic()
228 * immediately sees SBS_CANTRCVMORE, and sometimes it sleeps with flag
229 * SB_SEL so that it's woken up almost immediately and runs again,
230 * which is why we need a non-zero timeout here.
231 */
232 pfd.fd = ss2;
233 pfd.events = POLLRDHUP;
234 rc = poll(&pfd, 1, 60000);
235 ATF_CHECK_EQ(1, rc);
236 ATF_CHECK_EQ(POLLRDHUP, pfd.revents);
237
238 close(ss2);
239 close(ss);
240 }
241
242 ATF_TC_WITHOUT_HEAD(stream_reconnect);
ATF_TC_BODY(stream_reconnect,tc)243 ATF_TC_BODY(stream_reconnect, tc)
244 {
245 struct sockaddr_in sin;
246 socklen_t slen;
247 int ss, cs, rc;
248
249 /*
250 * Make sure that an attempt to connect(2) a connected or disconnected
251 * stream socket fails with EISCONN.
252 */
253
254 /* Server setup. */
255 ss = socket(PF_INET, SOCK_STREAM, 0);
256 ATF_CHECK(ss >= 0);
257 bzero(&sin, sizeof(sin));
258 sin.sin_family = AF_INET;
259 sin.sin_len = sizeof(sin);
260 sin.sin_port = htons(0);
261 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
262 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin));
263 ATF_CHECK_EQ(0, rc);
264 rc = listen(ss, 1);
265 ATF_CHECK_EQ(0, rc);
266 slen = sizeof(sin);
267 rc = getsockname(ss, (struct sockaddr *)&sin, &slen);
268 ATF_CHECK_EQ(0, rc);
269
270 /* Client connects, shuts down. */
271 cs = socket(PF_INET, SOCK_STREAM, 0);
272 ATF_CHECK(cs >= 0);
273 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
274 ATF_CHECK_EQ(0, rc);
275 rc = shutdown(cs, SHUT_RDWR);
276 ATF_CHECK_EQ(0, rc);
277
278 /* A subsequent connect(2) fails with EISCONN. */
279 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
280 ATF_CHECK_EQ(-1, rc);
281 ATF_CHECK_EQ(errno, EISCONN);
282
283 rc = close(cs);
284 ATF_CHECK_EQ(0, rc);
285 rc = close(ss);
286 ATF_CHECK_EQ(0, rc);
287 }
288
289 /*
290 * Make sure that unprivileged users can't set the IP_BINDANY or IPV6_BINDANY
291 * socket options.
292 */
293 ATF_TC(bindany);
ATF_TC_HEAD(bindany,tc)294 ATF_TC_HEAD(bindany, tc)
295 {
296 atf_tc_set_md_var(tc, "require.user", "unprivileged");
297 }
ATF_TC_BODY(bindany,tc)298 ATF_TC_BODY(bindany, tc)
299 {
300 int s;
301
302 s = socket(AF_INET, SOCK_STREAM, 0);
303 ATF_REQUIRE(s >= 0);
304 ATF_REQUIRE_ERRNO(EPERM,
305 setsockopt(s, IPPROTO_IP, IP_BINDANY, &(int){1}, sizeof(int)) ==
306 -1);
307 ATF_REQUIRE(close(s) == 0);
308
309 s = socket(AF_INET, SOCK_DGRAM, 0);
310 ATF_REQUIRE(s >= 0);
311 ATF_REQUIRE_ERRNO(EPERM,
312 setsockopt(s, IPPROTO_IP, IP_BINDANY, &(int){1}, sizeof(int)) ==
313 -1);
314 ATF_REQUIRE(close(s) == 0);
315
316 s = socket(AF_INET6, SOCK_STREAM, 0);
317 ATF_REQUIRE(s >= 0);
318 ATF_REQUIRE_ERRNO(EPERM,
319 setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY, &(int){1}, sizeof(int)) ==
320 -1);
321 ATF_REQUIRE(close(s) == 0);
322
323 s = socket(AF_INET6, SOCK_DGRAM, 0);
324 ATF_REQUIRE(s >= 0);
325 ATF_REQUIRE_ERRNO(EPERM,
326 setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY, &(int){1}, sizeof(int)) ==
327 -1);
328 ATF_REQUIRE(close(s) == 0);
329 }
330
331 /*
332 * Bind a socket to the specified address, optionally dropping privileges and
333 * setting one of the SO_REUSE* options first.
334 *
335 * Expected returns for different test case scenarios are: 1) successful
336 * immediate bind(2), successful bind(2) after setting specified SO_REUSE*
337 * socket option, and bind(2) failed with EADDRINUSE.
338 */
339 static enum bind_res {
340 BIND_FAILED = 0,
341 SETEUID_FAIL = 1,
342 SOCKET_FAIL = 2,
343 BIND_INSTANT_SUCCESS = 3,
344 BIND_BADERR1 = 4,
345 SETSOCKOPT_FAIL = 5,
346 BIND_REUSE_SUCCESS = 6,
347 BIND_BADERR2 = 7,
348 }
child_bind(const atf_tc_t * tc,int type,const struct sockaddr * sa,int opt,bool unpriv)349 child_bind(const atf_tc_t *tc, int type, const struct sockaddr *sa, int opt,
350 bool unpriv)
351 {
352 const char *user;
353 pid_t child;
354
355 if (unpriv) {
356 if (!atf_tc_has_config_var(tc, "unprivileged_user"))
357 atf_tc_skip("unprivileged_user not set");
358 user = atf_tc_get_config_var(tc, "unprivileged_user");
359 } else {
360 user = NULL;
361 }
362
363 child = fork();
364 ATF_REQUIRE(child != -1);
365 if (child == 0) {
366 int s;
367
368 if (user != NULL) {
369 struct passwd *passwd;
370
371 passwd = getpwnam(user);
372 if (seteuid(passwd->pw_uid) != 0)
373 _exit(SETEUID_FAIL);
374 }
375
376 s = socket(sa->sa_family, type, 0);
377 if (s < 0)
378 _exit(SOCKET_FAIL);
379 if (bind(s, sa, sa->sa_len) == 0)
380 _exit(BIND_INSTANT_SUCCESS);
381 if (errno != EADDRINUSE)
382 _exit(BIND_BADERR1);
383 if (opt != 0) {
384 if (setsockopt(s, SOL_SOCKET, opt, &(int){1},
385 sizeof(int)) != 0)
386 _exit(SETSOCKOPT_FAIL);
387 }
388 if (bind(s, sa, sa->sa_len) == 0)
389 _exit(BIND_REUSE_SUCCESS);
390 if (errno != EADDRINUSE)
391 _exit(BIND_BADERR1);
392 _exit(BIND_FAILED);
393 } else {
394 int status;
395
396 ATF_REQUIRE_EQ(waitpid(child, &status, 0), child);
397 ATF_REQUIRE(WIFEXITED(status));
398 status = WEXITSTATUS(status);
399 return (status);
400 }
401 }
402
403 /*
404 * Try to bind two sockets to the same address/port tuple. Under some
405 * conditions this is permitted.
406 */
407 ATF_TC(multibind);
ATF_TC_HEAD(multibind,tc)408 ATF_TC_HEAD(multibind, tc)
409 {
410 atf_tc_set_md_var(tc, "require.user", "root");
411 atf_tc_set_md_var(tc, "require.config", "unprivileged_user");
412 }
413
ATF_TC_BODY(multibind,tc)414 ATF_TC_BODY(multibind, tc)
415 {
416 const struct {
417 int type;
418 int opt1;
419 bool wild1;
420 int opt2;
421 bool wild2; /* not exercised yet, uses getsockname() rv */
422 enum bind_res priv_res;
423 enum bind_res unpriv_res;
424 } tests[] = {
425 #define ADDR SO_REUSEADDR
426 #define PORT SO_REUSEPORT
427 #define LB SO_REUSEPORT_LB
428 #define x true
429 #define o false
430 #define F BIND_FAILED
431 #define R BIND_REUSE_SUCCESS
432 /* p u */
433 { SOCK_STREAM, 0, o, 0, o, F, F },
434 { SOCK_STREAM, 0, o, ADDR, o, F, F },
435 { SOCK_STREAM, 0, o, PORT, o, F, F },
436 { SOCK_STREAM, 0, o, LB, o, F, F },
437 { SOCK_STREAM, ADDR, o, 0, o, F, F },
438 { SOCK_STREAM, ADDR, o, ADDR, o, F, F },
439 { SOCK_STREAM, ADDR, o, PORT, o, F, F },
440 { SOCK_STREAM, ADDR, o, LB, o, F, F },
441 { SOCK_STREAM, PORT, o, 0, o, F, F },
442 { SOCK_STREAM, PORT, o, ADDR, o, F, F },
443 { SOCK_STREAM, PORT, o, PORT, o, R, F },
444 { SOCK_STREAM, PORT, o, LB, o, F, F },
445 { SOCK_STREAM, LB, o, 0, o, F, F },
446 { SOCK_STREAM, LB, o, ADDR, o, F, F },
447 { SOCK_STREAM, LB, o, PORT, o, F, F },
448 { SOCK_STREAM, LB, o, LB, o, R, F },
449 { SOCK_STREAM, 0, x, 0, x, F, F },
450 { SOCK_STREAM, 0, x, ADDR, x, F, F },
451 { SOCK_STREAM, 0, x, PORT, x, F, F },
452 { SOCK_STREAM, 0, x, LB, x, F, F },
453 { SOCK_STREAM, ADDR, x, 0, x, F, F },
454 { SOCK_STREAM, ADDR, x, ADDR, x, F, F },
455 { SOCK_STREAM, ADDR, x, PORT, x, F, F },
456 { SOCK_STREAM, ADDR, x, LB, x, F, F },
457 { SOCK_STREAM, PORT, x, 0, x, F, F },
458 { SOCK_STREAM, PORT, x, ADDR, x, F, F },
459 { SOCK_STREAM, PORT, x, PORT, x, R, F },
460 { SOCK_STREAM, PORT, x, LB, x, F, F },
461 { SOCK_STREAM, LB, x, 0, x, F, F },
462 { SOCK_STREAM, LB, x, ADDR, x, F, F },
463 { SOCK_STREAM, LB, x, PORT, x, F, F },
464 { SOCK_STREAM, LB, x, LB, x, R, F },
465 { SOCK_STREAM, 0, x, 0, o, F, F },
466 { SOCK_STREAM, 0, x, ADDR, o, R, F },
467 { SOCK_STREAM, 0, x, PORT, o, R, F }, /* bug? */
468 { SOCK_STREAM, 0, o, 0, x, F, F },
469 { SOCK_STREAM, 0, o, ADDR, x, R, F }, /* too strict? */
470 { SOCK_STREAM, 0, o, PORT, x, R, F }, /* bug? */
471 /*
472 * ATM, expected result for SOCK_DGRAM is the same as for
473 * SOCK_STREAM. Thus the below is copy-and-paste of the above.
474 */
475 { SOCK_DGRAM, 0, o, 0, o, F, F },
476 { SOCK_DGRAM, 0, o, ADDR, o, F, F },
477 { SOCK_DGRAM, 0, o, PORT, o, F, F },
478 { SOCK_DGRAM, 0, o, LB, o, F, F },
479 { SOCK_DGRAM, ADDR, o, 0, o, F, F },
480 { SOCK_DGRAM, ADDR, o, ADDR, o, F, F },
481 { SOCK_DGRAM, ADDR, o, PORT, o, F, F },
482 { SOCK_DGRAM, ADDR, o, LB, o, F, F },
483 { SOCK_DGRAM, PORT, o, 0, o, F, F },
484 { SOCK_DGRAM, PORT, o, ADDR, o, F, F },
485 { SOCK_DGRAM, PORT, o, PORT, o, R, F },
486 { SOCK_DGRAM, PORT, o, LB, o, F, F },
487 { SOCK_DGRAM, LB, o, 0, o, F, F },
488 { SOCK_DGRAM, LB, o, ADDR, o, F, F },
489 { SOCK_DGRAM, LB, o, PORT, o, F, F },
490 { SOCK_DGRAM, LB, o, LB, o, R, F },
491 { SOCK_DGRAM, 0, x, 0, x, F, F },
492 { SOCK_DGRAM, 0, x, ADDR, x, F, F },
493 { SOCK_DGRAM, 0, x, PORT, x, F, F },
494 { SOCK_DGRAM, 0, x, LB, x, F, F },
495 { SOCK_DGRAM, ADDR, x, 0, x, F, F },
496 { SOCK_DGRAM, ADDR, x, ADDR, x, F, F },
497 { SOCK_DGRAM, ADDR, x, PORT, x, F, F },
498 { SOCK_DGRAM, ADDR, x, LB, x, F, F },
499 { SOCK_DGRAM, PORT, x, 0, x, F, F },
500 { SOCK_DGRAM, PORT, x, ADDR, x, F, F },
501 { SOCK_DGRAM, PORT, x, PORT, x, R, F },
502 { SOCK_DGRAM, PORT, x, LB, x, F, F },
503 { SOCK_DGRAM, LB, x, 0, x, F, F },
504 { SOCK_DGRAM, LB, x, ADDR, x, F, F },
505 { SOCK_DGRAM, LB, x, PORT, x, F, F },
506 { SOCK_DGRAM, LB, x, LB, x, R, F },
507 { SOCK_DGRAM, 0, x, 0, o, F, F },
508 { SOCK_DGRAM, 0, x, ADDR, o, R, F },
509 { SOCK_DGRAM, 0, x, PORT, o, R, F }, /* bug? */
510 { SOCK_DGRAM, 0, o, 0, x, F, F },
511 { SOCK_DGRAM, 0, o, ADDR, x, R, F }, /* too strict? */
512 { SOCK_DGRAM, 0, o, PORT, x, R, F }, /* bug? */
513 #undef F
514 #undef R
515 #undef x
516 #undef o
517 #undef ADDR
518 #undef PORT
519 #undef LB
520 };
521 /*
522 * Expected results for IPv4 and IPv6 shall always be the same, so
523 * this dimension is implemented as a cycle rather than table entry.
524 */
525 const union sockaddr_union {
526 struct sockaddr_in sin;
527 struct sockaddr_in6 sin6;
528 struct sockaddr sa;
529 } wild[] = {
530 {
531 .sin.sin_family = AF_INET,
532 .sin.sin_len = sizeof(struct sockaddr_in),
533 },
534 {
535 .sin6.sin6_family = AF_INET6,
536 .sin6.sin6_len = sizeof(struct sockaddr_in6),
537 },
538 }, loop[] = {
539 {
540 .sin.sin_family = AF_INET,
541 .sin.sin_len = sizeof(struct sockaddr_in),
542 .sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
543 },
544 {
545 .sin6.sin6_family = AF_INET6,
546 .sin6.sin6_len = sizeof(struct sockaddr_in6),
547 .sin6.sin6_addr = in6addr_loopback,
548 },
549 };
550
551 _Static_assert(nitems(wild) == nitems(loop), "EDOOFUS");
552 for (u_int af = 0; af < nitems(wild); af++) {
553 for (u_int i = 0; i < nitems(tests); i++) {
554 const struct sockaddr *sa;
555 union sockaddr_union su;
556 socklen_t slen;
557 enum bind_res res;
558 int s;
559 in_port_t port;
560
561 s = socket(wild[af].sa.sa_family, tests[i].type, 0);
562 ATF_REQUIRE(s >= 0);
563 sa = tests[i].wild1 ? &wild[af].sa : &loop[af].sa;
564 slen = sa->sa_len;
565 ATF_REQUIRE(bind(s, sa, slen) == 0);
566 if (tests[i].opt1 != 0)
567 ATF_REQUIRE(setsockopt(s, SOL_SOCKET,
568 tests[i].opt1, &(int){1}, sizeof(int)) ==
569 0);
570 ATF_REQUIRE(getsockname(s, &su.sa, &slen) == 0);
571 _Static_assert(offsetof(struct sockaddr_in, sin_port)
572 == offsetof(struct sockaddr_in6, sin6_port),
573 "EDOOFUS");
574 port = su.sin.sin_port;
575 memcpy(&su, tests[i].wild2 ? &wild[af] : &loop[af],
576 sizeof(su));
577 su.sin.sin_port = port;
578 sa = &su.sa;
579 res = child_bind(tc, tests[i].type, sa, tests[i].opt2,
580 false);
581 ATF_REQUIRE_MSG(tests[i].priv_res == res,
582 "af %d test #%d (priv) failed", sa->sa_family, i);
583
584 res = child_bind(tc, tests[i].type, sa, tests[i].opt2,
585 true);
586 ATF_REQUIRE_MSG(tests[i].unpriv_res == res,
587 "af %d test #%d (unpriv) failed", sa->sa_family, i);
588
589 ATF_REQUIRE(close(s) == 0);
590 }
591 }
592 }
593
594 /*
595 * Test operation of bind(2) in presence of a connected inpcb using the
596 * same local port.
597 */
598 static enum bind_res
bind_connected_port_test(const atf_tc_t * tc,int domain,int type,bool wild,bool unpriv)599 bind_connected_port_test(const atf_tc_t *tc, int domain, int type, bool wild,
600 bool unpriv)
601 {
602 struct sockaddr_in sin;
603 struct sockaddr_in6 sin6;
604 struct sockaddr *sinp;
605 socklen_t slen;
606 int error, ss, cs, as;
607 enum bind_res res;
608
609 /*
610 * Create a connected socket pair.
611 */
612 ss = socket(domain, type, 0);
613 ATF_REQUIRE_MSG(ss >= 0, "socket failed: %s", strerror(errno));
614 if (domain == PF_INET) {
615 memset(&sin, 0, sizeof(sin));
616 sin.sin_family = AF_INET;
617 sin.sin_len = sizeof(sin);
618 sin.sin_addr.s_addr = htonl(INADDR_ANY);
619 sin.sin_port = htons(0);
620 sinp = (struct sockaddr *)&sin;
621 } else {
622 ATF_REQUIRE(domain == PF_INET6);
623 memset(&sin6, 0, sizeof(sin6));
624 sin6.sin6_family = AF_INET6;
625 sin6.sin6_len = sizeof(sin6);
626 sin6.sin6_addr = in6addr_any;
627 sin6.sin6_port = htons(0);
628 sinp = (struct sockaddr *)&sin6;
629 }
630
631 error = bind(ss, sinp, sinp->sa_len);
632 ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
633
634 if (type == SOCK_STREAM) {
635 error = getsockname(ss, sinp, &(socklen_t){ sinp->sa_len });
636 ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s",
637 strerror(errno));
638 error = listen(ss, 1);
639 ATF_REQUIRE_MSG(error == 0,
640 "listen failed: %s", strerror(errno));
641 cs = socket(domain, type, 0);
642 ATF_REQUIRE_MSG(cs >= 0, "socket failed: %s", strerror(errno));
643 if (domain == PF_INET)
644 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
645 else
646 sin6.sin6_addr = in6addr_loopback;
647 error = connect(cs, sinp, sinp->sa_len);
648 ATF_REQUIRE_MSG(error == 0,
649 "connect failed: %s", strerror(errno));
650 slen = sinp->sa_len;
651 as = accept(ss, sinp, &slen);
652 ATF_REQUIRE_MSG(as >= 0, "accept failed: %s", strerror(errno));
653 } else {
654 ATF_REQUIRE(type == SOCK_DGRAM);
655 if (domain == PF_INET) {
656 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
657 sin.sin_port = htons(6666);
658 } else {
659 sin6.sin6_addr = in6addr_loopback;
660 sin6.sin6_port = htons(6666);
661 }
662 error = connect(ss, sinp, sinp->sa_len);
663 ATF_REQUIRE_MSG(error == 0,
664 "connect failed: %s", strerror(errno));
665 error = getsockname(ss, sinp, &(socklen_t){ sinp->sa_len });
666 ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s",
667 strerror(errno));
668 }
669
670 if (wild) {
671 if (domain == PF_INET)
672 sin.sin_addr.s_addr = htonl(INADDR_ANY);
673 else
674 sin6.sin6_addr = in6addr_any;
675 }
676
677 res = child_bind(tc, type, sinp, SO_REUSEADDR, unpriv);
678
679 if (type == SOCK_STREAM) {
680 ATF_REQUIRE(close(as) == 0);
681 ATF_REQUIRE(close(cs) == 0);
682 }
683 ATF_REQUIRE(close(ss) == 0);
684
685 return (res);
686 }
687
688 /*
689 * Normally bind() prevents port stealing by a different user, even when
690 * SO_REUSE* are specified. However, if the port is bound by a connected
691 * socket, then it's fair game.
692 */
693 ATF_TC(bind_connected_port);
ATF_TC_HEAD(bind_connected_port,tc)694 ATF_TC_HEAD(bind_connected_port, tc)
695 {
696 atf_tc_set_md_var(tc, "require.user", "root");
697 atf_tc_set_md_var(tc, "require.config", "unprivileged_user");
698 }
ATF_TC_BODY(bind_connected_port,tc)699 ATF_TC_BODY(bind_connected_port, tc)
700 {
701 struct bind_connected_port_res {
702 int domain;
703 int type;
704 bool wild;
705 bool unpriv;
706 enum bind_res result;
707 } tests[] = {
708 #define x true
709 #define o false
710 /* W U */
711 { AF_INET, SOCK_STREAM, x, x, BIND_REUSE_SUCCESS },
712 { AF_INET, SOCK_STREAM, o, x, BIND_REUSE_SUCCESS },
713 { AF_INET, SOCK_STREAM, x, o, BIND_REUSE_SUCCESS },
714 { AF_INET, SOCK_STREAM, o, o, BIND_REUSE_SUCCESS },
715 { AF_INET6, SOCK_STREAM, x, x, BIND_REUSE_SUCCESS },
716 { AF_INET6, SOCK_STREAM, o, x, BIND_REUSE_SUCCESS },
717 { AF_INET6, SOCK_STREAM, x, o, BIND_REUSE_SUCCESS },
718 { AF_INET6, SOCK_STREAM, o, o, BIND_REUSE_SUCCESS },
719 { AF_INET, SOCK_DGRAM, x, x, BIND_FAILED },
720 { AF_INET, SOCK_DGRAM, o, x, BIND_FAILED },
721 { AF_INET, SOCK_DGRAM, x, o, BIND_REUSE_SUCCESS },
722 { AF_INET, SOCK_DGRAM, o, o, BIND_REUSE_SUCCESS },
723 { AF_INET6, SOCK_DGRAM, x, x, BIND_FAILED },
724 { AF_INET6, SOCK_DGRAM, o, x, BIND_FAILED },
725 { AF_INET6, SOCK_DGRAM, x, o, BIND_REUSE_SUCCESS },
726 { AF_INET6, SOCK_DGRAM, o, o, BIND_REUSE_SUCCESS },
727 #undef x
728 #undef o
729 };
730
731 for (u_int i = 0; i < nitems(tests); i++) {
732 enum bind_res res;
733
734 res = bind_connected_port_test(tc, tests[i].domain,
735 tests[i].type, tests[i].wild, tests[i].unpriv);
736 ATF_REQUIRE_MSG(res == tests[i].result, "test #%u: "
737 "domain %u type %u%s %sprivileged: result %u (expected %u)",
738 i, tests[i].domain, tests[i].type,
739 tests[i].wild ? " wild" : "",
740 tests[i].unpriv ? "un" : "",
741 res, tests[i].result);
742 }
743 }
744
ATF_TP_ADD_TCS(tp)745 ATF_TP_ADD_TCS(tp)
746 {
747 ATF_TP_ADD_TC(tp, basic);
748 ATF_TP_ADD_TC(tp, bind_zero);
749 ATF_TP_ADD_TC(tp, bind_ok);
750 ATF_TP_ADD_TC(tp, poll_no_rdhup);
751 ATF_TP_ADD_TC(tp, poll_rdhup);
752 ATF_TP_ADD_TC(tp, stream_reconnect);
753 ATF_TP_ADD_TC(tp, bindany);
754 ATF_TP_ADD_TC(tp, multibind);
755 ATF_TP_ADD_TC(tp, bind_connected_port);
756
757 return atf_no_error();
758 }
759