xref: /freebsd/lib/libnv/tests/nvlist_send_recv_test.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 /*-
2  * Copyright (c) 2013 The FreeBSD Foundation
3  *
4  * This software was developed by Pawel Jakub Dawidek under sponsorship from
5  * the FreeBSD Foundation.
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 AUTHORS 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 AUTHORS 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/sysctl.h>
32 #include <sys/wait.h>
33 #include <sys/nv.h>
34 
35 #include <stdlib.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <paths.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 #include <atf-c.h>
45 
46 #include <nv_impl.h>
47 #include <msgio.h>
48 
49 #define	ALPHABET	"abcdefghijklmnopqrstuvwxyz"
50 #define	fd_is_valid(fd)	(fcntl((fd), F_GETFL) != -1 || errno != EBADF)
51 
52 static void
53 send_nvlist_child(int sock)
54 {
55 	nvlist_t *nvl;
56 	nvlist_t *empty;
57 	int pfd[2];
58 
59 	nvl = nvlist_create(0);
60 	empty = nvlist_create(0);
61 
62 	nvlist_add_bool(nvl, "nvlist/bool/true", true);
63 	nvlist_add_bool(nvl, "nvlist/bool/false", false);
64 	nvlist_add_number(nvl, "nvlist/number/0", 0);
65 	nvlist_add_number(nvl, "nvlist/number/1", 1);
66 	nvlist_add_number(nvl, "nvlist/number/-1", -1);
67 	nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
68 	nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
69 	nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
70 	nvlist_add_string(nvl, "nvlist/string/", "");
71 	nvlist_add_string(nvl, "nvlist/string/x", "x");
72 	nvlist_add_string(nvl, "nvlist/string/" ALPHABET, ALPHABET);
73 
74 	nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO",
75 	    STDERR_FILENO);
76 	if (pipe(pfd) == -1)
77 		err(EXIT_FAILURE, "pipe");
78 	if (write(pfd[1], "test", 4) != 4)
79 		err(EXIT_FAILURE, "write");
80 	close(pfd[1]);
81 	nvlist_add_descriptor(nvl, "nvlist/descriptor/pipe_rd", pfd[0]);
82 	close(pfd[0]);
83 
84 	nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
85 	nvlist_add_binary(nvl, "nvlist/binary/" ALPHABET, ALPHABET,
86 	    sizeof(ALPHABET));
87 	nvlist_move_nvlist(nvl, "nvlist/nvlist/empty", empty);
88 	nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
89 
90 	nvlist_send(sock, nvl);
91 
92 	nvlist_destroy(nvl);
93 }
94 
95 static void
96 send_nvlist_parent(int sock)
97 {
98 	nvlist_t *nvl;
99 	const nvlist_t *cnvl, *empty;
100 	const char *name, *cname;
101 	void *cookie, *ccookie;
102 	int type, ctype, fd;
103 	size_t size;
104 	char buf[4];
105 
106 	nvl = nvlist_recv(sock, 0);
107 	ATF_REQUIRE(nvlist_error(nvl) == 0);
108 	if (nvlist_error(nvl) != 0)
109 		err(1, "nvlist_recv() failed");
110 
111 	cookie = NULL;
112 
113 	name = nvlist_next(nvl, &type, &cookie);
114 	ATF_REQUIRE(name != NULL);
115 	ATF_REQUIRE(type == NV_TYPE_BOOL);
116 	ATF_REQUIRE(strcmp(name, "nvlist/bool/true") == 0);
117 	ATF_REQUIRE(nvlist_get_bool(nvl, name) == true);
118 
119 	name = nvlist_next(nvl, &type, &cookie);
120 	ATF_REQUIRE(name != NULL);
121 	ATF_REQUIRE(type == NV_TYPE_BOOL);
122 	ATF_REQUIRE(strcmp(name, "nvlist/bool/false") == 0);
123 	ATF_REQUIRE(nvlist_get_bool(nvl, name) == false);
124 
125 	name = nvlist_next(nvl, &type, &cookie);
126 	ATF_REQUIRE(name != NULL);
127 	ATF_REQUIRE(type == NV_TYPE_NUMBER);
128 	ATF_REQUIRE(strcmp(name, "nvlist/number/0") == 0);
129 	ATF_REQUIRE(nvlist_get_number(nvl, name) == 0);
130 
131 	name = nvlist_next(nvl, &type, &cookie);
132 	ATF_REQUIRE(name != NULL);
133 	ATF_REQUIRE(type == NV_TYPE_NUMBER);
134 	ATF_REQUIRE(strcmp(name, "nvlist/number/1") == 0);
135 	ATF_REQUIRE(nvlist_get_number(nvl, name) == 1);
136 
137 	name = nvlist_next(nvl, &type, &cookie);
138 	ATF_REQUIRE(name != NULL);
139 	ATF_REQUIRE(type == NV_TYPE_NUMBER);
140 	ATF_REQUIRE(strcmp(name, "nvlist/number/-1") == 0);
141 	ATF_REQUIRE((int)nvlist_get_number(nvl, name) == -1);
142 
143 	name = nvlist_next(nvl, &type, &cookie);
144 	ATF_REQUIRE(name != NULL);
145 	ATF_REQUIRE(type == NV_TYPE_NUMBER);
146 	ATF_REQUIRE(strcmp(name, "nvlist/number/UINT64_MAX") == 0);
147 	ATF_REQUIRE(nvlist_get_number(nvl, name) == UINT64_MAX);
148 
149 	name = nvlist_next(nvl, &type, &cookie);
150 	ATF_REQUIRE(name != NULL);
151 	ATF_REQUIRE(type == NV_TYPE_NUMBER);
152 	ATF_REQUIRE(strcmp(name, "nvlist/number/INT64_MIN") == 0);
153 	ATF_REQUIRE((int64_t)nvlist_get_number(nvl, name) == INT64_MIN);
154 
155 	name = nvlist_next(nvl, &type, &cookie);
156 	ATF_REQUIRE(name != NULL);
157 	ATF_REQUIRE(type == NV_TYPE_NUMBER);
158 	ATF_REQUIRE(strcmp(name, "nvlist/number/INT64_MAX") == 0);
159 	ATF_REQUIRE((int64_t)nvlist_get_number(nvl, name) == INT64_MAX);
160 
161 	name = nvlist_next(nvl, &type, &cookie);
162 	ATF_REQUIRE(name != NULL);
163 	ATF_REQUIRE(type == NV_TYPE_STRING);
164 	ATF_REQUIRE(strcmp(name, "nvlist/string/") == 0);
165 	ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), "") == 0);
166 
167 	name = nvlist_next(nvl, &type, &cookie);
168 	ATF_REQUIRE(name != NULL);
169 	ATF_REQUIRE(type == NV_TYPE_STRING);
170 	ATF_REQUIRE(strcmp(name, "nvlist/string/x") == 0);
171 	ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), "x") == 0);
172 
173 	name = nvlist_next(nvl, &type, &cookie);
174 	ATF_REQUIRE(name != NULL);
175 	ATF_REQUIRE(type == NV_TYPE_STRING);
176 	ATF_REQUIRE(strcmp(name, "nvlist/string/" ALPHABET) == 0);
177 	ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), ALPHABET) == 0);
178 
179 	name = nvlist_next(nvl, &type, &cookie);
180 	ATF_REQUIRE(name != NULL);
181 	ATF_REQUIRE(type == NV_TYPE_DESCRIPTOR);
182 	ATF_REQUIRE(strcmp(name, "nvlist/descriptor/STDERR_FILENO") == 0);
183 	ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(nvl, name)));
184 
185 	name = nvlist_next(nvl, &type, &cookie);
186 	ATF_REQUIRE(name != NULL);
187 	ATF_REQUIRE(type == NV_TYPE_DESCRIPTOR);
188 	ATF_REQUIRE(strcmp(name, "nvlist/descriptor/pipe_rd") == 0);
189 	fd = nvlist_get_descriptor(nvl, name);
190 	ATF_REQUIRE(fd_is_valid(fd));
191 	ATF_REQUIRE(read(fd, buf, sizeof(buf)) == 4);
192 	ATF_REQUIRE(strncmp(buf, "test", sizeof(buf)) == 0);
193 
194 	name = nvlist_next(nvl, &type, &cookie);
195 	ATF_REQUIRE(name != NULL);
196 	ATF_REQUIRE(type == NV_TYPE_BINARY);
197 	ATF_REQUIRE(strcmp(name, "nvlist/binary/x") == 0);
198 	ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, NULL), "x", 1) == 0);
199 	ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, &size), "x", 1) == 0);
200 	ATF_REQUIRE(size == 1);
201 
202 	name = nvlist_next(nvl, &type, &cookie);
203 	ATF_REQUIRE(name != NULL);
204 	ATF_REQUIRE(type == NV_TYPE_BINARY);
205 	ATF_REQUIRE(strcmp(name, "nvlist/binary/" ALPHABET) == 0);
206 	ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, NULL), ALPHABET,
207 	    sizeof(ALPHABET)) == 0);
208 	ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, &size), ALPHABET,
209 	    sizeof(ALPHABET)) == 0);
210 	ATF_REQUIRE(size == sizeof(ALPHABET));
211 
212 	name = nvlist_next(nvl, &type, &cookie);
213 	ATF_REQUIRE(name != NULL);
214 	ATF_REQUIRE(type == NV_TYPE_NVLIST);
215 	ATF_REQUIRE(strcmp(name, "nvlist/nvlist/empty") == 0);
216 	cnvl = nvlist_get_nvlist(nvl, name);
217 	ATF_REQUIRE(nvlist_empty(cnvl));
218 
219 	name = nvlist_next(nvl, &type, &cookie);
220 	ATF_REQUIRE(name != NULL);
221 	ATF_REQUIRE(type == NV_TYPE_NVLIST);
222 	ATF_REQUIRE(strcmp(name, "nvlist/nvlist") == 0);
223 	cnvl = nvlist_get_nvlist(nvl, name);
224 
225 	ccookie = NULL;
226 
227 	cname = nvlist_next(cnvl, &ctype, &ccookie);
228 	ATF_REQUIRE(cname != NULL);
229 	ATF_REQUIRE(ctype == NV_TYPE_BOOL);
230 	ATF_REQUIRE(strcmp(cname, "nvlist/bool/true") == 0);
231 	ATF_REQUIRE(nvlist_get_bool(cnvl, cname) == true);
232 
233 	cname = nvlist_next(cnvl, &ctype, &ccookie);
234 	ATF_REQUIRE(cname != NULL);
235 	ATF_REQUIRE(ctype == NV_TYPE_BOOL);
236 	ATF_REQUIRE(strcmp(cname, "nvlist/bool/false") == 0);
237 	ATF_REQUIRE(nvlist_get_bool(cnvl, cname) == false);
238 
239 	cname = nvlist_next(cnvl, &ctype, &ccookie);
240 	ATF_REQUIRE(cname != NULL);
241 	ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
242 	ATF_REQUIRE(strcmp(cname, "nvlist/number/0") == 0);
243 	ATF_REQUIRE(nvlist_get_number(cnvl, cname) == 0);
244 
245 	cname = nvlist_next(cnvl, &ctype, &ccookie);
246 	ATF_REQUIRE(cname != NULL);
247 	ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
248 	ATF_REQUIRE(strcmp(cname, "nvlist/number/1") == 0);
249 	ATF_REQUIRE(nvlist_get_number(cnvl, cname) == 1);
250 
251 	cname = nvlist_next(cnvl, &ctype, &ccookie);
252 	ATF_REQUIRE(cname != NULL);
253 	ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
254 	ATF_REQUIRE(strcmp(cname, "nvlist/number/-1") == 0);
255 	ATF_REQUIRE((int)nvlist_get_number(cnvl, cname) == -1);
256 
257 	cname = nvlist_next(cnvl, &ctype, &ccookie);
258 	ATF_REQUIRE(cname != NULL);
259 	ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
260 	ATF_REQUIRE(strcmp(cname, "nvlist/number/UINT64_MAX") == 0);
261 	ATF_REQUIRE(nvlist_get_number(cnvl, cname) == UINT64_MAX);
262 
263 	cname = nvlist_next(cnvl, &ctype, &ccookie);
264 	ATF_REQUIRE(cname != NULL);
265 	ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
266 	ATF_REQUIRE(strcmp(cname, "nvlist/number/INT64_MIN") == 0);
267 	ATF_REQUIRE((int64_t)nvlist_get_number(cnvl, cname) == INT64_MIN);
268 
269 	cname = nvlist_next(cnvl, &ctype, &ccookie);
270 	ATF_REQUIRE(cname != NULL);
271 	ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
272 	ATF_REQUIRE(strcmp(cname, "nvlist/number/INT64_MAX") == 0);
273 	ATF_REQUIRE((int64_t)nvlist_get_number(cnvl, cname) == INT64_MAX);
274 
275 	cname = nvlist_next(cnvl, &ctype, &ccookie);
276 	ATF_REQUIRE(cname != NULL);
277 	ATF_REQUIRE(ctype == NV_TYPE_STRING);
278 	ATF_REQUIRE(strcmp(cname, "nvlist/string/") == 0);
279 	ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), "") == 0);
280 
281 	cname = nvlist_next(cnvl, &ctype, &ccookie);
282 	ATF_REQUIRE(cname != NULL);
283 	ATF_REQUIRE(ctype == NV_TYPE_STRING);
284 	ATF_REQUIRE(strcmp(cname, "nvlist/string/x") == 0);
285 	ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), "x") == 0);
286 
287 	cname = nvlist_next(cnvl, &ctype, &ccookie);
288 	ATF_REQUIRE(cname != NULL);
289 	ATF_REQUIRE(ctype == NV_TYPE_STRING);
290 	ATF_REQUIRE(strcmp(cname, "nvlist/string/" ALPHABET) == 0);
291 	ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), ALPHABET) == 0);
292 
293 	cname = nvlist_next(cnvl, &ctype, &ccookie);
294 	ATF_REQUIRE(cname != NULL);
295 	ATF_REQUIRE(ctype == NV_TYPE_DESCRIPTOR);
296 	ATF_REQUIRE(strcmp(cname, "nvlist/descriptor/STDERR_FILENO") == 0);
297 	ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
298 
299 	cname = nvlist_next(cnvl, &ctype, &ccookie);
300 	ATF_REQUIRE(cname != NULL);
301 	ATF_REQUIRE(ctype == NV_TYPE_DESCRIPTOR);
302 	ATF_REQUIRE(strcmp(cname, "nvlist/descriptor/pipe_rd") == 0);
303 	ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
304 
305 	cname = nvlist_next(cnvl, &ctype, &ccookie);
306 	ATF_REQUIRE(cname != NULL);
307 	ATF_REQUIRE(ctype == NV_TYPE_BINARY);
308 	ATF_REQUIRE(strcmp(cname, "nvlist/binary/x") == 0);
309 	ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, NULL), "x", 1) == 0);
310 	ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, &size), "x", 1) == 0);
311 	ATF_REQUIRE(size == 1);
312 
313 	cname = nvlist_next(cnvl, &ctype, &ccookie);
314 	ATF_REQUIRE(cname != NULL);
315 	ATF_REQUIRE(ctype == NV_TYPE_BINARY);
316 	ATF_REQUIRE(strcmp(cname, "nvlist/binary/" ALPHABET) == 0);
317 	ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, NULL), ALPHABET,
318 	    sizeof(ALPHABET)) == 0);
319 	ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, &size), ALPHABET,
320 	    sizeof(ALPHABET)) == 0);
321 	ATF_REQUIRE(size == sizeof(ALPHABET));
322 
323 	cname = nvlist_next(cnvl, &ctype, &ccookie);
324 	ATF_REQUIRE(cname != NULL);
325 	ATF_REQUIRE(ctype == NV_TYPE_NVLIST);
326 	ATF_REQUIRE(strcmp(cname, "nvlist/nvlist/empty") == 0);
327 	empty = nvlist_get_nvlist(cnvl, cname);
328 	ATF_REQUIRE(nvlist_empty(empty));
329 
330 	cname = nvlist_next(cnvl, &ctype, &ccookie);
331 	ATF_REQUIRE(cname == NULL);
332 
333 	name = nvlist_next(nvl, &type, &cookie);
334 	ATF_REQUIRE(name == NULL);
335 
336 	nvlist_destroy(nvl);
337 }
338 
339 static void
340 nvlist_send_recv__send_nvlist(short sotype)
341 {
342 	int socks[2], status;
343 	pid_t pid;
344 
345 	ATF_REQUIRE(socketpair(PF_UNIX, sotype, 0, socks) == 0);
346 
347 	pid = fork();
348 	ATF_REQUIRE(pid >= 0);
349 	if (pid == 0) {
350 		/* Child. */
351 		(void)close(socks[0]);
352 		send_nvlist_child(socks[1]);
353 		_exit(0);
354 	}
355 
356 	(void)close(socks[1]);
357 	send_nvlist_parent(socks[0]);
358 
359 	ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
360 	ATF_REQUIRE(status == 0);
361 }
362 
363 static void
364 nvlist_send_recv__send_closed_fd(short sotype)
365 {
366 	nvlist_t *nvl;
367 	int socks[2];
368 
369 	ATF_REQUIRE(socketpair(PF_UNIX, sotype, 0, socks) == 0);
370 
371 	nvl = nvlist_create(0);
372 	ATF_REQUIRE(nvl != NULL);
373 	nvlist_add_descriptor(nvl, "fd", 12345);
374 	ATF_REQUIRE(nvlist_error(nvl) == EBADF);
375 
376 	ATF_REQUIRE_ERRNO(EBADF, nvlist_send(socks[1], nvl) != 0);
377 }
378 
379 static int
380 nopenfds(void)
381 {
382 	size_t len;
383 	int error, mib[4], n;
384 
385 	mib[0] = CTL_KERN;
386 	mib[1] = KERN_PROC;
387 	mib[2] = KERN_PROC_NFDS;
388 	mib[3] = 0;
389 
390 	len = sizeof(n);
391 	error = sysctl(mib, nitems(mib), &n, &len, NULL, 0);
392 	if (error != 0)
393 		return (-1);
394 	return (n);
395 }
396 
397 #define	NFDS	512
398 
399 static void
400 send_many_fds_child(int sock)
401 {
402 	char name[16];
403 	nvlist_t *nvl;
404 	int anfds, bnfds, fd, i, j;
405 
406 	fd = open(_PATH_DEVNULL, O_RDONLY);
407 	ATF_REQUIRE(fd >= 0);
408 
409 	for (i = 1; i < NFDS; i++) {
410 		nvl = nvlist_create(0);
411 		bnfds = nopenfds();
412 		if (bnfds == -1)
413 			err(EXIT_FAILURE, "sysctl");
414 
415 		for (j = 0; j < i; j++) {
416 			snprintf(name, sizeof(name), "fd%d", j);
417 			nvlist_add_descriptor(nvl, name, fd);
418 		}
419 		nvlist_send(sock, nvl);
420 		nvlist_destroy(nvl);
421 
422 		anfds = nopenfds();
423 		if (anfds == -1)
424 			err(EXIT_FAILURE, "sysctl");
425 		if (anfds != bnfds)
426 			errx(EXIT_FAILURE, "fd count mismatch");
427 	}
428 }
429 
430 static void
431 nvlist_send_recv__send_many_fds(short sotype)
432 {
433 	char name[16];
434 	nvlist_t *nvl;
435 	int anfds, bnfds, fd, i, j, socks[2], status;
436 	pid_t pid;
437 
438 	ATF_REQUIRE(socketpair(PF_UNIX, sotype, 0, socks) == 0);
439 
440 	pid = fork();
441 	ATF_REQUIRE(pid >= 0);
442 	if (pid == 0) {
443 		/* Child. */
444 		(void)close(socks[0]);
445 		send_many_fds_child(socks[1]);
446 		_exit(0);
447 	}
448 
449 	(void)close(socks[1]);
450 
451 	for (i = 1; i < NFDS; i++) {
452 		bnfds = nopenfds();
453 		ATF_REQUIRE(bnfds != -1);
454 
455 		nvl = nvlist_recv(socks[0], 0);
456 		ATF_REQUIRE(nvl != NULL);
457 		for (j = 0; j < i; j++) {
458 			snprintf(name, sizeof(name), "fd%d", j);
459 			fd = nvlist_take_descriptor(nvl, name);
460 			ATF_REQUIRE(close(fd) == 0);
461 		}
462 		nvlist_destroy(nvl);
463 
464 		anfds = nopenfds();
465 		ATF_REQUIRE(anfds != -1);
466 		ATF_REQUIRE(anfds == bnfds);
467 	}
468 
469 	ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
470 	ATF_REQUIRE(status == 0);
471 }
472 
473 /*
474  * This test needs to tune the following sysctl's:
475  *      net.local.dgram.maxdgram
476  *      net.local.dgram.recvspace
477  */
478 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_many_fds__dgram);
479 ATF_TC_BODY(nvlist_send_recv__send_many_fds__dgram, tc)
480 {
481 	u_long maxdgram, recvspace, temp_maxdgram, temp_recvspace;
482 	size_t len;
483 	int error;
484 
485 	atf_tc_skip("https://bugs.freebsd.org/260891");
486 
487 	/* size of the largest datagram to send */
488 	temp_maxdgram = 16772;
489 	len = sizeof(maxdgram);
490 	error = sysctlbyname("net.local.dgram.maxdgram", &maxdgram,
491 	    &len, &temp_maxdgram, sizeof(temp_maxdgram));
492 	if (error != 0)
493 		atf_tc_skip("cannot set net.local.dgram.maxdgram: %s", strerror(errno));
494 
495 	/*
496 	 * The receive queue fills up quicker than it's being emptied,
497 	 * bump it to a sufficiently large enough value, 1M.
498 	 */
499 	temp_recvspace = 1048576;
500 	len = sizeof(recvspace);
501 	error = sysctlbyname("net.local.dgram.recvspace", &recvspace,
502 	    &len, &temp_recvspace, sizeof(temp_recvspace));
503 	if (error != 0)
504 		atf_tc_skip("cannot set net.local.dgram.recvspace: %s", strerror(errno));
505 
506 	nvlist_send_recv__send_many_fds(SOCK_DGRAM);
507 
508 	/* restore original values */
509 	error = sysctlbyname("net.local.dgram.maxdgram", NULL, NULL, &maxdgram, sizeof(maxdgram));
510 	if (error != 0)
511 		warn("failed to restore net.local.dgram.maxdgram");
512 
513 	error = sysctlbyname("net.local.dgram.recvspace", NULL, NULL, &recvspace, sizeof(recvspace));
514 	if (error != 0)
515 		warn("failed to restore net.local.dgram.recvspace");
516 }
517 
518 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_many_fds__stream);
519 ATF_TC_BODY(nvlist_send_recv__send_many_fds__stream, tc)
520 {
521 	nvlist_send_recv__send_many_fds(SOCK_STREAM);
522 }
523 
524 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_nvlist__dgram);
525 ATF_TC_BODY(nvlist_send_recv__send_nvlist__dgram, tc)
526 {
527 	nvlist_send_recv__send_nvlist(SOCK_DGRAM);
528 }
529 
530 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_nvlist__stream);
531 ATF_TC_BODY(nvlist_send_recv__send_nvlist__stream, tc)
532 {
533 	nvlist_send_recv__send_nvlist(SOCK_STREAM);
534 }
535 
536 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_closed_fd__dgram);
537 ATF_TC_BODY(nvlist_send_recv__send_closed_fd__dgram, tc)
538 {
539 	nvlist_send_recv__send_closed_fd(SOCK_DGRAM);
540 }
541 
542 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_closed_fd__stream);
543 ATF_TC_BODY(nvlist_send_recv__send_closed_fd__stream, tc)
544 {
545 	nvlist_send_recv__send_closed_fd(SOCK_STREAM);
546 }
547 
548 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__overflow_header_size);
549 ATF_TC_BODY(nvlist_send_recv__overflow_header_size, tc)
550 {
551 	nvlist_t *nvl;
552 	void *packed;
553 	size_t packed_size;
554 	struct nvlist_header *header;
555 	int fd, socks[2], status;
556 	pid_t pid;
557 
558 #ifdef NO_ASAN
559 	atf_tc_skip("This test requires ASAN");
560 #endif
561 
562 	ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0);
563 
564 	pid = fork();
565 	ATF_REQUIRE(pid >= 0);
566 
567 	if (pid == 0) {
568 		/* Child. */
569 		fd = socks[0];
570 		close(socks[1]);
571 
572 		nvl = nvlist_create(0);
573 		ATF_REQUIRE(nvl != NULL);
574 		ATF_REQUIRE(nvlist_empty(nvl));
575 
576 		packed = nvlist_pack(nvl, &packed_size);
577 		ATF_REQUIRE(packed != NULL);
578 		ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header));
579 
580 		header = (struct nvlist_header *)packed;
581 		header->nvlh_size = SIZE_MAX - sizeof(struct nvlist_header) + 2;
582 
583 		ATF_REQUIRE_EQ(write(fd, packed, packed_size),
584 		    (ssize_t)sizeof(struct nvlist_header));
585 
586 		nvlist_destroy(nvl);
587 		free(packed);
588 
589 		exit(0);
590 	} else {
591 		/* Parent */
592 		fd = socks[1];
593 		close(socks[0]);
594 
595 		errno = 0;
596 		nvl = nvlist_recv(fd, 0);
597 		ATF_REQUIRE(nvl == NULL);
598 
599 		/*
600 		 * Make sure it has failed on EINVAL, and not on
601 		 * errors returned by malloc or recv.
602 		 */
603 		ATF_REQUIRE(errno == EINVAL);
604 
605 		ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
606 		ATF_REQUIRE(status == 0);
607 		close(fd);
608 	}
609 }
610 
611 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__invalid_fd_size);
612 ATF_TC_BODY(nvlist_send_recv__invalid_fd_size, tc)
613 {
614 	nvlist_t *nvl;
615 	void *packed;
616 	size_t packed_size;
617 	struct nvlist_header *header;
618 	int fd, socks[2], status;
619 	pid_t pid;
620 
621 	ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0);
622 
623 	pid = fork();
624 	ATF_REQUIRE(pid >= 0);
625 
626 	if (pid == 0) {
627 		/* Child. */
628 		fd = socks[0];
629 		close(socks[1]);
630 
631 		nvl = nvlist_create(0);
632 		ATF_REQUIRE(nvl != NULL);
633 		ATF_REQUIRE(nvlist_empty(nvl));
634 
635 		nvlist_add_string(nvl, "nvl/string", "test");
636 		ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
637 
638 		packed = nvlist_pack(nvl, &packed_size);
639 		ATF_REQUIRE(packed != NULL);
640 		ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header));
641 
642 		header = (struct nvlist_header *)packed;
643 		header->nvlh_descriptors = 0x20;
644 
645 		ATF_REQUIRE_EQ(write(fd, packed, packed_size),
646 		    (ssize_t)packed_size);
647 
648 		nvlist_destroy(nvl);
649 		free(packed);
650 
651 		exit(0);
652 	} else {
653 		/* Parent */
654 		fd = socks[1];
655 		close(socks[0]);
656 
657 		nvl = nvlist_recv(fd, 0);
658 		ATF_REQUIRE(nvl == NULL);
659 
660 		ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
661 		ATF_REQUIRE(status == 0);
662 	}
663 
664 	close(fd);
665 }
666 
667 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__overflow_fd_size);
668 ATF_TC_BODY(nvlist_send_recv__overflow_fd_size, tc)
669 {
670 	nvlist_t *nvl;
671 	void *packed;
672 	size_t packed_size;
673 	struct nvlist_header *header;
674 	int fd, socks[2], fds[1], status;
675 	pid_t pid;
676 
677 	ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0);
678 
679 	pid = fork();
680 	ATF_REQUIRE(pid >= 0);
681 
682 	if (pid == 0) {
683 		/* Child. */
684 		fd = socks[0];
685 		close(socks[1]);
686 
687 		nvl = nvlist_create(0);
688 		ATF_REQUIRE(nvl != NULL);
689 		ATF_REQUIRE(nvlist_empty(nvl));
690 
691 		nvlist_add_string(nvl, "nvl/string", "test");
692 		ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
693 
694 		packed = nvlist_pack(nvl, &packed_size);
695 		ATF_REQUIRE(packed != NULL);
696 		ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header));
697 
698 		header = (struct nvlist_header *)packed;
699 		header->nvlh_descriptors = 0x4000000000000002;
700 
701 		ATF_REQUIRE_EQ(write(fd, packed, packed_size),
702 		    (ssize_t)packed_size);
703 
704 		fds[0] = dup(STDERR_FILENO);
705 		ATF_REQUIRE(fds[0] >= 0);
706 		ATF_REQUIRE_EQ(fd_send(fd, fds, 1), 0);
707 
708 		nvlist_destroy(nvl);
709 		free(packed);
710 
711 		close(fds[0]);
712 		close(fd);
713 
714 		exit(0);
715 	} else {
716 		/* Parent */
717 		fd = socks[1];
718 		close(socks[0]);
719 
720 		nvl = nvlist_recv(fd, 0);
721 		ATF_REQUIRE(nvl == NULL);
722 
723 		/* Make sure that fd was not parsed by nvlist */
724 		ATF_REQUIRE(fd_recv(fd, fds, 1) == 0);
725 
726 		ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
727 		ATF_REQUIRE(status == 0);
728 
729 		close(fds[0]);
730 		close(fd);
731 	}
732 }
733 
734 ATF_TP_ADD_TCS(tp)
735 {
736 
737 	ATF_TP_ADD_TC(tp, nvlist_send_recv__send_nvlist__dgram);
738 	ATF_TP_ADD_TC(tp, nvlist_send_recv__send_nvlist__stream);
739 	ATF_TP_ADD_TC(tp, nvlist_send_recv__send_closed_fd__dgram);
740 	ATF_TP_ADD_TC(tp, nvlist_send_recv__send_closed_fd__stream);
741 	ATF_TP_ADD_TC(tp, nvlist_send_recv__send_many_fds__dgram);
742 	ATF_TP_ADD_TC(tp, nvlist_send_recv__send_many_fds__stream);
743 
744 	ATF_TP_ADD_TC(tp, nvlist_send_recv__overflow_header_size);
745 	ATF_TP_ADD_TC(tp, nvlist_send_recv__invalid_fd_size);
746 	ATF_TP_ADD_TC(tp, nvlist_send_recv__overflow_fd_size);
747 
748 	return (atf_no_error());
749 }
750