1*ac2250cbSAndy Fiddaman /*
2*ac2250cbSAndy Fiddaman * This file and its contents are supplied under the terms of the
3*ac2250cbSAndy Fiddaman * Common Development and Distribution License ("CDDL"), version 1.0.
4*ac2250cbSAndy Fiddaman * You may only use this file in accordance with the terms of version
5*ac2250cbSAndy Fiddaman * 1.0 of the CDDL.
6*ac2250cbSAndy Fiddaman *
7*ac2250cbSAndy Fiddaman * A full copy of the text of the CDDL should have accompanied this
8*ac2250cbSAndy Fiddaman * source. A copy of the CDDL is also available via the Internet at
9*ac2250cbSAndy Fiddaman * http://www.illumos.org/license/CDDL.
10*ac2250cbSAndy Fiddaman */
11*ac2250cbSAndy Fiddaman
12*ac2250cbSAndy Fiddaman /*
13*ac2250cbSAndy Fiddaman * Copyright 2026 Oxide Computer Company
14*ac2250cbSAndy Fiddaman */
15*ac2250cbSAndy Fiddaman
16*ac2250cbSAndy Fiddaman /*
17*ac2250cbSAndy Fiddaman * Tests for the raw spawn(2) system call interface. These concentrate
18*ac2250cbSAndy Fiddaman * mainly on checking that the kernel fully validates the marshalled
19*ac2250cbSAndy Fiddaman * spawn_param_t/spawn_args_t structures that libc constructs.
20*ac2250cbSAndy Fiddaman * We also test that a spawned child is robust against being killed in
21*ac2250cbSAndy Fiddaman * the window between creation and exec.
22*ac2250cbSAndy Fiddaman *
23*ac2250cbSAndy Fiddaman * Functional coverage of posix_spawn(3C) itself (attributes, file actions,
24*ac2250cbSAndy Fiddaman * PATH handling, etc.) lives in libc-tests/tests/posix_spawn.
25*ac2250cbSAndy Fiddaman */
26*ac2250cbSAndy Fiddaman
27*ac2250cbSAndy Fiddaman #include <errno.h>
28*ac2250cbSAndy Fiddaman #include <signal.h>
29*ac2250cbSAndy Fiddaman #include <spawn.h>
30*ac2250cbSAndy Fiddaman #include <stdio.h>
31*ac2250cbSAndy Fiddaman #include <stdlib.h>
32*ac2250cbSAndy Fiddaman #include <string.h>
33*ac2250cbSAndy Fiddaman #include <unistd.h>
34*ac2250cbSAndy Fiddaman #include <sys/syscall.h>
35*ac2250cbSAndy Fiddaman #include <sys/spawn_impl.h>
36*ac2250cbSAndy Fiddaman #include <sys/types.h>
37*ac2250cbSAndy Fiddaman #include <sys/wait.h>
38*ac2250cbSAndy Fiddaman
39*ac2250cbSAndy Fiddaman static uint_t failures = 0;
40*ac2250cbSAndy Fiddaman
41*ac2250cbSAndy Fiddaman #define TFAIL(name, fmt, ...) do { \
42*ac2250cbSAndy Fiddaman (void) fprintf(stderr, "TEST FAILED: %s: " fmt "\n", \
43*ac2250cbSAndy Fiddaman (name), ##__VA_ARGS__); \
44*ac2250cbSAndy Fiddaman failures++; \
45*ac2250cbSAndy Fiddaman } while (0)
46*ac2250cbSAndy Fiddaman
47*ac2250cbSAndy Fiddaman #define TPASS(name) (void) printf("TEST PASSED: %s\n", (name))
48*ac2250cbSAndy Fiddaman
49*ac2250cbSAndy Fiddaman /*
50*ac2250cbSAndy Fiddaman * The spawn_args_t and spawn_param_t structures end in a variable-length
51*ac2250cbSAndy Fiddaman * data[] region. These tests build small instances on the stack and reserve a
52*ac2250cbSAndy Fiddaman * fixed amount of room for that region.
53*ac2250cbSAndy Fiddaman */
54*ac2250cbSAndy Fiddaman #define SA_DATA 16
55*ac2250cbSAndy Fiddaman #define SP_DATA 64
56*ac2250cbSAndy Fiddaman
57*ac2250cbSAndy Fiddaman static pid_t
raw_spawn(const char * path,const void * sp,uint32_t spsize,const void * sa,uint32_t sasize)58*ac2250cbSAndy Fiddaman raw_spawn(const char *path, const void *sp, uint32_t spsize, const void *sa,
59*ac2250cbSAndy Fiddaman uint32_t sasize)
60*ac2250cbSAndy Fiddaman {
61*ac2250cbSAndy Fiddaman return (syscall(SYS_spawn, path, sp, spsize, sa, sasize));
62*ac2250cbSAndy Fiddaman }
63*ac2250cbSAndy Fiddaman
64*ac2250cbSAndy Fiddaman /*
65*ac2250cbSAndy Fiddaman * Build a minimal valid spawn_args_t in the provided buffer:
66*ac2250cbSAndy Fiddaman * argv = { "x" }, empty environment.
67*ac2250cbSAndy Fiddaman */
68*ac2250cbSAndy Fiddaman static uint32_t
valid_args(spawn_args_t * sa)69*ac2250cbSAndy Fiddaman valid_args(spawn_args_t *sa)
70*ac2250cbSAndy Fiddaman {
71*ac2250cbSAndy Fiddaman uint32_t sasize = sizeof (*sa) + 2;
72*ac2250cbSAndy Fiddaman
73*ac2250cbSAndy Fiddaman (void) memset(sa, 0, sasize);
74*ac2250cbSAndy Fiddaman sa->sa_size = sasize;
75*ac2250cbSAndy Fiddaman sa->sa_datalen = 2;
76*ac2250cbSAndy Fiddaman sa->sa_arg_cnt = 1;
77*ac2250cbSAndy Fiddaman sa->sa_env_off = 2;
78*ac2250cbSAndy Fiddaman sa->sa_data[0] = 'x';
79*ac2250cbSAndy Fiddaman sa->sa_data[1] = '\0';
80*ac2250cbSAndy Fiddaman
81*ac2250cbSAndy Fiddaman return (sasize);
82*ac2250cbSAndy Fiddaman }
83*ac2250cbSAndy Fiddaman
84*ac2250cbSAndy Fiddaman static const char *
errname(int err)85*ac2250cbSAndy Fiddaman errname(int err)
86*ac2250cbSAndy Fiddaman {
87*ac2250cbSAndy Fiddaman const char *name = strerrorname_np(err);
88*ac2250cbSAndy Fiddaman
89*ac2250cbSAndy Fiddaman return (name != NULL ? name : "?");
90*ac2250cbSAndy Fiddaman }
91*ac2250cbSAndy Fiddaman
92*ac2250cbSAndy Fiddaman static void
expect_err(const char * name,int wanted,const char * path,const void * sp,uint32_t spsize,const void * sa,uint32_t sasize)93*ac2250cbSAndy Fiddaman expect_err(const char *name, int wanted, const char *path, const void *sp,
94*ac2250cbSAndy Fiddaman uint32_t spsize, const void *sa, uint32_t sasize)
95*ac2250cbSAndy Fiddaman {
96*ac2250cbSAndy Fiddaman pid_t pid = raw_spawn(path, sp, spsize, sa, sasize);
97*ac2250cbSAndy Fiddaman
98*ac2250cbSAndy Fiddaman if (pid != -1) {
99*ac2250cbSAndy Fiddaman TFAIL(name, "spawn unexpectedly succeeded (pid %d)",
100*ac2250cbSAndy Fiddaman (int)pid);
101*ac2250cbSAndy Fiddaman (void) waitpid(pid, NULL, 0);
102*ac2250cbSAndy Fiddaman return;
103*ac2250cbSAndy Fiddaman }
104*ac2250cbSAndy Fiddaman if (errno != wanted) {
105*ac2250cbSAndy Fiddaman TFAIL(name, "got %s (%d), wanted %s (%d)", errname(errno),
106*ac2250cbSAndy Fiddaman errno, errname(wanted), wanted);
107*ac2250cbSAndy Fiddaman return;
108*ac2250cbSAndy Fiddaman }
109*ac2250cbSAndy Fiddaman TPASS(name);
110*ac2250cbSAndy Fiddaman }
111*ac2250cbSAndy Fiddaman
112*ac2250cbSAndy Fiddaman /*
113*ac2250cbSAndy Fiddaman * The positive case: a well-formed minimal request - a valid argument vector,
114*ac2250cbSAndy Fiddaman * no spawn parameters and no file actions - succeeds, and the child
115*ac2250cbSAndy Fiddaman * (/usr/bin/true) exits 0.
116*ac2250cbSAndy Fiddaman */
117*ac2250cbSAndy Fiddaman static void
t_valid(void)118*ac2250cbSAndy Fiddaman t_valid(void)
119*ac2250cbSAndy Fiddaman {
120*ac2250cbSAndy Fiddaman union {
121*ac2250cbSAndy Fiddaman spawn_args_t sa;
122*ac2250cbSAndy Fiddaman char pad[sizeof (spawn_args_t) + SA_DATA];
123*ac2250cbSAndy Fiddaman } au;
124*ac2250cbSAndy Fiddaman uint32_t sasize = valid_args(&au.sa);
125*ac2250cbSAndy Fiddaman int status;
126*ac2250cbSAndy Fiddaman pid_t pid;
127*ac2250cbSAndy Fiddaman
128*ac2250cbSAndy Fiddaman pid = raw_spawn("/usr/bin/true", NULL, 0, &au.sa, sasize);
129*ac2250cbSAndy Fiddaman if (pid == -1) {
130*ac2250cbSAndy Fiddaman TFAIL("valid", "spawn failed: %s", strerror(errno));
131*ac2250cbSAndy Fiddaman return;
132*ac2250cbSAndy Fiddaman }
133*ac2250cbSAndy Fiddaman if (waitpid(pid, &status, 0) != pid) {
134*ac2250cbSAndy Fiddaman TFAIL("valid", "waitpid: %s", strerror(errno));
135*ac2250cbSAndy Fiddaman return;
136*ac2250cbSAndy Fiddaman }
137*ac2250cbSAndy Fiddaman if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
138*ac2250cbSAndy Fiddaman TFAIL("valid", "status %#x", status);
139*ac2250cbSAndy Fiddaman return;
140*ac2250cbSAndy Fiddaman }
141*ac2250cbSAndy Fiddaman TPASS("valid, well-formed, minimal spawn request");
142*ac2250cbSAndy Fiddaman }
143*ac2250cbSAndy Fiddaman
144*ac2250cbSAndy Fiddaman static void
t_args_fuzz(void)145*ac2250cbSAndy Fiddaman t_args_fuzz(void)
146*ac2250cbSAndy Fiddaman {
147*ac2250cbSAndy Fiddaman union {
148*ac2250cbSAndy Fiddaman spawn_args_t sa;
149*ac2250cbSAndy Fiddaman char pad[sizeof (spawn_args_t) + SA_DATA];
150*ac2250cbSAndy Fiddaman } au;
151*ac2250cbSAndy Fiddaman spawn_args_t *sa = &au.sa;
152*ac2250cbSAndy Fiddaman uint32_t sasize;
153*ac2250cbSAndy Fiddaman
154*ac2250cbSAndy Fiddaman expect_err("null-path", EINVAL, NULL, NULL, 0, &au.sa,
155*ac2250cbSAndy Fiddaman valid_args(&au.sa));
156*ac2250cbSAndy Fiddaman expect_err("null-args", EINVAL, "/usr/bin/true", NULL, 0, NULL, 0);
157*ac2250cbSAndy Fiddaman
158*ac2250cbSAndy Fiddaman sasize = valid_args(sa);
159*ac2250cbSAndy Fiddaman sa->sa_size = sasize + 8;
160*ac2250cbSAndy Fiddaman expect_err("args-size-mismatch", EINVAL, "/usr/bin/true", NULL, 0,
161*ac2250cbSAndy Fiddaman sa, sasize);
162*ac2250cbSAndy Fiddaman
163*ac2250cbSAndy Fiddaman sasize = valid_args(sa);
164*ac2250cbSAndy Fiddaman sa->sa_datalen = 1;
165*ac2250cbSAndy Fiddaman expect_err("args-datalen-mismatch", EINVAL, "/usr/bin/true", NULL, 0,
166*ac2250cbSAndy Fiddaman sa, sasize);
167*ac2250cbSAndy Fiddaman
168*ac2250cbSAndy Fiddaman sasize = valid_args(sa);
169*ac2250cbSAndy Fiddaman sa->sa_arg_cnt = 100;
170*ac2250cbSAndy Fiddaman expect_err("args-cnt-overrun", EINVAL, "/usr/bin/true", NULL, 0,
171*ac2250cbSAndy Fiddaman sa, sasize);
172*ac2250cbSAndy Fiddaman
173*ac2250cbSAndy Fiddaman sasize = valid_args(sa);
174*ac2250cbSAndy Fiddaman sa->sa_data[1] = 'y'; /* string no longer NUL-terminated */
175*ac2250cbSAndy Fiddaman expect_err("args-unterminated", EINVAL, "/usr/bin/true", NULL, 0,
176*ac2250cbSAndy Fiddaman sa, sasize);
177*ac2250cbSAndy Fiddaman
178*ac2250cbSAndy Fiddaman sasize = valid_args(sa);
179*ac2250cbSAndy Fiddaman sa->sa_env_off = 100;
180*ac2250cbSAndy Fiddaman expect_err("args-env-off", EINVAL, "/usr/bin/true", NULL, 0,
181*ac2250cbSAndy Fiddaman sa, sasize);
182*ac2250cbSAndy Fiddaman
183*ac2250cbSAndy Fiddaman sasize = valid_args(sa);
184*ac2250cbSAndy Fiddaman sa->sa_env_cnt = 7;
185*ac2250cbSAndy Fiddaman expect_err("args-env-cnt", EINVAL, "/usr/bin/true", NULL, 0,
186*ac2250cbSAndy Fiddaman sa, sasize);
187*ac2250cbSAndy Fiddaman
188*ac2250cbSAndy Fiddaman sasize = valid_args(sa);
189*ac2250cbSAndy Fiddaman expect_err("args-e2big", E2BIG, "/usr/bin/true", NULL, 0,
190*ac2250cbSAndy Fiddaman sa, 0x400000);
191*ac2250cbSAndy Fiddaman
192*ac2250cbSAndy Fiddaman /* Truncated buffer: shorter than the header itself. */
193*ac2250cbSAndy Fiddaman sasize = valid_args(sa);
194*ac2250cbSAndy Fiddaman expect_err("args-short", EINVAL, "/usr/bin/true", NULL, 0,
195*ac2250cbSAndy Fiddaman sa, sizeof (*sa) - 4);
196*ac2250cbSAndy Fiddaman }
197*ac2250cbSAndy Fiddaman
198*ac2250cbSAndy Fiddaman static void
t_param_fuzz(void)199*ac2250cbSAndy Fiddaman t_param_fuzz(void)
200*ac2250cbSAndy Fiddaman {
201*ac2250cbSAndy Fiddaman union {
202*ac2250cbSAndy Fiddaman spawn_args_t sa;
203*ac2250cbSAndy Fiddaman char pad[sizeof (spawn_args_t) + SA_DATA];
204*ac2250cbSAndy Fiddaman } au;
205*ac2250cbSAndy Fiddaman union {
206*ac2250cbSAndy Fiddaman spawn_param_t sp;
207*ac2250cbSAndy Fiddaman char pad[sizeof (spawn_param_t) + SP_DATA];
208*ac2250cbSAndy Fiddaman } pu;
209*ac2250cbSAndy Fiddaman spawn_param_t *sp = &pu.sp;
210*ac2250cbSAndy Fiddaman uint32_t sasize = valid_args(&au.sa);
211*ac2250cbSAndy Fiddaman uint32_t spsize = sizeof (*sp) + SP_DATA;
212*ac2250cbSAndy Fiddaman kfile_attr_t *kfa;
213*ac2250cbSAndy Fiddaman
214*ac2250cbSAndy Fiddaman /* Size field disagreeing with the system call argument. */
215*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
216*ac2250cbSAndy Fiddaman sp->sp_size = spsize + 4;
217*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
218*ac2250cbSAndy Fiddaman expect_err("param-size-mismatch", EINVAL, "/usr/bin/true",
219*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
220*ac2250cbSAndy Fiddaman
221*ac2250cbSAndy Fiddaman /* Attribute region out of bounds. */
222*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
223*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
224*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
225*ac2250cbSAndy Fiddaman sp->sp_attr_off = 60;
226*ac2250cbSAndy Fiddaman sp->sp_attr_len = sizeof (spawn_attr_t);
227*ac2250cbSAndy Fiddaman expect_err("param-attr-off", EINVAL, "/usr/bin/true",
228*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
229*ac2250cbSAndy Fiddaman
230*ac2250cbSAndy Fiddaman /* Attribute length that is not sizeof (spawn_attr_t). */
231*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
232*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
233*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
234*ac2250cbSAndy Fiddaman sp->sp_attr_len = 8;
235*ac2250cbSAndy Fiddaman expect_err("param-attr-len", EINVAL, "/usr/bin/true",
236*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
237*ac2250cbSAndy Fiddaman
238*ac2250cbSAndy Fiddaman /* Undefined attribute flags. */
239*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
240*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
241*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
242*ac2250cbSAndy Fiddaman sp->sp_attr_off = 0;
243*ac2250cbSAndy Fiddaman sp->sp_attr_len = sizeof (spawn_attr_t);
244*ac2250cbSAndy Fiddaman ((spawn_attr_t *)&sp->sp_data[0])->sa_psflags = ~0;
245*ac2250cbSAndy Fiddaman expect_err("param-attr-flags", EINVAL, "/usr/bin/true",
246*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
247*ac2250cbSAndy Fiddaman
248*ac2250cbSAndy Fiddaman /* File action record with a zero length. */
249*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
250*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
251*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
252*ac2250cbSAndy Fiddaman sp->sp_fattr_cnt = 2;
253*ac2250cbSAndy Fiddaman expect_err("param-fattr-len", EINVAL, "/usr/bin/true",
254*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
255*ac2250cbSAndy Fiddaman
256*ac2250cbSAndy Fiddaman /* File action record with a bad type. */
257*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
258*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
259*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
260*ac2250cbSAndy Fiddaman sp->sp_fattr_cnt = 1;
261*ac2250cbSAndy Fiddaman kfa = (kfile_attr_t *)&sp->sp_data[0];
262*ac2250cbSAndy Fiddaman kfa->kfa_len = sizeof (*kfa);
263*ac2250cbSAndy Fiddaman kfa->kfa_type = 666;
264*ac2250cbSAndy Fiddaman expect_err("param-fattr-type", EINVAL, "/usr/bin/true",
265*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
266*ac2250cbSAndy Fiddaman
267*ac2250cbSAndy Fiddaman /* FA_CHDIR with an unterminated path. */
268*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
269*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
270*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
271*ac2250cbSAndy Fiddaman sp->sp_fattr_cnt = 1;
272*ac2250cbSAndy Fiddaman kfa = (kfile_attr_t *)&sp->sp_data[0];
273*ac2250cbSAndy Fiddaman kfa->kfa_type = FA_CHDIR;
274*ac2250cbSAndy Fiddaman kfa->kfa_pathsize = 4;
275*ac2250cbSAndy Fiddaman kfa->kfa_len = sizeof (*kfa) + 4;
276*ac2250cbSAndy Fiddaman (void) memcpy(kfa->kfa_path, "/tmp", 4); /* no NUL */
277*ac2250cbSAndy Fiddaman expect_err("param-chdir-nul", EINVAL, "/usr/bin/true",
278*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
279*ac2250cbSAndy Fiddaman
280*ac2250cbSAndy Fiddaman /* Unterminated shell and search path strings. */
281*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
282*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
283*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
284*ac2250cbSAndy Fiddaman sp->sp_shell_off = 0;
285*ac2250cbSAndy Fiddaman sp->sp_shell_len = 4;
286*ac2250cbSAndy Fiddaman (void) memcpy(sp->sp_data, "/bin", 4);
287*ac2250cbSAndy Fiddaman expect_err("param-shell-nul", EINVAL, "/usr/bin/true",
288*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
289*ac2250cbSAndy Fiddaman
290*ac2250cbSAndy Fiddaman (void) memset(&pu, 0, sizeof (pu));
291*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
292*ac2250cbSAndy Fiddaman sp->sp_datalen = SP_DATA;
293*ac2250cbSAndy Fiddaman sp->sp_path_off = 62;
294*ac2250cbSAndy Fiddaman sp->sp_path_len = 8;
295*ac2250cbSAndy Fiddaman expect_err("param-path-off", EINVAL, "/usr/bin/true",
296*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
297*ac2250cbSAndy Fiddaman
298*ac2250cbSAndy Fiddaman expect_err("param-e2big", E2BIG, "/usr/bin/true",
299*ac2250cbSAndy Fiddaman sp, 0x400000, &au.sa, sasize);
300*ac2250cbSAndy Fiddaman
301*ac2250cbSAndy Fiddaman expect_err("param-short", EINVAL, "/usr/bin/true",
302*ac2250cbSAndy Fiddaman sp, sizeof (*sp) - 4, &au.sa, sasize);
303*ac2250cbSAndy Fiddaman }
304*ac2250cbSAndy Fiddaman
305*ac2250cbSAndy Fiddaman /*
306*ac2250cbSAndy Fiddaman * Build a spawn_param_t carrying an attribute region with
307*ac2250cbSAndy Fiddaman * POSIX_SPAWN_SETSCHEDPARAM set and a scheduling region with the given
308*ac2250cbSAndy Fiddaman * operation.
309*ac2250cbSAndy Fiddaman */
310*ac2250cbSAndy Fiddaman static kspawn_sched_t *
valid_sched(spawn_param_t * sp,uint32_t spsize,int op)311*ac2250cbSAndy Fiddaman valid_sched(spawn_param_t *sp, uint32_t spsize, int op)
312*ac2250cbSAndy Fiddaman {
313*ac2250cbSAndy Fiddaman spawn_attr_t *spa;
314*ac2250cbSAndy Fiddaman kspawn_sched_t *ks;
315*ac2250cbSAndy Fiddaman
316*ac2250cbSAndy Fiddaman (void) memset(sp, 0, spsize);
317*ac2250cbSAndy Fiddaman sp->sp_size = spsize;
318*ac2250cbSAndy Fiddaman sp->sp_datalen = spsize - sizeof (*sp);
319*ac2250cbSAndy Fiddaman sp->sp_attr_off = 0;
320*ac2250cbSAndy Fiddaman sp->sp_attr_len = sizeof (spawn_attr_t);
321*ac2250cbSAndy Fiddaman spa = (spawn_attr_t *)&sp->sp_data[0];
322*ac2250cbSAndy Fiddaman spa->sa_psflags = POSIX_SPAWN_SETSCHEDPARAM;
323*ac2250cbSAndy Fiddaman sp->sp_sched_off = sizeof (spawn_attr_t);
324*ac2250cbSAndy Fiddaman sp->sp_sched_len = sizeof (kspawn_sched_t);
325*ac2250cbSAndy Fiddaman ks = (kspawn_sched_t *)&sp->sp_data[sp->sp_sched_off];
326*ac2250cbSAndy Fiddaman ks->ksched_op = op;
327*ac2250cbSAndy Fiddaman
328*ac2250cbSAndy Fiddaman return (ks);
329*ac2250cbSAndy Fiddaman }
330*ac2250cbSAndy Fiddaman
331*ac2250cbSAndy Fiddaman static void
t_sched_fuzz(void)332*ac2250cbSAndy Fiddaman t_sched_fuzz(void)
333*ac2250cbSAndy Fiddaman {
334*ac2250cbSAndy Fiddaman union {
335*ac2250cbSAndy Fiddaman spawn_args_t sa;
336*ac2250cbSAndy Fiddaman char pad[sizeof (spawn_args_t) + SA_DATA];
337*ac2250cbSAndy Fiddaman } au;
338*ac2250cbSAndy Fiddaman union {
339*ac2250cbSAndy Fiddaman spawn_param_t sp;
340*ac2250cbSAndy Fiddaman char pad[sizeof (spawn_param_t) + 128];
341*ac2250cbSAndy Fiddaman } pu;
342*ac2250cbSAndy Fiddaman spawn_param_t *sp = &pu.sp;
343*ac2250cbSAndy Fiddaman uint32_t sasize = valid_args(&au.sa);
344*ac2250cbSAndy Fiddaman uint32_t spsize = sizeof (*sp) + 128;
345*ac2250cbSAndy Fiddaman kspawn_sched_t *ks;
346*ac2250cbSAndy Fiddaman
347*ac2250cbSAndy Fiddaman /* Scheduling flag set but no scheduling region. */
348*ac2250cbSAndy Fiddaman (void) valid_sched(sp, spsize, KSCHED_PARMS);
349*ac2250cbSAndy Fiddaman sp->sp_sched_off = sp->sp_sched_len = 0;
350*ac2250cbSAndy Fiddaman expect_err("sched-missing", EINVAL, "/usr/bin/true",
351*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
352*ac2250cbSAndy Fiddaman
353*ac2250cbSAndy Fiddaman /* Scheduling region present without a scheduling flag. */
354*ac2250cbSAndy Fiddaman (void) valid_sched(sp, spsize, KSCHED_PARMS);
355*ac2250cbSAndy Fiddaman ((spawn_attr_t *)&sp->sp_data[0])->sa_psflags = 0;
356*ac2250cbSAndy Fiddaman expect_err("sched-no-flags", EINVAL, "/usr/bin/true",
357*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
358*ac2250cbSAndy Fiddaman
359*ac2250cbSAndy Fiddaman /* Scheduling region with the wrong length. */
360*ac2250cbSAndy Fiddaman (void) valid_sched(sp, spsize, KSCHED_PARMS);
361*ac2250cbSAndy Fiddaman sp->sp_sched_len = 8;
362*ac2250cbSAndy Fiddaman expect_err("sched-len", EINVAL, "/usr/bin/true",
363*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
364*ac2250cbSAndy Fiddaman
365*ac2250cbSAndy Fiddaman /* Scheduling region out of bounds. */
366*ac2250cbSAndy Fiddaman (void) valid_sched(sp, spsize, KSCHED_PARMS);
367*ac2250cbSAndy Fiddaman sp->sp_sched_off = sp->sp_datalen - 4;
368*ac2250cbSAndy Fiddaman expect_err("sched-off", EINVAL, "/usr/bin/true",
369*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
370*ac2250cbSAndy Fiddaman
371*ac2250cbSAndy Fiddaman /* Invalid operation. */
372*ac2250cbSAndy Fiddaman (void) valid_sched(sp, spsize, 0);
373*ac2250cbSAndy Fiddaman expect_err("sched-op", EINVAL, "/usr/bin/true",
374*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
375*ac2250cbSAndy Fiddaman
376*ac2250cbSAndy Fiddaman /* A priority change must be a set operation. */
377*ac2250cbSAndy Fiddaman ks = valid_sched(sp, spsize, KSCHED_PRIO);
378*ac2250cbSAndy Fiddaman ks->ksched_prio.pc_op = PC_GETPRIO;
379*ac2250cbSAndy Fiddaman ks->ksched_prio.pc_cid = 1;
380*ac2250cbSAndy Fiddaman expect_err("sched-prio-op", EINVAL, "/usr/bin/true",
381*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
382*ac2250cbSAndy Fiddaman
383*ac2250cbSAndy Fiddaman /*
384*ac2250cbSAndy Fiddaman * Class IDs out of range. These are not caught until the child
385*ac2250cbSAndy Fiddaman * applies the attributes to itself, exercising the error handshake.
386*ac2250cbSAndy Fiddaman */
387*ac2250cbSAndy Fiddaman ks = valid_sched(sp, spsize, KSCHED_PRIO);
388*ac2250cbSAndy Fiddaman ks->ksched_prio.pc_op = PC_SETPRIO;
389*ac2250cbSAndy Fiddaman ks->ksched_prio.pc_cid = 999;
390*ac2250cbSAndy Fiddaman expect_err("sched-prio-cid", EINVAL, "/usr/bin/true",
391*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
392*ac2250cbSAndy Fiddaman
393*ac2250cbSAndy Fiddaman ks = valid_sched(sp, spsize, KSCHED_PARMS);
394*ac2250cbSAndy Fiddaman ks->ksched_parms.pc_cid = 999;
395*ac2250cbSAndy Fiddaman expect_err("sched-parms-cid", EINVAL, "/usr/bin/true",
396*ac2250cbSAndy Fiddaman sp, spsize, &au.sa, sasize);
397*ac2250cbSAndy Fiddaman }
398*ac2250cbSAndy Fiddaman
399*ac2250cbSAndy Fiddaman /*
400*ac2250cbSAndy Fiddaman * A child killed immediately after spawn(2) returns must be waitable and
401*ac2250cbSAndy Fiddaman * must never leave the parent stuck. We try a few times to give us a fighting
402*ac2250cbSAndy Fiddaman * chance of catching it.
403*ac2250cbSAndy Fiddaman */
404*ac2250cbSAndy Fiddaman static void
t_kill_race(void)405*ac2250cbSAndy Fiddaman t_kill_race(void)
406*ac2250cbSAndy Fiddaman {
407*ac2250cbSAndy Fiddaman union {
408*ac2250cbSAndy Fiddaman spawn_args_t sa;
409*ac2250cbSAndy Fiddaman char pad[sizeof (spawn_args_t) + SA_DATA];
410*ac2250cbSAndy Fiddaman } au;
411*ac2250cbSAndy Fiddaman uint32_t sasize = valid_args(&au.sa);
412*ac2250cbSAndy Fiddaman
413*ac2250cbSAndy Fiddaman /*
414*ac2250cbSAndy Fiddaman * Spawn a child and immediately kill it, over and over, to exercise
415*ac2250cbSAndy Fiddaman * the window between creation and exec. valid_args() supplies only
416*ac2250cbSAndy Fiddaman * argv[0], so sleep runs with no duration. That does not matter,
417*ac2250cbSAndy Fiddaman * because we SIGKILL it at once - all we need is a live PID to race
418*ac2250cbSAndy Fiddaman * against.
419*ac2250cbSAndy Fiddaman */
420*ac2250cbSAndy Fiddaman for (int i = 0; i < 100; i++) {
421*ac2250cbSAndy Fiddaman int status;
422*ac2250cbSAndy Fiddaman pid_t pid;
423*ac2250cbSAndy Fiddaman
424*ac2250cbSAndy Fiddaman pid = raw_spawn("/usr/bin/sleep", NULL, 0, &au.sa, sasize);
425*ac2250cbSAndy Fiddaman if (pid == -1) {
426*ac2250cbSAndy Fiddaman TFAIL("kill-race", "spawn failed: %s",
427*ac2250cbSAndy Fiddaman strerror(errno));
428*ac2250cbSAndy Fiddaman return;
429*ac2250cbSAndy Fiddaman }
430*ac2250cbSAndy Fiddaman (void) kill(pid, SIGKILL);
431*ac2250cbSAndy Fiddaman if (waitpid(pid, &status, 0) != pid) {
432*ac2250cbSAndy Fiddaman TFAIL("kill-race", "waitpid: %s", strerror(errno));
433*ac2250cbSAndy Fiddaman return;
434*ac2250cbSAndy Fiddaman }
435*ac2250cbSAndy Fiddaman if (!WIFSIGNALED(status) &&
436*ac2250cbSAndy Fiddaman !(WIFEXITED(status) && WEXITSTATUS(status) != 0)) {
437*ac2250cbSAndy Fiddaman TFAIL("kill-race", "iteration %d: status %#x",
438*ac2250cbSAndy Fiddaman i, status);
439*ac2250cbSAndy Fiddaman return;
440*ac2250cbSAndy Fiddaman }
441*ac2250cbSAndy Fiddaman }
442*ac2250cbSAndy Fiddaman TPASS("kill-race");
443*ac2250cbSAndy Fiddaman }
444*ac2250cbSAndy Fiddaman
445*ac2250cbSAndy Fiddaman int
main(void)446*ac2250cbSAndy Fiddaman main(void)
447*ac2250cbSAndy Fiddaman {
448*ac2250cbSAndy Fiddaman t_valid();
449*ac2250cbSAndy Fiddaman t_args_fuzz();
450*ac2250cbSAndy Fiddaman t_param_fuzz();
451*ac2250cbSAndy Fiddaman t_sched_fuzz();
452*ac2250cbSAndy Fiddaman t_kill_race();
453*ac2250cbSAndy Fiddaman
454*ac2250cbSAndy Fiddaman if (failures == 0) {
455*ac2250cbSAndy Fiddaman (void) printf("All tests passed\n");
456*ac2250cbSAndy Fiddaman return (EXIT_SUCCESS);
457*ac2250cbSAndy Fiddaman }
458*ac2250cbSAndy Fiddaman
459*ac2250cbSAndy Fiddaman (void) fprintf(stderr, "%u test(s) failed\n", failures);
460*ac2250cbSAndy Fiddaman return (EXIT_FAILURE);
461*ac2250cbSAndy Fiddaman }
462