1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
5 * Copyright (c) 2018 Alan Somers
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 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 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/cdefs.h>
30 #include <sys/socket.h>
31 #include <sys/event.h>
32 #include <sys/select.h>
33 #include <sys/sysctl.h>
34 #include <sys/time.h>
35 #include <sys/un.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <poll.h>
41 #include <pthread.h>
42 #include <pthread_np.h>
43
44 #include <atf-c.h>
45
46 static void
do_socketpair(int * sv)47 do_socketpair(int *sv)
48 {
49 int s;
50
51 s = socketpair(PF_LOCAL, SOCK_STREAM, 0, sv);
52 ATF_REQUIRE_EQ(0, s);
53 ATF_REQUIRE(sv[0] >= 0);
54 ATF_REQUIRE(sv[1] >= 0);
55 ATF_REQUIRE(sv[0] != sv[1]);
56 }
57
58 static u_long
getsendspace(void)59 getsendspace(void)
60 {
61 u_long sendspace;
62
63 ATF_REQUIRE_MSG(sysctlbyname("net.local.stream.sendspace", &sendspace,
64 &(size_t){sizeof(u_long)}, NULL, 0) != -1,
65 "sysctl net.local.stream.sendspace failed: %s", strerror(errno));
66
67 return (sendspace);
68 }
69
70 /* getpeereid(3) should work with stream sockets created via socketpair(2) */
71 ATF_TC_WITHOUT_HEAD(getpeereid);
ATF_TC_BODY(getpeereid,tc)72 ATF_TC_BODY(getpeereid, tc)
73 {
74 int sv[2];
75 uid_t real_euid, euid;
76 gid_t real_egid, egid;
77
78 real_euid = geteuid();
79 real_egid = getegid();
80
81 do_socketpair(sv);
82
83 ATF_REQUIRE_EQ(0, getpeereid(sv[0], &euid, &egid));
84 ATF_CHECK_EQ(real_euid, euid);
85 ATF_CHECK_EQ(real_egid, egid);
86
87 ATF_REQUIRE_EQ(0, getpeereid(sv[1], &euid, &egid));
88 ATF_CHECK_EQ(real_euid, euid);
89 ATF_CHECK_EQ(real_egid, egid);
90
91 close(sv[0]);
92 close(sv[1]);
93 }
94
95 /* Sending zero bytes should succeed (once regressed in aba79b0f4a3f). */
96 ATF_TC_WITHOUT_HEAD(send_0);
ATF_TC_BODY(send_0,tc)97 ATF_TC_BODY(send_0, tc)
98 {
99 int sv[2];
100
101 do_socketpair(sv);
102 ATF_REQUIRE(send(sv[0], sv, 0, 0) == 0);
103 close(sv[0]);
104 close(sv[1]);
105 }
106
107 struct check_ctx;
108 typedef void check_func_t(struct check_ctx *);
109 struct check_ctx {
110 check_func_t *method;
111 int sv[2];
112 bool timeout;
113 union {
114 enum { SELECT_RD, SELECT_WR } select_what;
115 short poll_events;
116 short kev_filter;
117 };
118 int nfds;
119 union {
120 short poll_revents;
121 unsigned short kev_flags;
122 };
123 };
124
125 static void
check_select(struct check_ctx * ctx)126 check_select(struct check_ctx *ctx)
127 {
128 fd_set fds;
129 int nfds;
130
131 FD_ZERO(&fds);
132 FD_SET(ctx->sv[0], &fds);
133 nfds = select(ctx->sv[0] + 1,
134 ctx->select_what == SELECT_RD ? &fds : NULL,
135 ctx->select_what == SELECT_WR ? &fds : NULL,
136 NULL,
137 ctx->timeout ? &(struct timeval){.tv_usec = 1000} : NULL);
138 ATF_REQUIRE_MSG(nfds == ctx->nfds,
139 "select() returns %d errno %d", nfds, errno);
140 }
141
142 static void
check_poll(struct check_ctx * ctx)143 check_poll(struct check_ctx *ctx)
144 {
145 struct pollfd pfd[1];
146 int nfds;
147
148 pfd[0] = (struct pollfd){
149 .fd = ctx->sv[0],
150 .events = ctx->poll_events,
151 };
152 nfds = poll(pfd, 1, ctx->timeout ? 1 : INFTIM);
153 ATF_REQUIRE_MSG(nfds == ctx->nfds,
154 "poll() returns %d errno %d", nfds, errno);
155 ATF_REQUIRE((pfd[0].revents & ctx->poll_revents) == ctx->poll_revents);
156 }
157
158 static void
check_kevent(struct check_ctx * ctx)159 check_kevent(struct check_ctx *ctx)
160 {
161 struct kevent kev;
162 int nfds, kq;
163
164 ATF_REQUIRE(kq = kqueue());
165 EV_SET(&kev, ctx->sv[0], ctx->kev_filter, EV_ADD, 0, 0, NULL);
166 nfds = kevent(kq, &kev, 1, NULL, 0, NULL);
167 ATF_REQUIRE_MSG(nfds == 0,
168 "kevent() returns %d errno %d", nfds, errno);
169 nfds = kevent(kq, NULL, 0, &kev, 1, ctx->timeout ?
170 &(struct timespec){.tv_nsec = 1000000} : NULL);
171 ATF_REQUIRE_MSG(nfds == ctx->nfds,
172 "kevent() returns %d errno %d", nfds, errno);
173 ATF_REQUIRE(kev.ident == (uintptr_t)ctx->sv[0] &&
174 kev.filter == ctx->kev_filter &&
175 (kev.flags & ctx->kev_flags) == ctx->kev_flags);
176 close(kq);
177 }
178
179 static void
full_socketpair(int * sv)180 full_socketpair(int *sv)
181 {
182 void *buf;
183 u_long sendspace;
184
185 sendspace = getsendspace();
186 ATF_REQUIRE((buf = malloc(sendspace)) != NULL);
187 do_socketpair(sv);
188 ATF_REQUIRE(fcntl(sv[0], F_SETFL, O_NONBLOCK) != -1);
189 do {} while (send(sv[0], buf, sendspace, 0) == (ssize_t)sendspace);
190 ATF_REQUIRE(errno == EAGAIN);
191 ATF_REQUIRE(fcntl(sv[0], F_SETFL, 0) != -1);
192 free(buf);
193 }
194
195 static void *
pthread_wrap(void * arg)196 pthread_wrap(void *arg)
197 {
198 struct check_ctx *ctx = arg;
199
200 ctx->method(ctx);
201
202 return (NULL);
203 }
204
205 /*
206 * Launch a thread that would block in event mech and return it.
207 */
208 static pthread_t
pthread_create_blocked(struct check_ctx * ctx)209 pthread_create_blocked(struct check_ctx *ctx)
210 {
211 pthread_t thr;
212
213 ctx->timeout = false;
214 ctx->nfds = 1;
215 ATF_REQUIRE(pthread_create(&thr, NULL, pthread_wrap, ctx) == 0);
216
217 /* Sleep a bit to make sure that thread is put to sleep. */
218 usleep(10000);
219 ATF_REQUIRE(pthread_peekjoin_np(thr, NULL) == EBUSY);
220
221 return (thr);
222 }
223
224 static void
full_writability_check(struct check_ctx * ctx)225 full_writability_check(struct check_ctx *ctx)
226 {
227 pthread_t thr;
228 void *buf;
229 u_long space;
230
231 space = getsendspace() / 2;
232 ATF_REQUIRE((buf = malloc(space)) != NULL);
233
234 /* First check with timeout, expecting 0 fds returned. */
235 ctx->timeout = true;
236 ctx->nfds = 0;
237 ctx->method(ctx);
238
239 thr = pthread_create_blocked(ctx);
240
241 /* Read some data and re-check, the fd is expected to be returned. */
242 ATF_REQUIRE(read(ctx->sv[1], buf, space) == (ssize_t)space);
243
244 /* Now check that thread was successfully woken up and exited. */
245 ATF_REQUIRE(pthread_join(thr, NULL) == 0);
246
247 /* Extra check repeating what joined thread already did. */
248 ctx->method(ctx);
249
250 close(ctx->sv[0]);
251 close(ctx->sv[1]);
252 free(buf);
253 }
254
255 /*
256 * Make sure that a full socket is not reported as writable by event APIs.
257 */
258 ATF_TC_WITHOUT_HEAD(full_writability_select);
ATF_TC_BODY(full_writability_select,tc)259 ATF_TC_BODY(full_writability_select, tc)
260 {
261 struct check_ctx ctx = {
262 .method = check_select,
263 .select_what = SELECT_WR,
264 };
265
266 full_socketpair(ctx.sv);
267 full_writability_check(&ctx);
268 close(ctx.sv[0]);
269 close(ctx.sv[1]);
270 }
271
272 ATF_TC_WITHOUT_HEAD(full_writability_poll);
ATF_TC_BODY(full_writability_poll,tc)273 ATF_TC_BODY(full_writability_poll, tc)
274 {
275 struct check_ctx ctx = {
276 .method = check_poll,
277 .poll_events = POLLOUT | POLLWRNORM,
278 };
279
280 full_socketpair(ctx.sv);
281 full_writability_check(&ctx);
282 close(ctx.sv[0]);
283 close(ctx.sv[1]);
284 }
285
286 ATF_TC_WITHOUT_HEAD(full_writability_kevent);
ATF_TC_BODY(full_writability_kevent,tc)287 ATF_TC_BODY(full_writability_kevent, tc)
288 {
289 struct check_ctx ctx = {
290 .method = check_kevent,
291 .kev_filter = EVFILT_WRITE,
292 };
293
294 full_socketpair(ctx.sv);
295 full_writability_check(&ctx);
296 close(ctx.sv[0]);
297 close(ctx.sv[1]);
298 }
299
300 ATF_TC_WITHOUT_HEAD(connected_writability);
ATF_TC_BODY(connected_writability,tc)301 ATF_TC_BODY(connected_writability, tc)
302 {
303 struct check_ctx ctx = {
304 .timeout = true,
305 .nfds = 1,
306 };
307
308 do_socketpair(ctx.sv);
309
310 ctx.select_what = SELECT_WR;
311 check_select(&ctx);
312 ctx.poll_events = POLLOUT | POLLWRNORM;
313 check_poll(&ctx);
314 ctx.kev_filter = EVFILT_WRITE;
315 check_kevent(&ctx);
316
317 close(ctx.sv[0]);
318 close(ctx.sv[1]);
319 }
320
321 ATF_TC_WITHOUT_HEAD(unconnected_writability);
ATF_TC_BODY(unconnected_writability,tc)322 ATF_TC_BODY(unconnected_writability, tc)
323 {
324 struct check_ctx ctx = {
325 .timeout = true,
326 .nfds = 0,
327 };
328
329 ATF_REQUIRE((ctx.sv[0] = socket(PF_LOCAL, SOCK_STREAM, 0)) > 0);
330
331 ctx.select_what = SELECT_WR;
332 check_select(&ctx);
333 ctx.poll_events = POLLOUT | POLLWRNORM;
334 check_poll(&ctx);
335 ctx.kev_filter = EVFILT_WRITE;
336 check_kevent(&ctx);
337
338 close(ctx.sv[0]);
339 }
340
341 ATF_TC_WITHOUT_HEAD(peerclosed_writability);
ATF_TC_BODY(peerclosed_writability,tc)342 ATF_TC_BODY(peerclosed_writability, tc)
343 {
344 struct check_ctx ctx = {
345 .timeout = false,
346 .nfds = 1,
347 };
348
349 do_socketpair(ctx.sv);
350 close(ctx.sv[1]);
351
352 ctx.select_what = SELECT_WR;
353 check_select(&ctx);
354 ctx.poll_events = POLLOUT | POLLWRNORM;
355 check_poll(&ctx);
356 ctx.kev_filter = EVFILT_WRITE;
357 ctx.kev_flags = EV_EOF;
358 check_kevent(&ctx);
359
360 close(ctx.sv[0]);
361 }
362
363 ATF_TC_WITHOUT_HEAD(peershutdown_writability);
ATF_TC_BODY(peershutdown_writability,tc)364 ATF_TC_BODY(peershutdown_writability, tc)
365 {
366 struct check_ctx ctx = {
367 .timeout = false,
368 .nfds = 1,
369 };
370
371 do_socketpair(ctx.sv);
372 shutdown(ctx.sv[1], SHUT_RD);
373
374 ctx.select_what = SELECT_WR;
375 check_select(&ctx);
376 ctx.poll_events = POLLOUT | POLLWRNORM;
377 check_poll(&ctx);
378 /*
379 * XXXGL: historically unix(4) sockets were not reporting peer's
380 * shutdown(SHUT_RD) as our EV_EOF. The kevent(2) manual page says
381 * "filter will set EV_EOF when the reader disconnects", which is hard
382 * to interpret unambigously. For now leave the historic behavior,
383 * but we may want to change that in uipc_usrreq.c:uipc_filt_sowrite(),
384 * and then this test will also expect EV_EOF in returned flags.
385 */
386 ctx.kev_filter = EVFILT_WRITE;
387 check_kevent(&ctx);
388
389 close(ctx.sv[0]);
390 close(ctx.sv[1]);
391 }
392
393 ATF_TC_WITHOUT_HEAD(peershutdown_readability);
ATF_TC_BODY(peershutdown_readability,tc)394 ATF_TC_BODY(peershutdown_readability, tc)
395 {
396 struct check_ctx ctx = {
397 .timeout = false,
398 .nfds = 1,
399 };
400 ssize_t readsz;
401 char c;
402
403 do_socketpair(ctx.sv);
404 shutdown(ctx.sv[1], SHUT_WR);
405
406 /*
407 * The other side should flag as readable in select(2) to allow it to
408 * read(2) and observe EOF. Ensure that both poll(2) and select(2)
409 * are consistent here.
410 */
411 ctx.select_what = SELECT_RD;
412 check_select(&ctx);
413 ctx.poll_events = POLLIN | POLLRDNORM;
414 check_poll(&ctx);
415
416 /*
417 * Also check that read doesn't block.
418 */
419 readsz = read(ctx.sv[0], &c, sizeof(c));
420 ATF_REQUIRE_INTEQ(0, readsz);
421
422 close(ctx.sv[0]);
423 close(ctx.sv[1]);
424 }
425
426 static void
peershutdown_wakeup(struct check_ctx * ctx)427 peershutdown_wakeup(struct check_ctx *ctx)
428 {
429 pthread_t thr;
430
431 ctx->timeout = false;
432 ctx->nfds = 1;
433
434 do_socketpair(ctx->sv);
435 thr = pthread_create_blocked(ctx);
436 shutdown(ctx->sv[1], SHUT_WR);
437 ATF_REQUIRE(pthread_join(thr, NULL) == 0);
438
439 close(ctx->sv[0]);
440 close(ctx->sv[1]);
441 }
442
443 ATF_TC_WITHOUT_HEAD(peershutdown_wakeup_select);
ATF_TC_BODY(peershutdown_wakeup_select,tc)444 ATF_TC_BODY(peershutdown_wakeup_select, tc)
445 {
446 peershutdown_wakeup(&(struct check_ctx){
447 .method = check_select,
448 .select_what = SELECT_RD,
449 });
450 }
451
452 ATF_TC_WITHOUT_HEAD(peershutdown_wakeup_poll);
ATF_TC_BODY(peershutdown_wakeup_poll,tc)453 ATF_TC_BODY(peershutdown_wakeup_poll, tc)
454 {
455 peershutdown_wakeup(&(struct check_ctx){
456 .method = check_poll,
457 .poll_events = POLLIN | POLLRDNORM | POLLRDHUP,
458 .poll_revents = POLLRDHUP,
459 });
460 }
461
462 ATF_TC_WITHOUT_HEAD(peershutdown_wakeup_kevent);
ATF_TC_BODY(peershutdown_wakeup_kevent,tc)463 ATF_TC_BODY(peershutdown_wakeup_kevent, tc)
464 {
465 peershutdown_wakeup(&(struct check_ctx){
466 .method = check_kevent,
467 .kev_filter = EVFILT_READ,
468 .kev_flags = EV_EOF,
469 });
470 }
471
472 ATF_TC_WITHOUT_HEAD(ourshutdown_kevent);
ATF_TC_BODY(ourshutdown_kevent,tc)473 ATF_TC_BODY(ourshutdown_kevent, tc)
474 {
475 struct kevent kev;
476 int sv[2], kq;
477
478 do_socketpair(sv);
479 ATF_REQUIRE(kq = kqueue());
480
481 EV_SET(&kev, sv[1], EVFILT_WRITE, EV_ADD, 0, 0, NULL);
482 ATF_REQUIRE(kevent(kq, &kev, 1, NULL, 0, NULL) == 0);
483
484 ATF_REQUIRE(shutdown(sv[1], SHUT_WR) == 0);
485
486 ATF_REQUIRE(kevent(kq, NULL, 0, &kev, 1, NULL) == 1);
487 ATF_REQUIRE(kev.ident == (uintptr_t)sv[1] &&
488 kev.filter == EVFILT_WRITE &&
489 kev.flags == EV_EOF);
490
491 close(sv[0]);
492 close(sv[1]);
493 }
494
495 ATF_TC_WITHOUT_HEAD(SO_SNDTIMEO);
ATF_TC_BODY(SO_SNDTIMEO,tc)496 ATF_TC_BODY(SO_SNDTIMEO, tc)
497 {
498 struct timespec tp1, tp2, rtp, sleep = { .tv_nsec = 100000000 };
499 int sv[2];
500 char buf[10];
501
502 full_socketpair(sv);
503 ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDTIMEO,
504 &(struct timeval){ .tv_usec = sleep.tv_nsec / 1000 },
505 sizeof(struct timeval)));
506 ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC_PRECISE, &tp1));
507 ATF_REQUIRE_EQ(-1, send(sv[0], buf, sizeof(buf), 0));
508 ATF_REQUIRE(errno == EAGAIN);
509 ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC_PRECISE, &tp2));
510 timespecsub(&tp2, &tp1, &rtp);
511 ATF_REQUIRE(timespeccmp(&rtp, &sleep, >=));
512 ATF_REQUIRE_EQ(sizeof(buf), recv(sv[1], buf, sizeof(buf), 0));
513 ATF_REQUIRE_EQ(sizeof(buf), send(sv[0], buf, sizeof(buf), 0));
514
515 close(sv[0]);
516 close(sv[1]);
517 }
518
ATF_TP_ADD_TCS(tp)519 ATF_TP_ADD_TCS(tp)
520 {
521 ATF_TP_ADD_TC(tp, getpeereid);
522 ATF_TP_ADD_TC(tp, send_0);
523 ATF_TP_ADD_TC(tp, connected_writability);
524 ATF_TP_ADD_TC(tp, unconnected_writability);
525 ATF_TP_ADD_TC(tp, full_writability_select);
526 ATF_TP_ADD_TC(tp, full_writability_poll);
527 ATF_TP_ADD_TC(tp, full_writability_kevent);
528 ATF_TP_ADD_TC(tp, peerclosed_writability);
529 ATF_TP_ADD_TC(tp, peershutdown_writability);
530 ATF_TP_ADD_TC(tp, peershutdown_readability);
531 ATF_TP_ADD_TC(tp, peershutdown_wakeup_select);
532 ATF_TP_ADD_TC(tp, peershutdown_wakeup_poll);
533 ATF_TP_ADD_TC(tp, peershutdown_wakeup_kevent);
534 ATF_TP_ADD_TC(tp, ourshutdown_kevent);
535 ATF_TP_ADD_TC(tp, SO_SNDTIMEO);
536
537 return atf_no_error();
538 }
539