1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2020-2021 Kyle Evans <kevans@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/param.h>
29#include <sys/cpuset.h>
30#include <sys/jail.h>
31#include <sys/procdesc.h>
32#include <sys/select.h>
33#include <sys/socket.h>
34#include <sys/uio.h>
35#include <sys/wait.h>
36
37#include <errno.h>
38#include <stdio.h>
39#include <unistd.h>
40
41#include <atf-c.h>
42
43#define	SP_PARENT	0
44#define	SP_CHILD	1
45
46struct jail_test_info {
47	cpuset_t	jail_tidmask;
48	cpusetid_t	jail_cpuset;
49	cpusetid_t	jail_child_cpuset;
50};
51
52struct jail_test_cb_params {
53	struct jail_test_info		info;
54	cpuset_t			mask;
55	cpusetid_t			rootid;
56	cpusetid_t			setid;
57};
58
59typedef void (*jail_test_cb)(struct jail_test_cb_params *);
60
61#define	FAILURE_JAIL	42
62#define	FAILURE_MASK	43
63#define	FAILURE_JAILSET	44
64#define	FAILURE_PIDSET	45
65#define	FAILURE_SEND	46
66#define	FAILURE_DEADLK	47
67#define	FAILURE_ATTACH	48
68#define	FAILURE_BADAFFIN	49
69#define	FAILURE_SUCCESS	50
70
71static const char *
72do_jail_errstr(int error)
73{
74
75	switch (error) {
76	case FAILURE_JAIL:
77		return ("jail_set(2) failed");
78	case FAILURE_MASK:
79		return ("Failed to get the thread cpuset mask");
80	case FAILURE_JAILSET:
81		return ("Failed to get the jail setid");
82	case FAILURE_PIDSET:
83		return ("Failed to get the pid setid");
84	case FAILURE_SEND:
85		return ("Failed to send(2) cpuset information");
86	case FAILURE_DEADLK:
87		return ("Deadlock hit trying to attach to jail");
88	case FAILURE_ATTACH:
89		return ("jail_attach(2) failed");
90	case FAILURE_BADAFFIN:
91		return ("Unexpected post-attach affinity");
92	case FAILURE_SUCCESS:
93		return ("jail_attach(2) succeeded, but should have failed.");
94	default:
95		return (NULL);
96	}
97}
98
99static void
100skip_ltncpu(int ncpu, cpuset_t *mask)
101{
102
103	CPU_ZERO(mask);
104	ATF_REQUIRE_EQ(0, cpuset_getaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID,
105	    -1, sizeof(*mask), mask));
106	if (CPU_COUNT(mask) < ncpu)
107		atf_tc_skip("Test requires %d or more cores.", ncpu);
108}
109
110ATF_TC(newset);
111ATF_TC_HEAD(newset, tc)
112{
113	atf_tc_set_md_var(tc, "descr", "Test cpuset(2)");
114}
115ATF_TC_BODY(newset, tc)
116{
117	cpusetid_t nsetid, setid, qsetid;
118
119	/* Obtain our initial set id. */
120	ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1,
121	    &setid));
122
123	/* Create a new one. */
124	ATF_REQUIRE_EQ(0, cpuset(&nsetid));
125	ATF_CHECK(nsetid != setid);
126
127	/* Query id again, make sure it's equal to the one we just got. */
128	ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1,
129	    &qsetid));
130	ATF_CHECK_EQ(nsetid, qsetid);
131}
132
133ATF_TC(transient);
134ATF_TC_HEAD(transient, tc)
135{
136	atf_tc_set_md_var(tc, "descr",
137	   "Test that transient cpusets are freed.");
138}
139ATF_TC_BODY(transient, tc)
140{
141	cpusetid_t isetid, scratch, setid;
142
143	ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1,
144	    &isetid));
145
146	ATF_REQUIRE_EQ(0, cpuset(&setid));
147	ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET,
148	    setid, &scratch));
149
150	/*
151	 * Return back to our initial cpuset; the kernel should free the cpuset
152	 * we just created.
153	 */
154	ATF_REQUIRE_EQ(0, cpuset_setid(CPU_WHICH_PID, -1, isetid));
155	ATF_REQUIRE_EQ(-1, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET,
156	    setid, &scratch));
157	ATF_CHECK_EQ(ESRCH, errno);
158}
159
160ATF_TC(deadlk);
161ATF_TC_HEAD(deadlk, tc)
162{
163	atf_tc_set_md_var(tc, "descr", "Test against disjoint cpusets.");
164	atf_tc_set_md_var(tc, "require.user", "root");
165}
166ATF_TC_BODY(deadlk, tc)
167{
168	cpusetid_t setid;
169	cpuset_t dismask, mask, omask;
170	int fcpu, i, found, ncpu, second;
171
172	/* Make sure we have 3 cpus, so we test partial overlap. */
173	skip_ltncpu(3, &omask);
174
175	ATF_REQUIRE_EQ(0, cpuset(&setid));
176	CPU_ZERO(&mask);
177	CPU_ZERO(&dismask);
178	CPU_COPY(&omask, &mask);
179	CPU_COPY(&omask, &dismask);
180	fcpu = CPU_FFS(&mask);
181	ncpu = CPU_COUNT(&mask);
182
183	/*
184	 * Turn off all but the first two for mask, turn off the first for
185	 * dismask and turn them all off for both after the third.
186	 */
187	for (i = fcpu - 1, found = 0; i < CPU_MAXSIZE && found != ncpu; i++) {
188		if (CPU_ISSET(i, &omask)) {
189			found++;
190			if (found == 1) {
191				CPU_CLR(i, &dismask);
192			} else if (found == 2) {
193				second = i;
194			} else if (found >= 3) {
195				CPU_CLR(i, &mask);
196				if (found > 3)
197					CPU_CLR(i, &dismask);
198			}
199		}
200	}
201
202	ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID,
203	    -1, sizeof(mask), &mask));
204
205	/* Must be a strict subset! */
206	ATF_REQUIRE_EQ(-1, cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
207	    -1, sizeof(dismask), &dismask));
208	ATF_REQUIRE_EQ(EINVAL, errno);
209
210	/*
211	 * We'll set our anonymous set to the 0,1 set that currently matches
212	 * the process.  If we then set the process to the 1,2 set that's in
213	 * dismask, we should then personally be restricted down to the single
214	 * overlapping CPOU.
215	 */
216	ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
217	    -1, sizeof(mask), &mask));
218	ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID,
219	    -1, sizeof(dismask), &dismask));
220	ATF_REQUIRE_EQ(0, cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
221	    -1, sizeof(mask), &mask));
222	ATF_REQUIRE_EQ(1, CPU_COUNT(&mask));
223	ATF_REQUIRE(CPU_ISSET(second, &mask));
224
225	/*
226	 * Finally, clearing the overlap and attempting to set the process
227	 * cpuset to a completely disjoint mask should fail, because this
228	 * process will then not have anything to run on.
229	 */
230	CPU_CLR(second, &dismask);
231	ATF_REQUIRE_EQ(-1, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID,
232	    -1, sizeof(dismask), &dismask));
233	ATF_REQUIRE_EQ(EDEADLK, errno);
234}
235
236static int
237do_jail(int sock)
238{
239	struct jail_test_info info;
240	struct iovec iov[2];
241	char *name;
242	int error;
243
244	if (asprintf(&name, "cpuset_%d", getpid()) == -1)
245		_exit(42);
246
247	iov[0].iov_base = "name";
248	iov[0].iov_len = 5;
249
250	iov[1].iov_base = name;
251	iov[1].iov_len = strlen(name) + 1;
252
253	if (jail_set(iov, 2, JAIL_CREATE | JAIL_ATTACH) < 0)
254		return (FAILURE_JAIL);
255
256	/* Record parameters, kick them over, then make a swift exit. */
257	CPU_ZERO(&info.jail_tidmask);
258	error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
259	    -1, sizeof(info.jail_tidmask), &info.jail_tidmask);
260	if (error != 0)
261		return (FAILURE_MASK);
262
263	error = cpuset_getid(CPU_LEVEL_ROOT, CPU_WHICH_TID, -1,
264	    &info.jail_cpuset);
265	if (error != 0)
266		return (FAILURE_JAILSET);
267	error = cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1,
268	    &info.jail_child_cpuset);
269	if (error != 0)
270		return (FAILURE_PIDSET);
271	if (send(sock, &info, sizeof(info), 0) != sizeof(info))
272		return (FAILURE_SEND);
273	return (0);
274}
275
276static void
277do_jail_test(int ncpu, bool newset, jail_test_cb prologue,
278    jail_test_cb epilogue)
279{
280	struct jail_test_cb_params cbp;
281	const char *errstr;
282	pid_t pid;
283	int error, sock, sockpair[2], status;
284
285	memset(&cbp.info, '\0', sizeof(cbp.info));
286
287	skip_ltncpu(ncpu, &cbp.mask);
288
289	ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
290	    &cbp.rootid));
291	if (newset)
292		ATF_REQUIRE_EQ(0, cpuset(&cbp.setid));
293	else
294		ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_PID,
295		    -1, &cbp.setid));
296	/* Special hack for prison0; it uses cpuset 1 as the root. */
297	if (cbp.rootid == 0)
298		cbp.rootid = 1;
299
300	/* Not every test needs early setup. */
301	if (prologue != NULL)
302		(*prologue)(&cbp);
303
304	ATF_REQUIRE_EQ(0, socketpair(PF_UNIX, SOCK_STREAM, 0, sockpair));
305	ATF_REQUIRE((pid = fork()) != -1);
306
307	if (pid == 0) {
308		/* Child */
309		close(sockpair[SP_PARENT]);
310		sock = sockpair[SP_CHILD];
311
312		_exit(do_jail(sock));
313	} else {
314		/* Parent */
315		sock = sockpair[SP_PARENT];
316		close(sockpair[SP_CHILD]);
317
318		while ((error = waitpid(pid, &status, 0)) == -1 &&
319		    errno == EINTR) {
320		}
321
322		ATF_REQUIRE_EQ(sizeof(cbp.info), recv(sock, &cbp.info,
323		    sizeof(cbp.info), 0));
324
325		/* Sanity check the exit info. */
326		ATF_REQUIRE_EQ(pid, error);
327		ATF_REQUIRE(WIFEXITED(status));
328		if (WEXITSTATUS(status) != 0) {
329			errstr = do_jail_errstr(WEXITSTATUS(status));
330			if (errstr != NULL)
331				atf_tc_fail("%s", errstr);
332			else
333				atf_tc_fail("Unknown error '%d'",
334				    WEXITSTATUS(status));
335		}
336
337		epilogue(&cbp);
338	}
339}
340
341static void
342jail_attach_mutate_pro(struct jail_test_cb_params *cbp)
343{
344	cpuset_t *mask;
345	int count;
346
347	mask = &cbp->mask;
348
349	/* Knock out the first cpu. */
350	count = CPU_COUNT(mask);
351	CPU_CLR(CPU_FFS(mask) - 1, mask);
352	ATF_REQUIRE_EQ(count - 1, CPU_COUNT(mask));
353	ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
354	    -1, sizeof(*mask), mask));
355}
356
357static void
358jail_attach_newbase_epi(struct jail_test_cb_params *cbp)
359{
360	struct jail_test_info *info;
361	cpuset_t *mask;
362
363	info = &cbp->info;
364	mask = &cbp->mask;
365
366	/*
367	 * The rootid test has been thrown in because a bug was discovered
368	 * where any newly derived cpuset during attach would be parented to
369	 * the wrong cpuset.  Otherwise, we should observe that a new cpuset
370	 * has been created for this process.
371	 */
372	ATF_REQUIRE(info->jail_cpuset != cbp->rootid);
373	ATF_REQUIRE(info->jail_cpuset != cbp->setid);
374	ATF_REQUIRE(info->jail_cpuset != info->jail_child_cpuset);
375	ATF_REQUIRE_EQ(0, CPU_CMP(mask, &info->jail_tidmask));
376}
377
378ATF_TC(jail_attach_newbase);
379ATF_TC_HEAD(jail_attach_newbase, tc)
380{
381	atf_tc_set_md_var(tc, "descr",
382	    "Test jail attachment effect on affinity with a new base cpuset.");
383	atf_tc_set_md_var(tc, "require.user", "root");
384}
385ATF_TC_BODY(jail_attach_newbase, tc)
386{
387
388	/* Need >= 2 cpus to test restriction. */
389	do_jail_test(2, true, &jail_attach_mutate_pro,
390	    &jail_attach_newbase_epi);
391}
392
393ATF_TC(jail_attach_newbase_plain);
394ATF_TC_HEAD(jail_attach_newbase_plain, tc)
395{
396	atf_tc_set_md_var(tc, "descr",
397	    "Test jail attachment effect on affinity with a new, unmodified base cpuset.");
398	atf_tc_set_md_var(tc, "require.user", "root");
399}
400ATF_TC_BODY(jail_attach_newbase_plain, tc)
401{
402
403	do_jail_test(2, true, NULL, &jail_attach_newbase_epi);
404}
405
406/*
407 * Generic epilogue for tests that are expecting to use the jail's root cpuset
408 * with their own mask, whether that's been modified or not.
409 */
410static void
411jail_attach_jset_epi(struct jail_test_cb_params *cbp)
412{
413	struct jail_test_info *info;
414	cpuset_t *mask;
415
416	info = &cbp->info;
417	mask = &cbp->mask;
418
419	ATF_REQUIRE(info->jail_cpuset != cbp->setid);
420	ATF_REQUIRE_EQ(info->jail_cpuset, info->jail_child_cpuset);
421	ATF_REQUIRE_EQ(0, CPU_CMP(mask, &info->jail_tidmask));
422}
423
424ATF_TC(jail_attach_prevbase);
425ATF_TC_HEAD(jail_attach_prevbase, tc)
426{
427	atf_tc_set_md_var(tc, "descr",
428	    "Test jail attachment effect on affinity without a new base.");
429	atf_tc_set_md_var(tc, "require.user", "root");
430}
431ATF_TC_BODY(jail_attach_prevbase, tc)
432{
433
434	do_jail_test(2, false, &jail_attach_mutate_pro, &jail_attach_jset_epi);
435}
436
437static void
438jail_attach_plain_pro(struct jail_test_cb_params *cbp)
439{
440
441	if (cbp->setid != cbp->rootid)
442		atf_tc_skip("Must be running with the root cpuset.");
443}
444
445ATF_TC(jail_attach_plain);
446ATF_TC_HEAD(jail_attach_plain, tc)
447{
448	atf_tc_set_md_var(tc, "descr",
449	    "Test jail attachment effect on affinity without specialization.");
450	atf_tc_set_md_var(tc, "require.user", "root");
451}
452ATF_TC_BODY(jail_attach_plain, tc)
453{
454
455	do_jail_test(1, false, &jail_attach_plain_pro, &jail_attach_jset_epi);
456}
457
458static int
459jail_attach_disjoint_newjail(int fd)
460{
461	struct iovec iov[2];
462	char *name;
463	int jid;
464
465	if (asprintf(&name, "cpuset_%d", getpid()) == -1)
466		_exit(42);
467
468	iov[0].iov_base = "name";
469	iov[0].iov_len = sizeof("name");
470
471	iov[1].iov_base = name;
472	iov[1].iov_len = strlen(name) + 1;
473
474	if ((jid = jail_set(iov, 2, JAIL_CREATE | JAIL_ATTACH)) < 0)
475		return (FAILURE_JAIL);
476
477	/* Signal that we're ready. */
478	write(fd, &jid, sizeof(jid));
479	for (;;) {
480		/* Spin */
481	}
482}
483
484static int
485wait_jail(int fd, int pfd)
486{
487	fd_set lset;
488	struct timeval tv;
489	int error, jid, maxfd;
490
491	FD_ZERO(&lset);
492	FD_SET(fd, &lset);
493	FD_SET(pfd, &lset);
494
495	maxfd = MAX(fd, pfd);
496
497	tv.tv_sec = 5;
498	tv.tv_usec = 0;
499
500	/* Wait for jid to be written. */
501	do {
502		error = select(maxfd + 1, &lset, NULL, NULL, &tv);
503	} while (error == -1 && errno == EINTR);
504
505	if (error == 0) {
506		atf_tc_fail("Jail creator did not respond in time.");
507	}
508
509	ATF_REQUIRE_MSG(error > 0, "Unexpected error %d from select()", errno);
510
511	if (FD_ISSET(pfd, &lset)) {
512		/* Process died */
513		atf_tc_fail("Jail creator died unexpectedly.");
514	}
515
516	ATF_REQUIRE(FD_ISSET(fd, &lset));
517	ATF_REQUIRE_EQ(sizeof(jid), recv(fd, &jid, sizeof(jid), 0));
518
519	return (jid);
520}
521
522static int
523try_attach_child(int jid, cpuset_t *expected_mask)
524{
525	cpuset_t mask;
526
527	if (jail_attach(jid) == -1) {
528		if (errno == EDEADLK)
529			return (FAILURE_DEADLK);
530		return (FAILURE_ATTACH);
531	}
532
533	if (expected_mask == NULL)
534		return (FAILURE_SUCCESS);
535
536	/* If we had an expected mask, check it against the new process mask. */
537	CPU_ZERO(&mask);
538	if (cpuset_getaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID,
539	    -1, sizeof(mask), &mask) != 0) {
540		return (FAILURE_MASK);
541	}
542
543	if (CPU_CMP(expected_mask, &mask) != 0)
544		return (FAILURE_BADAFFIN);
545
546	return (0);
547}
548
549static void
550try_attach(int jid, cpuset_t *expected_mask)
551{
552	const char *errstr;
553	pid_t pid;
554	int error, fail, status;
555
556	ATF_REQUIRE(expected_mask != NULL);
557	ATF_REQUIRE((pid = fork()) != -1);
558	if (pid == 0)
559		_exit(try_attach_child(jid, expected_mask));
560
561	while ((error = waitpid(pid, &status, 0)) == -1 && errno == EINTR) {
562		/* Try again. */
563	}
564
565	/* Sanity check the exit info. */
566	ATF_REQUIRE_EQ(pid, error);
567	ATF_REQUIRE(WIFEXITED(status));
568	if ((fail = WEXITSTATUS(status)) != 0) {
569		errstr = do_jail_errstr(fail);
570		if (errstr != NULL)
571			atf_tc_fail("%s", errstr);
572		else
573			atf_tc_fail("Unknown error '%d'", WEXITSTATUS(status));
574	}
575}
576
577ATF_TC(jail_attach_disjoint);
578ATF_TC_HEAD(jail_attach_disjoint, tc)
579{
580	atf_tc_set_md_var(tc, "descr",
581	    "Test root attachment into completely disjoint jail cpuset.");
582	atf_tc_set_md_var(tc, "require.user", "root");
583}
584ATF_TC_BODY(jail_attach_disjoint, tc)
585{
586	cpuset_t smask, jmask;
587	int sockpair[2];
588	cpusetid_t setid;
589	pid_t pid;
590	int fcpu, jid, pfd, sock, scpu;
591
592	ATF_REQUIRE_EQ(0, cpuset(&setid));
593
594	skip_ltncpu(2, &jmask);
595	fcpu = CPU_FFS(&jmask) - 1;
596	ATF_REQUIRE_EQ(0, socketpair(PF_UNIX, SOCK_STREAM, 0, sockpair));
597
598	/* We'll wait on the procdesc, too, so we can fail faster if it dies. */
599	ATF_REQUIRE((pid = pdfork(&pfd, 0)) != -1);
600
601	if (pid == 0) {
602		/* First child sets up the jail. */
603		sock = sockpair[SP_CHILD];
604		close(sockpair[SP_PARENT]);
605
606		_exit(jail_attach_disjoint_newjail(sock));
607	}
608
609	close(sockpair[SP_CHILD]);
610	sock = sockpair[SP_PARENT];
611
612	ATF_REQUIRE((jid = wait_jail(sock, pfd)) > 0);
613
614	/*
615	 * This process will be clamped down to the first cpu, while the jail
616	 * will simply have the first CPU removed to make it a completely
617	 * disjoint operation.
618	 */
619	CPU_ZERO(&smask);
620	CPU_SET(fcpu, &smask);
621	CPU_CLR(fcpu, &jmask);
622
623	/*
624	 * We'll test with the first and second cpu set as well.  Only the
625	 * second cpu should be used.
626	 */
627	scpu = CPU_FFS(&jmask) - 1;
628
629	ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_ROOT, CPU_WHICH_JAIL,
630	    jid, sizeof(jmask), &jmask));
631	ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET,
632	    setid, sizeof(smask), &smask));
633
634	try_attach(jid, &jmask);
635
636	CPU_SET(scpu, &smask);
637	ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET,
638	    setid, sizeof(smask), &smask));
639
640	CPU_CLR(fcpu, &smask);
641	try_attach(jid, &smask);
642}
643
644ATF_TC(badparent);
645ATF_TC_HEAD(badparent, tc)
646{
647	atf_tc_set_md_var(tc, "descr",
648	    "Test parent assignment when assigning a new cpuset.");
649}
650ATF_TC_BODY(badparent, tc)
651{
652	cpuset_t mask;
653	cpusetid_t finalsetid, origsetid, setid;
654
655	/* Need to mask off at least one CPU. */
656	skip_ltncpu(2, &mask);
657
658	ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1,
659	    &origsetid));
660
661	ATF_REQUIRE_EQ(0, cpuset(&setid));
662
663	/*
664	 * Mask off the first CPU, then we'll reparent ourselves to our original
665	 * set.
666	 */
667	CPU_CLR(CPU_FFS(&mask) - 1, &mask);
668	ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
669	    -1, sizeof(mask), &mask));
670
671	ATF_REQUIRE_EQ(0, cpuset_setid(CPU_WHICH_PID, -1, origsetid));
672	ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1,
673	    &finalsetid));
674
675	ATF_REQUIRE_EQ(finalsetid, origsetid);
676}
677
678ATF_TP_ADD_TCS(tp)
679{
680
681	ATF_TP_ADD_TC(tp, newset);
682	ATF_TP_ADD_TC(tp, transient);
683	ATF_TP_ADD_TC(tp, deadlk);
684	ATF_TP_ADD_TC(tp, jail_attach_newbase);
685	ATF_TP_ADD_TC(tp, jail_attach_newbase_plain);
686	ATF_TP_ADD_TC(tp, jail_attach_prevbase);
687	ATF_TP_ADD_TC(tp, jail_attach_plain);
688	ATF_TP_ADD_TC(tp, jail_attach_disjoint);
689	ATF_TP_ADD_TC(tp, badparent);
690	return (atf_no_error());
691}
692