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