xref: /freebsd/lib/libnv/tests/nvlist_send_recv_test.c (revision e2219bbd634f673f774ddf118dfe19e531e08a45)
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