1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2013 The FreeBSD Foundation
5 * Copyright (c) 2024-2026 Mariusz Zaborski <oshogbo@FreeBSD.org>
6 *
7 * This software was developed by Pawel Jakub Dawidek under sponsorship from
8 * the FreeBSD Foundation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/resource.h>
34 #include <sys/select.h>
35 #include <sys/socket.h>
36 #include <sys/sysctl.h>
37 #include <sys/wait.h>
38 #include <sys/nv.h>
39
40 #include <stdlib.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <paths.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 #include <atf-c.h>
50
51 #include <nv_impl.h>
52 #include <msgio.h>
53
54 #define ALPHABET "abcdefghijklmnopqrstuvwxyz"
55 #define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
56
57 static void
send_nvlist_child(int sock)58 send_nvlist_child(int sock)
59 {
60 nvlist_t *nvl;
61 nvlist_t *empty;
62 int pfd[2];
63
64 nvl = nvlist_create(0);
65 empty = nvlist_create(0);
66
67 nvlist_add_bool(nvl, "nvlist/bool/true", true);
68 nvlist_add_bool(nvl, "nvlist/bool/false", false);
69 nvlist_add_number(nvl, "nvlist/number/0", 0);
70 nvlist_add_number(nvl, "nvlist/number/1", 1);
71 nvlist_add_number(nvl, "nvlist/number/-1", -1);
72 nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
73 nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
74 nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
75 nvlist_add_string(nvl, "nvlist/string/", "");
76 nvlist_add_string(nvl, "nvlist/string/x", "x");
77 nvlist_add_string(nvl, "nvlist/string/" ALPHABET, ALPHABET);
78
79 nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO",
80 STDERR_FILENO);
81 if (pipe(pfd) == -1)
82 err(EXIT_FAILURE, "pipe");
83 if (write(pfd[1], "test", 4) != 4)
84 err(EXIT_FAILURE, "write");
85 close(pfd[1]);
86 nvlist_add_descriptor(nvl, "nvlist/descriptor/pipe_rd", pfd[0]);
87 close(pfd[0]);
88
89 nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
90 nvlist_add_binary(nvl, "nvlist/binary/" ALPHABET, ALPHABET,
91 sizeof(ALPHABET));
92 nvlist_move_nvlist(nvl, "nvlist/nvlist/empty", empty);
93 nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
94
95 nvlist_send(sock, nvl);
96
97 nvlist_destroy(nvl);
98 }
99
100 static void
send_nvlist_parent(int sock)101 send_nvlist_parent(int sock)
102 {
103 nvlist_t *nvl;
104 const nvlist_t *cnvl, *empty;
105 const char *name, *cname;
106 void *cookie, *ccookie;
107 int type, ctype, fd;
108 size_t size;
109 char buf[4];
110
111 nvl = nvlist_recv(sock, 0);
112 ATF_REQUIRE(nvlist_error(nvl) == 0);
113 if (nvlist_error(nvl) != 0)
114 err(1, "nvlist_recv() failed");
115
116 cookie = NULL;
117
118 name = nvlist_next(nvl, &type, &cookie);
119 ATF_REQUIRE(name != NULL);
120 ATF_REQUIRE(type == NV_TYPE_BOOL);
121 ATF_REQUIRE(strcmp(name, "nvlist/bool/true") == 0);
122 ATF_REQUIRE(nvlist_get_bool(nvl, name) == true);
123
124 name = nvlist_next(nvl, &type, &cookie);
125 ATF_REQUIRE(name != NULL);
126 ATF_REQUIRE(type == NV_TYPE_BOOL);
127 ATF_REQUIRE(strcmp(name, "nvlist/bool/false") == 0);
128 ATF_REQUIRE(nvlist_get_bool(nvl, name) == false);
129
130 name = nvlist_next(nvl, &type, &cookie);
131 ATF_REQUIRE(name != NULL);
132 ATF_REQUIRE(type == NV_TYPE_NUMBER);
133 ATF_REQUIRE(strcmp(name, "nvlist/number/0") == 0);
134 ATF_REQUIRE(nvlist_get_number(nvl, name) == 0);
135
136 name = nvlist_next(nvl, &type, &cookie);
137 ATF_REQUIRE(name != NULL);
138 ATF_REQUIRE(type == NV_TYPE_NUMBER);
139 ATF_REQUIRE(strcmp(name, "nvlist/number/1") == 0);
140 ATF_REQUIRE(nvlist_get_number(nvl, name) == 1);
141
142 name = nvlist_next(nvl, &type, &cookie);
143 ATF_REQUIRE(name != NULL);
144 ATF_REQUIRE(type == NV_TYPE_NUMBER);
145 ATF_REQUIRE(strcmp(name, "nvlist/number/-1") == 0);
146 ATF_REQUIRE((int)nvlist_get_number(nvl, name) == -1);
147
148 name = nvlist_next(nvl, &type, &cookie);
149 ATF_REQUIRE(name != NULL);
150 ATF_REQUIRE(type == NV_TYPE_NUMBER);
151 ATF_REQUIRE(strcmp(name, "nvlist/number/UINT64_MAX") == 0);
152 ATF_REQUIRE(nvlist_get_number(nvl, name) == UINT64_MAX);
153
154 name = nvlist_next(nvl, &type, &cookie);
155 ATF_REQUIRE(name != NULL);
156 ATF_REQUIRE(type == NV_TYPE_NUMBER);
157 ATF_REQUIRE(strcmp(name, "nvlist/number/INT64_MIN") == 0);
158 ATF_REQUIRE((int64_t)nvlist_get_number(nvl, name) == INT64_MIN);
159
160 name = nvlist_next(nvl, &type, &cookie);
161 ATF_REQUIRE(name != NULL);
162 ATF_REQUIRE(type == NV_TYPE_NUMBER);
163 ATF_REQUIRE(strcmp(name, "nvlist/number/INT64_MAX") == 0);
164 ATF_REQUIRE((int64_t)nvlist_get_number(nvl, name) == INT64_MAX);
165
166 name = nvlist_next(nvl, &type, &cookie);
167 ATF_REQUIRE(name != NULL);
168 ATF_REQUIRE(type == NV_TYPE_STRING);
169 ATF_REQUIRE(strcmp(name, "nvlist/string/") == 0);
170 ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), "") == 0);
171
172 name = nvlist_next(nvl, &type, &cookie);
173 ATF_REQUIRE(name != NULL);
174 ATF_REQUIRE(type == NV_TYPE_STRING);
175 ATF_REQUIRE(strcmp(name, "nvlist/string/x") == 0);
176 ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), "x") == 0);
177
178 name = nvlist_next(nvl, &type, &cookie);
179 ATF_REQUIRE(name != NULL);
180 ATF_REQUIRE(type == NV_TYPE_STRING);
181 ATF_REQUIRE(strcmp(name, "nvlist/string/" ALPHABET) == 0);
182 ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), ALPHABET) == 0);
183
184 name = nvlist_next(nvl, &type, &cookie);
185 ATF_REQUIRE(name != NULL);
186 ATF_REQUIRE(type == NV_TYPE_DESCRIPTOR);
187 ATF_REQUIRE(strcmp(name, "nvlist/descriptor/STDERR_FILENO") == 0);
188 ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(nvl, name)));
189
190 name = nvlist_next(nvl, &type, &cookie);
191 ATF_REQUIRE(name != NULL);
192 ATF_REQUIRE(type == NV_TYPE_DESCRIPTOR);
193 ATF_REQUIRE(strcmp(name, "nvlist/descriptor/pipe_rd") == 0);
194 fd = nvlist_get_descriptor(nvl, name);
195 ATF_REQUIRE(fd_is_valid(fd));
196 ATF_REQUIRE(read(fd, buf, sizeof(buf)) == 4);
197 ATF_REQUIRE(strncmp(buf, "test", sizeof(buf)) == 0);
198
199 name = nvlist_next(nvl, &type, &cookie);
200 ATF_REQUIRE(name != NULL);
201 ATF_REQUIRE(type == NV_TYPE_BINARY);
202 ATF_REQUIRE(strcmp(name, "nvlist/binary/x") == 0);
203 ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, NULL), "x", 1) == 0);
204 ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, &size), "x", 1) == 0);
205 ATF_REQUIRE(size == 1);
206
207 name = nvlist_next(nvl, &type, &cookie);
208 ATF_REQUIRE(name != NULL);
209 ATF_REQUIRE(type == NV_TYPE_BINARY);
210 ATF_REQUIRE(strcmp(name, "nvlist/binary/" ALPHABET) == 0);
211 ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, NULL), ALPHABET,
212 sizeof(ALPHABET)) == 0);
213 ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, &size), ALPHABET,
214 sizeof(ALPHABET)) == 0);
215 ATF_REQUIRE(size == sizeof(ALPHABET));
216
217 name = nvlist_next(nvl, &type, &cookie);
218 ATF_REQUIRE(name != NULL);
219 ATF_REQUIRE(type == NV_TYPE_NVLIST);
220 ATF_REQUIRE(strcmp(name, "nvlist/nvlist/empty") == 0);
221 cnvl = nvlist_get_nvlist(nvl, name);
222 ATF_REQUIRE(nvlist_empty(cnvl));
223
224 name = nvlist_next(nvl, &type, &cookie);
225 ATF_REQUIRE(name != NULL);
226 ATF_REQUIRE(type == NV_TYPE_NVLIST);
227 ATF_REQUIRE(strcmp(name, "nvlist/nvlist") == 0);
228 cnvl = nvlist_get_nvlist(nvl, name);
229
230 ccookie = NULL;
231
232 cname = nvlist_next(cnvl, &ctype, &ccookie);
233 ATF_REQUIRE(cname != NULL);
234 ATF_REQUIRE(ctype == NV_TYPE_BOOL);
235 ATF_REQUIRE(strcmp(cname, "nvlist/bool/true") == 0);
236 ATF_REQUIRE(nvlist_get_bool(cnvl, cname) == true);
237
238 cname = nvlist_next(cnvl, &ctype, &ccookie);
239 ATF_REQUIRE(cname != NULL);
240 ATF_REQUIRE(ctype == NV_TYPE_BOOL);
241 ATF_REQUIRE(strcmp(cname, "nvlist/bool/false") == 0);
242 ATF_REQUIRE(nvlist_get_bool(cnvl, cname) == false);
243
244 cname = nvlist_next(cnvl, &ctype, &ccookie);
245 ATF_REQUIRE(cname != NULL);
246 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
247 ATF_REQUIRE(strcmp(cname, "nvlist/number/0") == 0);
248 ATF_REQUIRE(nvlist_get_number(cnvl, cname) == 0);
249
250 cname = nvlist_next(cnvl, &ctype, &ccookie);
251 ATF_REQUIRE(cname != NULL);
252 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
253 ATF_REQUIRE(strcmp(cname, "nvlist/number/1") == 0);
254 ATF_REQUIRE(nvlist_get_number(cnvl, cname) == 1);
255
256 cname = nvlist_next(cnvl, &ctype, &ccookie);
257 ATF_REQUIRE(cname != NULL);
258 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
259 ATF_REQUIRE(strcmp(cname, "nvlist/number/-1") == 0);
260 ATF_REQUIRE((int)nvlist_get_number(cnvl, cname) == -1);
261
262 cname = nvlist_next(cnvl, &ctype, &ccookie);
263 ATF_REQUIRE(cname != NULL);
264 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
265 ATF_REQUIRE(strcmp(cname, "nvlist/number/UINT64_MAX") == 0);
266 ATF_REQUIRE(nvlist_get_number(cnvl, cname) == UINT64_MAX);
267
268 cname = nvlist_next(cnvl, &ctype, &ccookie);
269 ATF_REQUIRE(cname != NULL);
270 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
271 ATF_REQUIRE(strcmp(cname, "nvlist/number/INT64_MIN") == 0);
272 ATF_REQUIRE((int64_t)nvlist_get_number(cnvl, cname) == INT64_MIN);
273
274 cname = nvlist_next(cnvl, &ctype, &ccookie);
275 ATF_REQUIRE(cname != NULL);
276 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
277 ATF_REQUIRE(strcmp(cname, "nvlist/number/INT64_MAX") == 0);
278 ATF_REQUIRE((int64_t)nvlist_get_number(cnvl, cname) == INT64_MAX);
279
280 cname = nvlist_next(cnvl, &ctype, &ccookie);
281 ATF_REQUIRE(cname != NULL);
282 ATF_REQUIRE(ctype == NV_TYPE_STRING);
283 ATF_REQUIRE(strcmp(cname, "nvlist/string/") == 0);
284 ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), "") == 0);
285
286 cname = nvlist_next(cnvl, &ctype, &ccookie);
287 ATF_REQUIRE(cname != NULL);
288 ATF_REQUIRE(ctype == NV_TYPE_STRING);
289 ATF_REQUIRE(strcmp(cname, "nvlist/string/x") == 0);
290 ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), "x") == 0);
291
292 cname = nvlist_next(cnvl, &ctype, &ccookie);
293 ATF_REQUIRE(cname != NULL);
294 ATF_REQUIRE(ctype == NV_TYPE_STRING);
295 ATF_REQUIRE(strcmp(cname, "nvlist/string/" ALPHABET) == 0);
296 ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), ALPHABET) == 0);
297
298 cname = nvlist_next(cnvl, &ctype, &ccookie);
299 ATF_REQUIRE(cname != NULL);
300 ATF_REQUIRE(ctype == NV_TYPE_DESCRIPTOR);
301 ATF_REQUIRE(strcmp(cname, "nvlist/descriptor/STDERR_FILENO") == 0);
302 ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
303
304 cname = nvlist_next(cnvl, &ctype, &ccookie);
305 ATF_REQUIRE(cname != NULL);
306 ATF_REQUIRE(ctype == NV_TYPE_DESCRIPTOR);
307 ATF_REQUIRE(strcmp(cname, "nvlist/descriptor/pipe_rd") == 0);
308 ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
309
310 cname = nvlist_next(cnvl, &ctype, &ccookie);
311 ATF_REQUIRE(cname != NULL);
312 ATF_REQUIRE(ctype == NV_TYPE_BINARY);
313 ATF_REQUIRE(strcmp(cname, "nvlist/binary/x") == 0);
314 ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, NULL), "x", 1) == 0);
315 ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, &size), "x", 1) == 0);
316 ATF_REQUIRE(size == 1);
317
318 cname = nvlist_next(cnvl, &ctype, &ccookie);
319 ATF_REQUIRE(cname != NULL);
320 ATF_REQUIRE(ctype == NV_TYPE_BINARY);
321 ATF_REQUIRE(strcmp(cname, "nvlist/binary/" ALPHABET) == 0);
322 ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, NULL), ALPHABET,
323 sizeof(ALPHABET)) == 0);
324 ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, &size), ALPHABET,
325 sizeof(ALPHABET)) == 0);
326 ATF_REQUIRE(size == sizeof(ALPHABET));
327
328 cname = nvlist_next(cnvl, &ctype, &ccookie);
329 ATF_REQUIRE(cname != NULL);
330 ATF_REQUIRE(ctype == NV_TYPE_NVLIST);
331 ATF_REQUIRE(strcmp(cname, "nvlist/nvlist/empty") == 0);
332 empty = nvlist_get_nvlist(cnvl, cname);
333 ATF_REQUIRE(nvlist_empty(empty));
334
335 cname = nvlist_next(cnvl, &ctype, &ccookie);
336 ATF_REQUIRE(cname == NULL);
337
338 name = nvlist_next(nvl, &type, &cookie);
339 ATF_REQUIRE(name == NULL);
340
341 nvlist_destroy(nvl);
342 }
343
344 static void
nvlist_send_recv__send_nvlist(short sotype)345 nvlist_send_recv__send_nvlist(short sotype)
346 {
347 int socks[2], status;
348 pid_t pid;
349
350 ATF_REQUIRE(socketpair(PF_UNIX, sotype, 0, socks) == 0);
351
352 pid = fork();
353 ATF_REQUIRE(pid >= 0);
354 if (pid == 0) {
355 /* Child. */
356 (void)close(socks[0]);
357 send_nvlist_child(socks[1]);
358 _exit(0);
359 }
360
361 (void)close(socks[1]);
362 send_nvlist_parent(socks[0]);
363
364 ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
365 ATF_REQUIRE(status == 0);
366 }
367
368 static void
nvlist_send_recv__send_closed_fd(short sotype)369 nvlist_send_recv__send_closed_fd(short sotype)
370 {
371 nvlist_t *nvl;
372 int socks[2];
373
374 ATF_REQUIRE(socketpair(PF_UNIX, sotype, 0, socks) == 0);
375
376 nvl = nvlist_create(0);
377 ATF_REQUIRE(nvl != NULL);
378 nvlist_add_descriptor(nvl, "fd", 12345);
379 ATF_REQUIRE(nvlist_error(nvl) == EBADF);
380
381 ATF_REQUIRE_ERRNO(EBADF, nvlist_send(socks[1], nvl) != 0);
382 }
383
384 static int
nopenfds(void)385 nopenfds(void)
386 {
387 size_t len;
388 int error, mib[4], n;
389
390 mib[0] = CTL_KERN;
391 mib[1] = KERN_PROC;
392 mib[2] = KERN_PROC_NFDS;
393 mib[3] = 0;
394
395 len = sizeof(n);
396 error = sysctl(mib, nitems(mib), &n, &len, NULL, 0);
397 if (error != 0)
398 return (-1);
399 return (n);
400 }
401
402 #define NFDS 512
403
404 static void
send_many_fds_child(int sock)405 send_many_fds_child(int sock)
406 {
407 char name[16];
408 nvlist_t *nvl;
409 int anfds, bnfds, fd, i, j;
410
411 fd = open(_PATH_DEVNULL, O_RDONLY);
412 ATF_REQUIRE(fd >= 0);
413
414 for (i = 1; i < NFDS; i++) {
415 nvl = nvlist_create(0);
416 bnfds = nopenfds();
417 if (bnfds == -1)
418 err(EXIT_FAILURE, "sysctl");
419
420 for (j = 0; j < i; j++) {
421 snprintf(name, sizeof(name), "fd%d", j);
422 nvlist_add_descriptor(nvl, name, fd);
423 }
424 nvlist_send(sock, nvl);
425 nvlist_destroy(nvl);
426
427 anfds = nopenfds();
428 if (anfds == -1)
429 err(EXIT_FAILURE, "sysctl");
430 if (anfds != bnfds)
431 errx(EXIT_FAILURE, "fd count mismatch");
432 }
433 }
434
435 static void
nvlist_send_recv__send_many_fds(short sotype)436 nvlist_send_recv__send_many_fds(short sotype)
437 {
438 char name[16];
439 nvlist_t *nvl;
440 int anfds, bnfds, fd, i, j, socks[2], status;
441 pid_t pid;
442
443 ATF_REQUIRE(socketpair(PF_UNIX, sotype, 0, socks) == 0);
444
445 pid = fork();
446 ATF_REQUIRE(pid >= 0);
447 if (pid == 0) {
448 /* Child. */
449 (void)close(socks[0]);
450 send_many_fds_child(socks[1]);
451 _exit(0);
452 }
453
454 (void)close(socks[1]);
455
456 for (i = 1; i < NFDS; i++) {
457 bnfds = nopenfds();
458 ATF_REQUIRE(bnfds != -1);
459
460 nvl = nvlist_recv(socks[0], 0);
461 ATF_REQUIRE(nvl != NULL);
462 for (j = 0; j < i; j++) {
463 snprintf(name, sizeof(name), "fd%d", j);
464 fd = nvlist_take_descriptor(nvl, name);
465 ATF_REQUIRE(close(fd) == 0);
466 }
467 nvlist_destroy(nvl);
468
469 anfds = nopenfds();
470 ATF_REQUIRE(anfds != -1);
471 ATF_REQUIRE(anfds == bnfds);
472 }
473
474 ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
475 ATF_REQUIRE(status == 0);
476 }
477
478 /*
479 * This test needs to tune the following sysctl's:
480 * net.local.dgram.maxdgram
481 * net.local.dgram.recvspace
482 */
483 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_many_fds__dgram);
ATF_TC_BODY(nvlist_send_recv__send_many_fds__dgram,tc)484 ATF_TC_BODY(nvlist_send_recv__send_many_fds__dgram, tc)
485 {
486 u_long maxdgram, recvspace, temp_maxdgram, temp_recvspace;
487 size_t len;
488 int error;
489
490 /* size of the largest datagram to send */
491 temp_maxdgram = 16772;
492 len = sizeof(maxdgram);
493 error = sysctlbyname("net.local.dgram.maxdgram", &maxdgram,
494 &len, &temp_maxdgram, sizeof(temp_maxdgram));
495 if (error != 0)
496 atf_tc_skip("cannot set net.local.dgram.maxdgram: %s", strerror(errno));
497
498 /*
499 * The receive queue fills up quicker than it's being emptied,
500 * bump it to a sufficiently large enough value, 1M.
501 */
502 temp_recvspace = 1048576;
503 len = sizeof(recvspace);
504 error = sysctlbyname("net.local.dgram.recvspace", &recvspace,
505 &len, &temp_recvspace, sizeof(temp_recvspace));
506 if (error != 0)
507 atf_tc_skip("cannot set net.local.dgram.recvspace: %s", strerror(errno));
508
509 nvlist_send_recv__send_many_fds(SOCK_DGRAM);
510
511 /* restore original values */
512 error = sysctlbyname("net.local.dgram.maxdgram", NULL, NULL, &maxdgram, sizeof(maxdgram));
513 if (error != 0)
514 warn("failed to restore net.local.dgram.maxdgram");
515
516 error = sysctlbyname("net.local.dgram.recvspace", NULL, NULL, &recvspace, sizeof(recvspace));
517 if (error != 0)
518 warn("failed to restore net.local.dgram.recvspace");
519 }
520
521 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_many_fds__stream);
ATF_TC_BODY(nvlist_send_recv__send_many_fds__stream,tc)522 ATF_TC_BODY(nvlist_send_recv__send_many_fds__stream, tc)
523 {
524 nvlist_send_recv__send_many_fds(SOCK_STREAM);
525 }
526
527 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_nvlist__dgram);
ATF_TC_BODY(nvlist_send_recv__send_nvlist__dgram,tc)528 ATF_TC_BODY(nvlist_send_recv__send_nvlist__dgram, tc)
529 {
530 nvlist_send_recv__send_nvlist(SOCK_DGRAM);
531 }
532
533 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_nvlist__stream);
ATF_TC_BODY(nvlist_send_recv__send_nvlist__stream,tc)534 ATF_TC_BODY(nvlist_send_recv__send_nvlist__stream, tc)
535 {
536 nvlist_send_recv__send_nvlist(SOCK_STREAM);
537 }
538
539 /*
540 * Regression test for fd_wait(): the previous select(2)-based implementation
541 * called FD_SET() unconditionally, which is an out-of-bounds stack write when
542 * the socket fd is >= FD_SETSIZE. Force the socketpair fds above FD_SETSIZE
543 * and verify a full nvlist round-trip still works.
544 */
545 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__highfd);
ATF_TC_BODY(nvlist_send_recv__highfd,tc)546 ATF_TC_BODY(nvlist_send_recv__highfd, tc)
547 {
548 struct rlimit rl;
549 nvlist_t *nvl;
550 int socks[2], hi_send, hi_recv, status;
551 pid_t pid;
552
553 hi_send = FD_SETSIZE + 5;
554 hi_recv = FD_SETSIZE + 6;
555
556 rl.rlim_cur = rl.rlim_max = hi_recv + 1;
557 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
558 atf_tc_skip("cannot raise RLIMIT_NOFILE: %s", strerror(errno));
559
560 ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, socks) == 0);
561 ATF_REQUIRE(dup2(socks[0], hi_recv) == hi_recv);
562 ATF_REQUIRE(dup2(socks[1], hi_send) == hi_send);
563 (void)close(socks[0]);
564 (void)close(socks[1]);
565
566 pid = fork();
567 ATF_REQUIRE(pid >= 0);
568 if (pid == 0) {
569 /* Child: send. */
570 (void)close(hi_recv);
571 nvl = nvlist_create(0);
572 nvlist_add_string(nvl, "key", "value");
573 if (nvlist_send(hi_send, nvl) != 0)
574 err(EXIT_FAILURE, "nvlist_send");
575 nvlist_destroy(nvl);
576 _exit(0);
577 }
578
579 (void)close(hi_send);
580 nvl = nvlist_recv(hi_recv, 0);
581 ATF_REQUIRE(nvl != NULL);
582 ATF_REQUIRE(nvlist_error(nvl) == 0);
583 ATF_REQUIRE(nvlist_exists_string(nvl, "key"));
584 ATF_REQUIRE(strcmp(nvlist_get_string(nvl, "key"), "value") == 0);
585 nvlist_destroy(nvl);
586
587 ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
588 ATF_REQUIRE(status == 0);
589 (void)close(hi_recv);
590 }
591
592 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_closed_fd__dgram);
ATF_TC_BODY(nvlist_send_recv__send_closed_fd__dgram,tc)593 ATF_TC_BODY(nvlist_send_recv__send_closed_fd__dgram, tc)
594 {
595 nvlist_send_recv__send_closed_fd(SOCK_DGRAM);
596 }
597
598 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_closed_fd__stream);
ATF_TC_BODY(nvlist_send_recv__send_closed_fd__stream,tc)599 ATF_TC_BODY(nvlist_send_recv__send_closed_fd__stream, tc)
600 {
601 nvlist_send_recv__send_closed_fd(SOCK_STREAM);
602 }
603
604 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__overflow_header_size);
ATF_TC_BODY(nvlist_send_recv__overflow_header_size,tc)605 ATF_TC_BODY(nvlist_send_recv__overflow_header_size, tc)
606 {
607 nvlist_t *nvl;
608 void *packed;
609 size_t packed_size;
610 struct nvlist_header *header;
611 int fd, socks[2], status;
612 pid_t pid;
613
614 #ifdef NO_ASAN
615 atf_tc_skip("This test requires ASAN");
616 #endif
617
618 ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0);
619
620 pid = fork();
621 ATF_REQUIRE(pid >= 0);
622
623 if (pid == 0) {
624 /* Child. */
625 fd = socks[0];
626 close(socks[1]);
627
628 nvl = nvlist_create(0);
629 ATF_REQUIRE(nvl != NULL);
630 ATF_REQUIRE(nvlist_empty(nvl));
631
632 packed = nvlist_pack(nvl, &packed_size);
633 ATF_REQUIRE(packed != NULL);
634 ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header));
635
636 header = (struct nvlist_header *)packed;
637 header->nvlh_size = SIZE_MAX - sizeof(struct nvlist_header) + 2;
638
639 ATF_REQUIRE_EQ(write(fd, packed, packed_size),
640 (ssize_t)sizeof(struct nvlist_header));
641
642 nvlist_destroy(nvl);
643 free(packed);
644
645 exit(0);
646 } else {
647 /* Parent */
648 fd = socks[1];
649 close(socks[0]);
650
651 errno = 0;
652 nvl = nvlist_recv(fd, 0);
653 ATF_REQUIRE(nvl == NULL);
654
655 /*
656 * Make sure it has failed on EINVAL, and not on
657 * errors returned by malloc or recv.
658 */
659 ATF_REQUIRE(errno == EINVAL);
660
661 ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
662 ATF_REQUIRE(status == 0);
663 close(fd);
664 }
665 }
666
667 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__overflow_big_endian_size);
ATF_TC_BODY(nvlist_send_recv__overflow_big_endian_size,tc)668 ATF_TC_BODY(nvlist_send_recv__overflow_big_endian_size, tc)
669 {
670 static const unsigned char payload[] = {
671 0x6c, /* magic */
672 0x00, /* version */
673 0x80, /* flags: NV_FLAG_BIG_ENDIAN */
674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5,
676 };
677 nvlist_t *nvl;
678 int sv[2];
679
680 ATF_REQUIRE_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0);
681 ATF_REQUIRE_EQ(write(sv[1], payload, sizeof(payload)),
682 (ssize_t)sizeof(payload));
683 ATF_REQUIRE_EQ(close(sv[1]), 0);
684
685 errno = 0;
686 nvl = nvlist_recv(sv[0], 0);
687 ATF_REQUIRE(nvl == NULL);
688 ATF_REQUIRE_EQ(errno, EINVAL);
689
690 ATF_REQUIRE_EQ(close(sv[0]), 0);
691 }
692
693 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__overflow_little_endian_size);
ATF_TC_BODY(nvlist_send_recv__overflow_little_endian_size,tc)694 ATF_TC_BODY(nvlist_send_recv__overflow_little_endian_size, tc)
695 {
696 static const unsigned char payload[] = {
697 0x6c, /* magic */
698 0x00, /* version */
699 0x00, /* flags */
700 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
702 };
703 nvlist_t *nvl;
704 int sv[2];
705
706 ATF_REQUIRE_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0);
707 ATF_REQUIRE_EQ(write(sv[1], payload, sizeof(payload)),
708 (ssize_t)sizeof(payload));
709 ATF_REQUIRE_EQ(close(sv[1]), 0);
710
711 errno = 0;
712 nvl = nvlist_recv(sv[0], 0);
713 ATF_REQUIRE(nvl == NULL);
714 ATF_REQUIRE_EQ(errno, EINVAL);
715
716 ATF_REQUIRE_EQ(close(sv[0]), 0);
717 }
718
719 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__invalid_fd_size);
ATF_TC_BODY(nvlist_send_recv__invalid_fd_size,tc)720 ATF_TC_BODY(nvlist_send_recv__invalid_fd_size, tc)
721 {
722 nvlist_t *nvl;
723 void *packed;
724 size_t packed_size;
725 struct nvlist_header *header;
726 int fd, socks[2], status;
727 pid_t pid;
728
729 ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0);
730
731 pid = fork();
732 ATF_REQUIRE(pid >= 0);
733
734 if (pid == 0) {
735 /* Child. */
736 fd = socks[0];
737 close(socks[1]);
738
739 nvl = nvlist_create(0);
740 ATF_REQUIRE(nvl != NULL);
741 ATF_REQUIRE(nvlist_empty(nvl));
742
743 nvlist_add_string(nvl, "nvl/string", "test");
744 ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
745
746 packed = nvlist_pack(nvl, &packed_size);
747 ATF_REQUIRE(packed != NULL);
748 ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header));
749
750 header = (struct nvlist_header *)packed;
751 header->nvlh_descriptors = 0x20;
752
753 ATF_REQUIRE_EQ(write(fd, packed, packed_size),
754 (ssize_t)packed_size);
755
756 nvlist_destroy(nvl);
757 free(packed);
758
759 exit(0);
760 } else {
761 /* Parent */
762 fd = socks[1];
763 close(socks[0]);
764
765 nvl = nvlist_recv(fd, 0);
766 ATF_REQUIRE(nvl == NULL);
767
768 ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
769 ATF_REQUIRE(status == 0);
770 }
771
772 close(fd);
773 }
774
775 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__overflow_fd_size);
ATF_TC_BODY(nvlist_send_recv__overflow_fd_size,tc)776 ATF_TC_BODY(nvlist_send_recv__overflow_fd_size, tc)
777 {
778 nvlist_t *nvl;
779 void *packed;
780 size_t packed_size;
781 struct nvlist_header *header;
782 int fd, socks[2], fds[1], status;
783 pid_t pid;
784
785 ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0);
786
787 pid = fork();
788 ATF_REQUIRE(pid >= 0);
789
790 if (pid == 0) {
791 /* Child. */
792 fd = socks[0];
793 close(socks[1]);
794
795 nvl = nvlist_create(0);
796 ATF_REQUIRE(nvl != NULL);
797 ATF_REQUIRE(nvlist_empty(nvl));
798
799 nvlist_add_string(nvl, "nvl/string", "test");
800 ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
801
802 packed = nvlist_pack(nvl, &packed_size);
803 ATF_REQUIRE(packed != NULL);
804 ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header));
805
806 header = (struct nvlist_header *)packed;
807 header->nvlh_descriptors = 0x4000000000000002;
808
809 ATF_REQUIRE_EQ(write(fd, packed, packed_size),
810 (ssize_t)packed_size);
811
812 fds[0] = dup(STDERR_FILENO);
813 ATF_REQUIRE(fds[0] >= 0);
814 ATF_REQUIRE_EQ(fd_send(fd, fds, 1), 0);
815
816 nvlist_destroy(nvl);
817 free(packed);
818
819 close(fds[0]);
820 close(fd);
821
822 exit(0);
823 } else {
824 /* Parent */
825 fd = socks[1];
826 close(socks[0]);
827
828 nvl = nvlist_recv(fd, 0);
829 ATF_REQUIRE(nvl == NULL);
830
831 /* Make sure that fd was not parsed by nvlist */
832 ATF_REQUIRE(fd_recv(fd, fds, 1) == 0);
833
834 ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
835 ATF_REQUIRE(status == 0);
836
837 close(fds[0]);
838 close(fd);
839 }
840 }
841
ATF_TP_ADD_TCS(tp)842 ATF_TP_ADD_TCS(tp)
843 {
844
845 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_nvlist__dgram);
846 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_nvlist__stream);
847 ATF_TP_ADD_TC(tp, nvlist_send_recv__highfd);
848 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_closed_fd__dgram);
849 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_closed_fd__stream);
850 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_many_fds__dgram);
851 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_many_fds__stream);
852
853 ATF_TP_ADD_TC(tp, nvlist_send_recv__overflow_header_size);
854 ATF_TP_ADD_TC(tp, nvlist_send_recv__overflow_big_endian_size);
855 ATF_TP_ADD_TC(tp, nvlist_send_recv__overflow_little_endian_size);
856 ATF_TP_ADD_TC(tp, nvlist_send_recv__invalid_fd_size);
857 ATF_TP_ADD_TC(tp, nvlist_send_recv__overflow_fd_size);
858
859 return (atf_no_error());
860 }
861