xref: /minix/minix/tests/test87.c (revision d2532d3d)
1 /* Tests for sysctl(2) and the MIB service - by D.C. van Moolenbroek */
2 /* This test needs to run as root: many sysctl(2) calls are privileged. */
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <pwd.h>
7 #include <sys/mman.h>
8 #include <sys/wait.h>
9 #include <minix/sysctl.h>
10 #include <assert.h>
11 
12 #define ITERATIONS 2
13 
14 #include "common.h"
15 
16 #define NONROOT_USER	"bin"		/* name of any unprivileged user */
17 
18 #define NEXT_VER(n)	(((n) + 1 == 0) ? 1 : ((n) + 1)) /* node version + 1 */
19 
20 static void *bad_ptr;			/* a pointer to unmapped memory */
21 static unsigned int nodes, objects;	/* stats for pre/post test check */
22 
23 /*
24  * Spawn a child process that drops privileges and then executes the given
25  * procedure.  The returned PID value is of the dead, cleaned-up child, and
26  * should be used only to check whether the child could store its own PID.
27  */
28 static pid_t
29 test_nonroot(void (* proc)(void))
30 {
31 	struct passwd *pw;
32 	pid_t pid;
33 	int status;
34 
35 	pid = fork();
36 
37 	switch (pid) {
38 	case -1:
39 		e(0);
40 		break;
41 	case 0:
42 		errct = 0;
43 
44 		if ((pw = getpwnam(NONROOT_USER)) == NULL) e(0);
45 
46 		/* FIXME: this may rely on a MINIXism. */
47 		if (setuid(pw->pw_uid) != 0) e(0);
48 		if (seteuid(pw->pw_uid) != 0) e(0);
49 
50 		proc();
51 
52 		exit(errct);
53 	default:
54 		if (wait(&status) != pid) e(0);
55 		if (!WIFEXITED(status)) e(0);
56 		if (WEXITSTATUS(status) != 0) e(0);
57 	}
58 
59 	return pid;
60 }
61 
62 /*
63  * Test basic operations from an unprivileged process.
64  */
65 static void
66 sub87a(void)
67 {
68 	size_t oldlen;
69 	pid_t pid;
70 	bool b;
71 	int i, mib[4];
72 
73 	pid = getpid();
74 
75 	mib[0] = CTL_MINIX;
76 	mib[1] = MINIX_TEST;
77 
78 	/* Regular reads should succeed. */
79 	mib[2] = TEST_INT;
80 	oldlen = sizeof(i);
81 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
82 	if (oldlen != sizeof(i)) e(0);
83 	if (i != 0x01020304) e(0);
84 
85 	mib[2] = TEST_BOOL;
86 	oldlen = sizeof(b);
87 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
88 	if (oldlen != sizeof(b)) e(0);
89 	if (b != false) e(0);
90 
91 	/* Regular writes should fail. */
92 	b = true;
93 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != -1) e(0);
94 	if (errno != EPERM) e(0);
95 
96 	oldlen = sizeof(b);
97 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
98 	if (oldlen != sizeof(b)) e(0);
99 	if (b != false) e(0);
100 
101 	/* Privileged reads and writes should fail. */
102 	mib[2] = TEST_PRIVATE;
103 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != -1) e(0);
104 	if (errno != EPERM) e(0);
105 
106 	oldlen = sizeof(i);
107 	i = 1;
108 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != -1) e(0);
109 	if (errno != EPERM) e(0);
110 	if (i != 1) e(0);
111 
112 	if (sysctl(mib, 3, NULL, NULL, &i, sizeof(i)) != -1) e(0);
113 	if (errno != EPERM) e(0);
114 
115 	mib[2] = TEST_SECRET;
116 	mib[3] = SECRET_VALUE;
117 	i = 0;
118 	oldlen = sizeof(i);
119 	if (sysctl(mib, 4, &i, &oldlen, NULL, 0) != -1) e(0);
120 	if (errno != EPERM) e(0);
121 	if (i == 12345) e(0);
122 
123 	mib[3]++;
124 	i = 0;
125 	oldlen = sizeof(i);
126 	if (sysctl(mib, 4, &i, &oldlen, NULL, 0) != -1) e(0);
127 	if (errno != EPERM) e(0);
128 
129 	/* Free-for-all writes should succeed. */
130 	mib[2] = TEST_ANYWRITE;
131 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
132 	if (oldlen != sizeof(i)) e(0);
133 
134 	i = pid;
135 	if (sysctl(mib, 3, NULL, NULL, &i, sizeof(i)) != 0) e(0);
136 
137 	i = 0;
138 	oldlen = sizeof(i);
139 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
140 	if (oldlen != sizeof(i)) e(0);
141 	if (i != pid) e(0);
142 }
143 
144 /*
145  * Test the basic sysctl(2) interface.
146  */
147 static void
148 test87a(void)
149 {
150 	char buf[32];
151 	size_t len, oldlen;
152 	pid_t pid;
153 	u_quad_t q;
154 	bool b, b2;
155 	int i, va[2], lastva, mib[CTL_MAXNAME + 1];
156 
157 	subtest = 0;
158 
159 	mib[0] = INT_MAX; /* some root-level identifier that does not exist */
160 	for (i = 1; i <= CTL_MAXNAME; i++)
161 		mib[i] = i;
162 
163 	/*
164 	 * We cannot test for invalid 'name' and 'oldlenp' pointers, because
165 	 * those may be accessed directly by the libc system call stub.  The
166 	 * NetBSD part of the stub even accesses name[0] without checking
167 	 * namelen first.
168 	 */
169 	if (sysctl(mib, 0, NULL, NULL, NULL, 0) != -1) e(0);
170 	if (errno != EINVAL) e(0);
171 	if (sysctl(mib, INT_MAX, NULL, NULL, NULL, 0) != -1) e(0);
172 	if (errno != EINVAL) e(0);
173 	if (sysctl(mib, UINT_MAX, NULL, NULL, NULL, 0) != -1) e(0);
174 	if (errno != EINVAL) e(0);
175 	for (i = 1; i <= CTL_MAXNAME; i++) {
176 		if (sysctl(mib, i, NULL, NULL, NULL, 0) != -1) e(i);
177 		if (errno != ENOENT) e(i);
178 	}
179 	if (sysctl(mib, i, NULL, NULL, NULL, 0) != -1) e(0);
180 	if (errno != EINVAL) e(0);
181 
182 	/* Test names that are too short, right, and too long. */
183 	mib[0] = CTL_MINIX;
184 	if (sysctl(mib, 1, NULL, NULL, NULL, 0) != -1) e(0);
185 	if (errno != EISDIR) e(0);
186 	mib[1] = MINIX_TEST;
187 	if (sysctl(mib, 2, NULL, NULL, NULL, 0) != -1) e(0);
188 	if (errno != EISDIR) e(0);
189 	mib[2] = TEST_INT;
190 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != 0) e(0);
191 	mib[3] = 0;
192 	if (sysctl(mib, 4, NULL, NULL, NULL, 0) != -1) e(0);
193 	if (errno != ENOTDIR) e(0);
194 
195 	/* Do some tests with meta-identifiers (special keys). */
196 	mib[3] = CTL_QUERY;
197 	if (sysctl(mib, 4, NULL, NULL, NULL, 0) != -1) e(0);
198 	if (errno != ENOTDIR) e(0);
199 
200 	mib[2] = CTL_QUERY;
201 	mib[3] = 0;
202 	if (sysctl(mib, 4, NULL, NULL, NULL, 0) != -1) e(0);
203 	if (errno != EINVAL) e(0);
204 
205 	mib[2] = CTL_EOL; /* a known-invalid meta-identifier */
206 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
207 	if (errno != EOPNOTSUPP) e(0);
208 
209 	/* This case returns EINVAL now but might as well return EOPNOTSUPP. */
210 	mib[3] = 0;
211 	if (sysctl(mib, 4, NULL, NULL, NULL, 0) != -1) e(0);
212 	if (errno != EOPNOTSUPP && errno != EINVAL) e(0);
213 
214 	/* Make sure the given oldlen value is ignored when unused. */
215 	mib[2] = TEST_INT;
216 	oldlen = 0;
217 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
218 	if (oldlen != sizeof(int)) e(0);
219 	oldlen = 1;
220 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
221 	if (oldlen != sizeof(int)) e(0);
222 	oldlen = SSIZE_MAX;
223 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
224 	if (oldlen != sizeof(int)) e(0);
225 	oldlen = SIZE_MAX;
226 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
227 	if (oldlen != sizeof(int)) e(0);
228 
229 	/* Test retrieval with the exact length. */
230 	oldlen = sizeof(va[0]);
231 	va[0] = va[1] = -1;
232 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
233 	if (oldlen != sizeof(va[0])) e(0);
234 	if (va[0] != 0x01020304) e(0);
235 	if (va[1] != -1) e(0);
236 
237 	/* Test retrieval with a length that is too short. */
238 	for (i = 0; i < sizeof(va[0]); i++) {
239 		va[0] = -1;
240 		oldlen = i;
241 		if (sysctl(mib, 3, va, &oldlen, NULL, 0) != -1) e(0);
242 		if (errno != ENOMEM) e(0);
243 		if (oldlen != sizeof(va[0])) e(0);
244 		if (i == 0 && va[0] != -1) e(0);
245 		if (i > 0 && va[0] >= lastva) e(0);
246 		if (va[1] != -1) e(0);
247 		lastva = va[0];
248 	}
249 
250 	/* Test retrieval with a length that is too long. */
251 	oldlen = sizeof(va[0]) + 1;
252 	va[0] = -1;
253 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
254 	if (oldlen != sizeof(va[0])) e(0);
255 	if (va[0] != 0x01020304) e(0);
256 	if (va[1] != -1) e(0);
257 
258 	oldlen = SSIZE_MAX;
259 	va[0] = -1;
260 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
261 	if (oldlen != sizeof(va[0])) e(0);
262 	if (va[0] != 0x01020304) e(0);
263 	if (va[1] != -1) e(0);
264 
265 	oldlen = SIZE_MAX;
266 	va[0] = -1;
267 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
268 	if (oldlen != sizeof(va[0])) e(0);
269 	if (va[0] != 0x01020304) e(0);
270 	if (va[1] != -1) e(0);
271 
272 	/*
273 	 * Ensure that we cannot overwrite this read-only integer.  A write
274 	 * request must have both a pointer and a nonzero length, though.
275 	 */
276 	va[0] = 0x05060708;
277 	if (sysctl(mib, 3, NULL, NULL, NULL, 1) != 0) e(0);
278 	if (sysctl(mib, 3, NULL, NULL, va, 0) != 0) e(0);
279 	if (sysctl(mib, 3, NULL, NULL, va, sizeof(va[0])) != -1) e(0);
280 	if (errno != EPERM) e(0);
281 
282 	oldlen = sizeof(va[0]);
283 	va[0] = -1;
284 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
285 	if (oldlen != sizeof(va[0])) e(0);
286 	if (va[0] != 0x01020304) e(0);
287 	if (va[1] != -1) e(0);
288 
289 	/* Test retrieval into a bad pointer. */
290 	oldlen = sizeof(int);
291 	if (sysctl(mib, 3, bad_ptr, &oldlen, NULL, 0) != -1) e(0);
292 	if (errno != EFAULT) e(0);
293 
294 	/*
295 	 * Test reading and writing booleans.  Booleans may actually be an int,
296 	 * a char, or just one bit of a char.  As a result, the MIB service can
297 	 * not test properly for non-bool values being passed in bool fields,
298 	 * and we can not do effective testing on this either, because in both
299 	 * cases our efforts may simply be optimized away, and result in
300 	 * unexpected success.
301 	 */
302 	mib[2] = TEST_BOOL;
303 	oldlen = sizeof(b);
304 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
305 	if (oldlen != sizeof(b)) e(0);
306 	if (b != false && b != true) e(0);
307 
308 	b = true;
309 	if (sysctl(mib, 3, NULL, &oldlen, &b, sizeof(b)) != 0) e(0);
310 	if (oldlen != sizeof(b)) e(0);
311 
312 	b = false;
313 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
314 	if (oldlen != sizeof(b)) e(0);
315 	if (b != true) e(0);
316 
317 	b = false;
318 	b2 = false;
319 	oldlen = sizeof(b2);
320 	if (sysctl(mib, 3, &b2, &oldlen, &b, sizeof(b)) != 0) e(0);
321 	if (oldlen != sizeof(b2)) e(0);
322 	if (b != false) e(0);
323 	if (b2 != true) e(0);
324 
325 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b) + 1) != -1) e(0);
326 	if (errno != EINVAL) e(0);
327 
328 	/*
329 	 * The MIB service does not support value swaps.  If we pass in the
330 	 * same buffer for old and new data, we expect that the old data stays.
331 	 */
332 	b = true;
333 	oldlen = sizeof(b);
334 	if (sysctl(mib, 3, &b, &oldlen, &b, sizeof(b)) != 0) e(0);
335 	if (oldlen != sizeof(b)) e(0);
336 	if (b != false) e(0);
337 
338 	b = true;
339 	oldlen = sizeof(b);
340 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
341 	if (oldlen != sizeof(b)) e(0);
342 	if (b != false) e(0);
343 
344 	/* Test reading and writing a quad. */
345 	mib[2] = TEST_QUAD;
346 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
347 	if (oldlen != sizeof(q)) e(0);
348 
349 	q = 0x1234567890abcdefULL;
350 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
351 
352 	q = 0ULL;
353 	oldlen = sizeof(q);
354 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
355 	if (oldlen != sizeof(q)) e(0);
356 	if (q != 0x1234567890abcdefULL) e(0);
357 
358 	q = ~0ULL;
359 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
360 
361 	/* Test writing with a bad pointer.  The value must stay. */
362 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(q)) != -1) e(0);
363 	if (errno != EFAULT) e(0);
364 
365 	q = 0ULL;
366 	oldlen = sizeof(q);
367 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
368 	if (oldlen != sizeof(q)) e(0);
369 	if (q != ~0ULL) e(0);
370 
371 	q = 0ULL;
372 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
373 
374 	q = 1ULL;
375 	oldlen = sizeof(q);
376 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
377 	if (oldlen != sizeof(q)) e(0);
378 	if (q != 0ULL) e(0);
379 
380 	/* Test reading and writing a string. */
381 	mib[2] = TEST_STRING;
382 	strlcpy(buf, "test", sizeof(buf));
383 	len = strlen(buf);
384 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1) != 0) e(0);
385 
386 	oldlen = sizeof(buf);
387 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
388 	if (oldlen != len + 1) e(0);
389 
390 	memset(buf, 0x07, sizeof(buf));
391 	oldlen = sizeof(buf);
392 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
393 	if (strcmp(buf, "test")) e(0);
394 	if (oldlen != len + 1) e(0);
395 	if (buf[len + 1] != 0x07) e(0);
396 
397 	strlcpy(buf, "abc123", sizeof(buf));
398 	oldlen = 2;
399 	if (sysctl(mib, 3, NULL, &oldlen, buf, strlen(buf) + 1) != 0) e(0);
400 	if (oldlen != len + 1) e(0);
401 	len = strlen(buf);
402 
403 	memset(buf, 0x07, sizeof(buf));
404 	oldlen = len - 1;
405 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
406 	if (errno != ENOMEM) e(0);
407 	if (oldlen != len + 1) e(0);
408 	if (strncmp(buf, "abc12", len - 1)) e(0);
409 	if (buf[len - 1] != 0x07 || buf[len] != 0x07) e(0);
410 
411 	memset(buf, 0x07, sizeof(buf));
412 	oldlen = len + 1;
413 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
414 	if (oldlen != len + 1) e(0);
415 	if (strcmp(buf, "abc123")) e(0);
416 
417 	/*
418 	 * Now put in a shorter string, without null terminator.  The string
419 	 * must be accepted; the null terminator must be added automatically.
420 	 */
421 	strlcpy(buf, "foolproof", sizeof(buf));
422 	len = strlen("foo");
423 	if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
424 
425 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
426 	if (oldlen != len + 1) e(0);
427 
428 	memset(buf, 0x07, sizeof(buf));
429 	oldlen = len;
430 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
431 	if (errno != ENOMEM) e(0);
432 	if (oldlen != len + 1) e(0);
433 	if (strncmp(buf, "foo", len)) e(0);
434 	if (buf[len] != 0x07) e(0);
435 
436 	memset(buf, 0x07, sizeof(buf));
437 	oldlen = sizeof(buf);
438 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
439 	if (oldlen != len + 1) e(0);
440 	if (strcmp(buf, "foo")) e(0);
441 	if (buf[len + 1] != 0x07) e(0);
442 
443 	/*
444 	 * Passing in more data after the string is fine, but whatever comes
445 	 * after the first null terminator is disregarded.
446 	 */
447 	strlcpy(buf, "barbapapa", sizeof(buf));
448 	len = strlen(buf);
449 	buf[3] = '\0';
450 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1)) e(0);
451 	len = strlen(buf);
452 
453 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
454 	if (oldlen != len + 1) e(0);
455 
456 	memset(buf, 0x07, sizeof(buf));
457 	oldlen = sizeof(buf);
458 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
459 	if (oldlen != len + 1) e(0);
460 	if (strcmp(buf, "bar")) e(0);
461 	if (buf[len + 1] != 0x07) e(0);
462 
463 	/* Test the maximum string length. */
464 	strlcpy(buf, "0123456789abcdef", sizeof(buf));
465 	len = strlen(buf);
466 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1) != -1) e(0);
467 	if (errno != EINVAL) e(0);
468 	if (sysctl(mib, 3, NULL, NULL, buf, len) != -1) e(0);
469 	if (errno != EINVAL) e(0);
470 
471 	buf[--len] = '\0';
472 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1) != 0) e(0);
473 	memset(buf, 0x07, sizeof(buf));
474 	oldlen = sizeof(buf);
475 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
476 	if (oldlen != len + 1) e(0);
477 	if (strcmp(buf, "0123456789abcde")) e(0);
478 	if (buf[len + 1] != 0x07) e(0);
479 
480 	/*
481 	 * Clearing out the field with zero-length data is not possible,
482 	 * because zero-length updates are disregarded at a higher level.
483 	 */
484 	if (sysctl(mib, 3, NULL, NULL, "", 0) != 0) e(0);
485 	memset(buf, 0x07, sizeof(buf));
486 	oldlen = sizeof(buf);
487 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
488 	if (oldlen != len + 1) e(0);
489 	if (strcmp(buf, "0123456789abcde")) e(0);
490 
491 	/* To clear the field, the null terminator is required. */
492 	if (sysctl(mib, 3, NULL, NULL, "", 1) != 0) e(0);
493 	memset(buf, 0x07, sizeof(buf));
494 	oldlen = sizeof(buf);
495 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
496 	if (oldlen != 1) e(0);
497 	if (buf[0] != '\0') e(0);
498 	if (buf[1] != 0x07) e(0);
499 
500 	/*
501 	 * Test reading and writing structures.  Structures are just blobs of
502 	 * data, with no special handling by default.  They can only be read
503 	 * and written all at once.
504 	 */
505 	mib[2] = TEST_STRUCT;
506 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
507 	if (oldlen != 12) e(0);
508 	len = oldlen;
509 
510 	for (i = 0; i < len + 1; i++)
511 		buf[i] = i + 1;
512 	if (sysctl(mib, 3, NULL, NULL, buf, len - 1) != -1) e(0);
513 	if (errno != EINVAL) e(0);
514 	if (sysctl(mib, 3, NULL, NULL, buf, len + 1) != -1) e(0);
515 	if (errno != EINVAL) e(0);
516 	if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
517 
518 	memset(buf, 0x7f, sizeof(buf));
519 	oldlen = len - 1;
520 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
521 	if (errno != ENOMEM) e(0);
522 	if (oldlen != len) e(0);
523 	for (i = 0; i < len - 1; i++)
524 		if (buf[i] != i + 1) e(0);
525 	if (buf[i] != 0x7f) e(0);
526 
527 	memset(buf, 0x7f, sizeof(buf));
528 	oldlen = len + 1;
529 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
530 	if (oldlen != len) e(0);
531 	for (i = 0; i < len; i++)
532 		if (buf[i] != i + 1) e(0);
533 	if (buf[i] != 0x7f) e(0);
534 
535 	memset(buf, 0x7f, sizeof(buf));
536 	oldlen = len;
537 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
538 	for (i = 0; i < len; i++)
539 		if (buf[i] != i + 1) e(0);
540 	if (buf[len] != 0x7f) e(0);
541 
542 	/* Null characters are not treated in any special way. */
543 	for (i = 0; i < len; i++)
544 		buf[i] = !!i;
545 	if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
546 
547 	oldlen = len;
548 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
549 	if (oldlen != len) e(0);
550 	for (i = 0; i < len; i++)
551 		if (buf[i] != !!i) e(0);
552 	if (buf[len] != 0x7f) e(0);
553 
554 	memset(buf, 0, len);
555 	if (sysctl(mib, 3, NULL, NULL, buf, len) != 0) e(0);
556 
557 	oldlen = len;
558 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
559 	if (oldlen != len) e(0);
560 	for (i = 0; i < len; i++)
561 		if (buf[i] != 0) e(0);
562 	if (buf[len] != 0x7f) e(0);
563 
564 	/*
565 	 * Test private read and free-for-all write operations.  For starters,
566 	 * this test should run with superuser privileges, and thus should be
567 	 * able to read and write private fields.
568 	 */
569 	mib[2] = TEST_PRIVATE;
570 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
571 	if (oldlen != sizeof(va[0])) e(0);
572 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
573 	if (va[0] != -5375) e(0);
574 	if (sysctl(mib, 3, NULL, NULL, va, sizeof(va[0])) != 0) e(0);
575 
576 	mib[2] = TEST_SECRET;
577 	mib[3] = SECRET_VALUE;
578 	oldlen = sizeof(va[0]);
579 	if (sysctl(mib, 4, va, &oldlen, NULL, 0) != 0) e(0);
580 	if (va[0] != 12345) e(0);
581 	if (sysctl(mib, 4, NULL, NULL, va, sizeof(va[0])) != -1) e(0);
582 	if (errno != EPERM) e(0);
583 
584 	mib[3]++;
585 	i = 0;
586 	oldlen = sizeof(i);
587 	if (sysctl(mib, 4, &i, &oldlen, NULL, 0) != -1) e(0);
588 	if (errno != ENOENT) e(0);
589 
590 	/* Use a child process to test operations without root privileges. */
591 	pid = test_nonroot(sub87a);
592 
593 	/* The change made by the child should be visible to the parent. */
594 	mib[2] = TEST_ANYWRITE;
595 	va[0] = 0;
596 	oldlen = sizeof(va[0]);
597 	if (sysctl(mib, 3, va, &oldlen, NULL, 0) != 0) e(0);
598 	if (oldlen != sizeof(va[0])) e(0);
599 	if (va[0] != pid) e(0);
600 }
601 
602 /*
603  * Test queries from an unprivileged process.
604  */
605 static void
606 sub87b(void)
607 {
608 	struct sysctlnode scn[32];
609 	unsigned int count;
610 	size_t oldlen;
611 	int i, mib[4];
612 
613 	/* Query minix.test and make sure we do not get privileged values. */
614 	mib[0] = CTL_MINIX;
615 	mib[1] = MINIX_TEST;
616 	mib[2] = CTL_QUERY;
617 
618 	oldlen = sizeof(scn);
619 	if (sysctl(mib, 3, scn, &oldlen, NULL, 0) != 0) e(0);
620 	if (oldlen % sizeof(scn[0])) e(0);
621 	count = oldlen / sizeof(scn[0]);
622 	if (count < 8) e(0);
623 
624 	/*
625 	 * Do not bother doing the entire check again, but test enough to
626 	 * inspire confidence that only the right values are hidden.
627 	 */
628 	if (scn[0].sysctl_num != TEST_INT) e(0);
629 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
630 	if (SYSCTL_FLAGS(scn[0].sysctl_flags) !=
631 	    (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE | CTLFLAG_HEX)) e(0);
632 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
633 	if (strcmp(scn[0].sysctl_name, "int")) e(0);
634 	if (scn[0].sysctl_ver == 0) e(0);
635 	if (scn[0].sysctl_size != sizeof(int)) e(0);
636 	if (scn[0].sysctl_idata != 0x01020304) e(0);
637 
638 	for (i = 0; i < count; i++)
639 		if (scn[i].sysctl_num == TEST_PRIVATE)
640 			break;
641 	if (i == count) e(0);
642 	if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_INT) e(0);
643 	if (SYSCTL_FLAGS(scn[i].sysctl_flags) !=
644 	    (CTLFLAG_READWRITE | CTLFLAG_PRIVATE | CTLFLAG_IMMEDIATE)) e(0);
645 	if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
646 	if (strcmp(scn[i].sysctl_name, "private")) e(0);
647 	if (scn[i].sysctl_size != sizeof(int)) e(0);
648 	if (scn[i].sysctl_idata != 0) e(0); /* private */
649 
650 	for (i = 0; i < count; i++)
651 		if (scn[i].sysctl_num == TEST_SECRET)
652 			break;
653 	if (i == count) e(0);
654 	if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_NODE) e(0);
655 	if (SYSCTL_FLAGS(scn[i].sysctl_flags) !=
656 	    (CTLFLAG_READONLY | CTLFLAG_PRIVATE)) e(0);
657 	if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
658 	if (strcmp(scn[i].sysctl_name, "secret")) e(0);
659 	if (scn[i].sysctl_ver == 0) e(0);
660 	if (scn[i].sysctl_size != sizeof(scn[0])) e(0);
661 	if (scn[i].sysctl_csize != 0) e(0); /* private */
662 	if (scn[i].sysctl_clen != 0) e(0); /* private */
663 
664 	/* Make sure that a query on minix.test.secret fails. */
665 	mib[2] = TEST_SECRET;
666 	mib[3] = CTL_QUERY;
667 	if (sysctl(mib, 4, NULL, &oldlen, NULL, 0) != -1) e(0);
668 	if (errno != EPERM) e(0);
669 }
670 
671 /*
672  * Test sysctl(2) queries.
673  */
674 static void
675 test87b(void)
676 {
677 	struct sysctlnode scn[32];
678 	unsigned int count;
679 	size_t len, oldlen;
680 	u_quad_t q;
681 	bool b;
682 	int i, mib[4];
683 
684 	subtest = 1;
685 
686 	/* We should be able to query the root key. */
687 	mib[0] = CTL_QUERY;
688 
689 	oldlen = 0;
690 	if (sysctl(mib, 1, NULL, &oldlen, NULL, 0) != 0) e(0);
691 	if (oldlen <= sizeof(scn[0])) e(0);
692 	if (oldlen % sizeof(scn[0])) e(0);
693 
694 	oldlen = sizeof(scn[0]);
695 	if (sysctl(mib, 1, scn, &oldlen, NULL, 0) != -1) e(0);
696 	if (errno != ENOMEM);
697 	if (oldlen <= sizeof(scn[0])) e(0);
698 	if (oldlen % sizeof(scn[0])) e(0);
699 
700 	/*
701 	 * We assume that the root node's first child is always CTL_KERN, which
702 	 * must be read-only and may have only the CTLFLAG_PERMANENT flag set.
703 	 */
704 	if (scn[0].sysctl_num != CTL_KERN) e(0);
705 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_NODE) e(0);
706 	if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
707 	    CTLFLAG_READONLY) e(0);
708 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
709 	if (strcmp(scn[0].sysctl_name, "kern")) e(0);
710 	if (scn[0].sysctl_ver == 0) e(0);
711 	if (scn[0].sysctl_size != sizeof(scn[0])) e(0);
712 	if ((int)scn[0].sysctl_csize <= 0) e(0);
713 	if ((int)scn[0].sysctl_clen <= 0) e(0);
714 	if (scn[0].sysctl_csize < scn[0].sysctl_clen) e(0);
715 
716 	/* Now do a more complete test on the minix.test subtree. */
717 	mib[0] = CTL_MINIX;
718 	mib[1] = MINIX_TEST;
719 
720 	/*
721 	 * Initialize a few immediate fields to nonzero so that we can test
722 	 * that their values are returned as a result of the query.
723 	 */
724 	mib[2] = TEST_BOOL;
725 	b = true;
726 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
727 
728 	mib[2] = TEST_QUAD;
729 	q = ~0;
730 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
731 
732 	mib[2] = CTL_QUERY;
733 
734 	oldlen = 1;
735 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
736 	if (oldlen % sizeof(scn[0])) e(0);
737 	if (oldlen >= sizeof(scn)) e(0);
738 	len = oldlen;
739 	count = len / sizeof(scn[0]);
740 	if (count < 8) e(0);
741 
742 	memset(scn, 0x7e, sizeof(scn));
743 	if (sysctl(mib, 3, scn, &oldlen, NULL, 0) != 0) e(0);
744 	if (oldlen != len) e(0);
745 	if (scn[count].sysctl_name[0] != 0x7e) e(0);
746 
747 	/*
748 	 * Again, we rely on the MIB service returning entries in ascending
749 	 * order for at least the static nodes.  We do not make assumptions
750 	 * about whether dynamic nodes are merged in or (as is the case as of
751 	 * writing) returned after the static nodes.  At this point there
752 	 * should be no dynamic nodes here yet anyway.
753 	 */
754 	if (scn[0].sysctl_num != TEST_INT) e(0);
755 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
756 	if (SYSCTL_FLAGS(scn[0].sysctl_flags) !=
757 	    (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE | CTLFLAG_HEX)) e(0);
758 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
759 	if (strcmp(scn[0].sysctl_name, "int")) e(0);
760 	if (scn[0].sysctl_ver == 0) e(0);
761 	if (scn[0].sysctl_size != sizeof(int)) e(0);
762 	if (scn[0].sysctl_idata != 0x01020304) e(0);
763 
764 	if (scn[1].sysctl_num != TEST_BOOL) e(0);
765 	if (SYSCTL_TYPE(scn[1].sysctl_flags) != CTLTYPE_BOOL) e(0);
766 	if (SYSCTL_FLAGS(scn[1].sysctl_flags) !=
767 	    (CTLFLAG_READWRITE | CTLFLAG_IMMEDIATE)) e(0);
768 	if (SYSCTL_VERS(scn[1].sysctl_flags) != SYSCTL_VERSION) e(0);
769 	if (strcmp(scn[1].sysctl_name, "bool")) e(0);
770 	if (scn[1].sysctl_ver == 0) e(0);
771 	if (scn[1].sysctl_size != sizeof(bool)) e(0);
772 	if (scn[1].sysctl_bdata != true) e(0);
773 
774 	if (scn[2].sysctl_num != TEST_QUAD) e(0);
775 	if (SYSCTL_TYPE(scn[2].sysctl_flags) != CTLTYPE_QUAD) e(0);
776 	if (SYSCTL_FLAGS(scn[2].sysctl_flags) !=
777 	    (CTLFLAG_READWRITE | CTLFLAG_IMMEDIATE)) e(0);
778 	if (SYSCTL_VERS(scn[2].sysctl_flags) != SYSCTL_VERSION) e(0);
779 	if (strcmp(scn[2].sysctl_name, "quad")) e(0);
780 	if (scn[2].sysctl_ver == 0) e(0);
781 	if (scn[2].sysctl_size != sizeof(u_quad_t)) e(0);
782 	if (scn[2].sysctl_qdata != q) e(0);
783 
784 	if (scn[3].sysctl_num != TEST_STRING) e(0);
785 	if (SYSCTL_TYPE(scn[3].sysctl_flags) != CTLTYPE_STRING) e(0);
786 	if (SYSCTL_FLAGS(scn[3].sysctl_flags) != CTLFLAG_READWRITE) e(0);
787 	if (SYSCTL_VERS(scn[3].sysctl_flags) != SYSCTL_VERSION) e(0);
788 	if (strcmp(scn[3].sysctl_name, "string")) e(0);
789 	if (scn[3].sysctl_ver == 0) e(0);
790 	if (scn[3].sysctl_size != 16) e(0);
791 
792 	if (scn[4].sysctl_num != TEST_STRUCT) e(0);
793 	if (SYSCTL_TYPE(scn[4].sysctl_flags) != CTLTYPE_STRUCT) e(0);
794 	if (SYSCTL_FLAGS(scn[4].sysctl_flags) != CTLFLAG_READWRITE) e(0);
795 	if (SYSCTL_VERS(scn[4].sysctl_flags) != SYSCTL_VERSION) e(0);
796 	if (strcmp(scn[4].sysctl_name, "struct")) e(0);
797 	if (scn[4].sysctl_ver == 0) e(0);
798 	if (scn[4].sysctl_size != 12) e(0);
799 
800 	if (scn[5].sysctl_num != TEST_PRIVATE) e(0);
801 	if (SYSCTL_TYPE(scn[5].sysctl_flags) != CTLTYPE_INT) e(0);
802 	if (SYSCTL_FLAGS(scn[5].sysctl_flags) !=
803 	    (CTLFLAG_READWRITE | CTLFLAG_PRIVATE | CTLFLAG_IMMEDIATE)) e(0);
804 	if (SYSCTL_VERS(scn[5].sysctl_flags) != SYSCTL_VERSION) e(0);
805 	if (strcmp(scn[5].sysctl_name, "private")) e(0);
806 	if (scn[5].sysctl_ver == 0) e(0);
807 	if (scn[5].sysctl_size != sizeof(int)) e(0);
808 	if (scn[5].sysctl_idata != -5375) e(0);
809 
810 	if (scn[6].sysctl_num != TEST_ANYWRITE) e(0);
811 	if (SYSCTL_TYPE(scn[6].sysctl_flags) != CTLTYPE_INT) e(0);
812 	if (SYSCTL_FLAGS(scn[6].sysctl_flags) !=
813 	    (CTLFLAG_READWRITE | CTLFLAG_ANYWRITE | CTLFLAG_IMMEDIATE)) e(0);
814 	if (SYSCTL_VERS(scn[6].sysctl_flags) != SYSCTL_VERSION) e(0);
815 	if (strcmp(scn[6].sysctl_name, "anywrite")) e(0);
816 	if (scn[6].sysctl_ver == 0) e(0);
817 	if (scn[6].sysctl_size != sizeof(int)) e(0);
818 
819 	i = (scn[7].sysctl_num == TEST_DYNAMIC) ? 8 : 7;
820 
821 	if (scn[i].sysctl_num != TEST_SECRET) e(0);
822 	if (SYSCTL_TYPE(scn[i].sysctl_flags) != CTLTYPE_NODE) e(0);
823 	if (SYSCTL_FLAGS(scn[i].sysctl_flags) !=
824 	    (CTLFLAG_READONLY | CTLFLAG_PRIVATE)) e(0);
825 	if (SYSCTL_VERS(scn[i].sysctl_flags) != SYSCTL_VERSION) e(0);
826 	if (strcmp(scn[i].sysctl_name, "secret")) e(0);
827 	if (scn[i].sysctl_ver == 0) e(0);
828 	if (scn[i].sysctl_size != sizeof(scn[0])) e(0);
829 	if (scn[i].sysctl_csize != 1) e(0);
830 	if (scn[i].sysctl_clen != 1) e(0);
831 
832 	/*
833 	 * Now that we know how many entries there are in minix.test, also look
834 	 * at whether the right child length is returned in a query on its
835 	 * parent.  While doing that, see whether data structure versioning
836 	 * works as expected as well.  MINIX_TEST is hardcoded to zero so we
837 	 * expect it to be the first entry returned from a query.
838 	 */
839 	mib[1] = CTL_QUERY;
840 
841 	memset(scn, 0, sizeof(scn));
842 	scn[1].sysctl_flags = SYSCTL_VERS_0;
843 	if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1])) != -1) e(0);
844 	if (errno != EINVAL) e(0);
845 	scn[1].sysctl_flags = SYSCTL_VERS_1;
846 	if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1]) - 1) != -1)
847 		e(0);
848 	if (errno != EINVAL) e(0);
849 	if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1]) + 1) != -1)
850 		e(0);
851 	if (errno != EINVAL) e(0);
852 	if (sysctl(mib, 2, NULL, &oldlen, &scn[1], sizeof(scn[1])) != 0) e(0);
853 	if (oldlen == 0) e(0);
854 	if (oldlen % sizeof(scn[0])) e(0);
855 
856 	oldlen = sizeof(scn[0]);
857 	scn[1].sysctl_flags = SYSCTL_VERS_0;
858 	if (sysctl(mib, 2, scn, &oldlen, &scn[1], sizeof(scn[1])) != -1) e(0);
859 	if (errno != EINVAL) e(0);
860 	oldlen = sizeof(scn[0]);
861 	scn[1].sysctl_flags = SYSCTL_VERS_1;
862 	if (sysctl(mib, 2, scn, &oldlen, &scn[1], sizeof(scn[1])) != 0 &&
863 	    errno != ENOMEM) e(0);
864 	if (oldlen == 0) e(0);
865 	if (oldlen % sizeof(scn[0])) e(0);
866 
867 	if (scn[0].sysctl_num != MINIX_TEST) e(0);
868 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_NODE) e(0);
869 	if ((SYSCTL_FLAGS(scn[0].sysctl_flags) & ~CTLFLAG_PERMANENT) !=
870 	    (CTLFLAG_READWRITE | CTLFLAG_HIDDEN)) e(0);
871 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
872 	if (strcmp(scn[0].sysctl_name, "test")) e(0);
873 	if (scn[0].sysctl_ver == 0) e(0);
874 	if (scn[0].sysctl_size != sizeof(scn[0])) e(0);
875 	if ((int)scn[0].sysctl_clen != count) e(0);
876 	if (scn[0].sysctl_csize < scn[0].sysctl_clen) e(0);
877 
878 	/*
879 	 * Test querying minix.test.secret, which should have exactly one node.
880 	 * At the same time, test bad pointers.
881 	 */
882 	mib[1] = MINIX_TEST;
883 	mib[2] = TEST_SECRET;
884 	mib[3] = CTL_QUERY;
885 	oldlen = sizeof(scn);
886 	if (sysctl(mib, 4, NULL, &oldlen, bad_ptr, sizeof(scn[0])) != -1) e(0);
887 	if (errno != EFAULT) e(0);
888 
889 	oldlen = sizeof(scn[0]) * 2;
890 	if (sysctl(mib, 4, bad_ptr, &oldlen, NULL, 0) != -1) e(0);
891 	if (errno != EFAULT) e(0);
892 
893 	memset(scn, 0x7, sizeof(scn[0]) * 2);
894 	oldlen = sizeof(scn[0]) * 2;
895 	if (sysctl(mib, 4, scn, &oldlen, NULL, 0) != 0) e(0);
896 	if (oldlen != sizeof(scn[0])) e(0);
897 
898 	if (scn[0].sysctl_num != SECRET_VALUE) e(0);
899 	if (SYSCTL_TYPE(scn[0].sysctl_flags) != CTLTYPE_INT) e(0);
900 	if (SYSCTL_FLAGS(scn[0].sysctl_flags) !=
901 	    (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE)) e(0);
902 	if (SYSCTL_VERS(scn[0].sysctl_flags) != SYSCTL_VERSION) e(0);
903 	if (strcmp(scn[0].sysctl_name, "value")) e(0);
904 	if (scn[0].sysctl_ver == 0) e(0);
905 	if (scn[0].sysctl_size != sizeof(int)) e(0);
906 	if (scn[0].sysctl_idata != 12345) e(0);
907 	if (scn[1].sysctl_name[0] != 0x07) e(0);
908 
909 	/* Use a child process to test queries without root privileges. */
910 	(void)test_nonroot(sub87b);
911 
912 	/* Do some more path-related error code tests unrelated to the rest. */
913 	mib[1] = INT_MAX;
914 	mib[2] = CTL_QUERY;
915 	oldlen = sizeof(scn[0]);
916 	if (sysctl(mib, 3, &scn, &oldlen, NULL, 0) != -1) e(0);
917 	if (errno != ENOENT) e(0);
918 
919 	mib[1] = MINIX_TEST;
920 	mib[2] = TEST_INT;
921 	mib[3] = CTL_QUERY;
922 	oldlen = sizeof(scn[0]);
923 	if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
924 	if (errno != ENOTDIR) e(0); /* ..and not EPERM (_INT is read-only) */
925 
926 	mib[2] = TEST_BOOL;
927 	oldlen = sizeof(scn[0]);
928 	if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
929 	if (errno != ENOTDIR) e(0); /* (_BOOL is read-write) */
930 
931 	mib[2] = CTL_QUERY;
932 	oldlen = sizeof(scn[0]);
933 	if (sysctl(mib, 4, &scn, &oldlen, NULL, 0) != -1) e(0);
934 	if (errno != EINVAL) e(0);
935 }
936 
937 /*
938  * Attempt to create a node, using a given node template, identifier, and name
939  * string.  If other_id is nonnegative, the creation is expected to fail due to
940  * a collision with an existing node, which should have the ID other_id and the
941  * name string in other_name.  Otherwise, the creation may succeed or fail, and
942  * the caller must perform the appropriate checks.  On success, return the new
943  * node identifier.  On failure, return -1, with errno set.
944  */
945 static int
946 create_node(const int * path, unsigned int pathlen, struct sysctlnode * tmpscn,
947 	int id, const char * name, int other_id, const char * other_name)
948 {
949 	struct sysctlnode scn, oldscn;
950 	size_t oldlen;
951 	int r, mib[CTL_MAXNAME];
952 
953 	assert(pathlen < CTL_MAXNAME);
954 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
955 	mib[pathlen] = CTL_CREATE;
956 
957 	memcpy(&scn, tmpscn, sizeof(scn));
958 	scn.sysctl_num = id;
959 	strlcpy(scn.sysctl_name, name, sizeof(scn.sysctl_name));
960 	oldlen = sizeof(oldscn);
961 	r = sysctl(mib, pathlen + 1, &oldscn, &oldlen, &scn, sizeof(scn));
962 	if (other_id >= 0) { /* conflict expected */
963 		if (oldlen != sizeof(oldscn)) e(0);
964 		if (r != -1) e(0);
965 		if (errno != EEXIST) e(0);
966 		if (oldscn.sysctl_num != other_id) e(0);
967 		if (strcmp(oldscn.sysctl_name, other_name)) e(0);
968 		return -1;
969 	} else {
970 		if (r != 0)
971 			return r;
972 		if (oldlen != sizeof(oldscn)) e(0);
973 		return oldscn.sysctl_num;
974 	}
975 }
976 
977 /*
978  * Destroy a node by identifier in the given named node directory.  Return 0 on
979  * success.  Return -1 on failure, with errno set.
980  */
981 static int
982 destroy_node(const int * path, unsigned int pathlen, int id)
983 {
984 	struct sysctlnode scn;
985 	int mib[CTL_MAXNAME];
986 
987 	assert(pathlen < CTL_MAXNAME);
988 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
989 	mib[pathlen] = CTL_DESTROY;
990 
991 	memset(&scn, 0, sizeof(scn));
992 	scn.sysctl_flags = SYSCTL_VERSION;
993 	scn.sysctl_num = id;
994 
995 	return sysctl(mib, pathlen + 1, NULL, NULL, &scn, sizeof(scn));
996 }
997 
998 /*
999  * Obtain the node data for one particular node in a node directory, by its
1000  * parent path and identifier.  Return 0 on success, with the node details
1001  * stored in 'scn', or -1 on failure.
1002  */
1003 static int
1004 query_node(const int * path, unsigned int pathlen, int id,
1005 	struct sysctlnode * scn)
1006 {
1007 	struct sysctlnode scnset[32];
1008 	size_t oldlen;
1009 	unsigned int i;
1010 	int r, mib[CTL_MAXNAME];
1011 
1012 	assert(pathlen < CTL_MAXNAME);
1013 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
1014 	mib[pathlen] = CTL_QUERY;
1015 
1016 	oldlen = sizeof(scnset);
1017 	if ((r = sysctl(mib, pathlen + 1, scnset, &oldlen, NULL, 0)) != 0 &&
1018 	    errno != ENOMEM) e(0);
1019 	if (oldlen == 0 || oldlen % sizeof(scnset[0])) e(0);
1020 	for (i = 0; i < oldlen / sizeof(scnset[0]); i++)
1021 		if (scnset[i].sysctl_num == id)
1022 			break;
1023 	if (i == oldlen / sizeof(scnset[0])) {
1024 		if (r != 0) e(0); /* if this triggers, make scnset[] bigger! */
1025 		return -1;
1026 	}
1027 	memcpy(scn, &scnset[i], sizeof(*scn));
1028 	return 0;
1029 }
1030 
1031 /*
1032  * Test unprivileged node creation.
1033  */
1034 static void
1035 sub87c(void)
1036 {
1037 	struct sysctlnode scn;
1038 	int mib[4];
1039 
1040 	mib[0] = CTL_MINIX;
1041 	mib[1] = MINIX_TEST;
1042 	mib[2] = TEST_DYNAMIC;
1043 	mib[3] = CTL_CREATE;
1044 
1045 	memset(&scn, 0, sizeof(scn));
1046 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
1047 	    CTLFLAG_READONLY | CTLTYPE_INT;
1048 	scn.sysctl_size = sizeof(int);
1049 	scn.sysctl_num = CTL_CREATE;
1050 	scn.sysctl_idata = 777;
1051 	strlcpy(scn.sysctl_name, "nonroot", sizeof(scn.sysctl_name));
1052 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1053 	if (errno != EPERM) e(0);
1054 
1055 	mib[0] = CTL_CREATE;
1056 	scn.sysctl_num = CTL_MINIX + 1;
1057 	if (sysctl(mib, 1, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1058 	if (errno != EPERM) e(0);
1059 }
1060 
1061 /*
1062  * Test sysctl(2) node creation.
1063  */
1064 static void
1065 test87c(void)
1066 {
1067 	static const uint32_t badflags[] = {
1068 		SYSCTL_VERS_MASK, SYSCTL_TYPEMASK, CTLFLAG_PERMANENT,
1069 		CTLFLAG_ROOT, CTLFLAG_ANYNUMBER, CTLFLAG_ALIAS, CTLFLAG_MMAP,
1070 		CTLFLAG_OWNDESC
1071 	};
1072 	static const size_t badintsizes[] = {
1073 		0, 1, sizeof(int) - 1, sizeof(int) + 1, sizeof(int) * 2,
1074 		sizeof(int) * 4, SSIZE_MAX, SIZE_MAX
1075 	};
1076 	static const char *goodnames[] = {
1077 		"_", "a", "test_name", "_____foo", "bar_0_1_2_3", "_2bornot2b",
1078 		"abcdefghijklmnopqrstuvwxyz12345",
1079 		"ABCDEFGHIJKLMNOPQRSTUVWXYZ67890",
1080 	};
1081 	static const char *badnames[] = {
1082 		"", "0", "test.name", "2bornot2b", "@a", "b[", "c`d", "{",
1083 		"\n", "\xff", "dir/name", "foo:bar",
1084 		"abcdefghijklmnopqrstuvwxyz123456"
1085 	};
1086 	struct sysctlnode scn, pscn, oldscn, newscn, tmpscn, scnset[32];
1087 	size_t oldlen, len;
1088 	char buf[32], seen[5];
1089 	bool b;
1090 	u_quad_t q;
1091 	int i, mib[CTL_MAXNAME], id[3];
1092 
1093 	subtest = 2;
1094 
1095 	/*
1096 	 * On the first run of this test, this call with actually destroy a
1097 	 * static node.  On subsequent runs, it may clean up the most likely
1098 	 * leftover from a previous failed test.
1099 	 */
1100 	mib[0] = CTL_MINIX;
1101 	mib[1] = MINIX_TEST;
1102 	(void)destroy_node(mib, 2, TEST_DYNAMIC);
1103 
1104 	/* Get child statistics about the parent node, for later comparison. */
1105 	if (query_node(mib, 1, MINIX_TEST, &pscn) != 0) e(0);
1106 	if (pscn.sysctl_clen == 0) e(0);
1107 	if (pscn.sysctl_csize <= pscn.sysctl_clen) e(0);
1108 
1109 	/* Start by testing if we can actually create a node at all. */
1110 	mib[2] = CTL_CREATE;
1111 	memset(&scn, 0, sizeof(scn));
1112 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
1113 	    CTLFLAG_READONLY | CTLTYPE_INT;
1114 	scn.sysctl_size = sizeof(int);
1115 	scn.sysctl_num = TEST_DYNAMIC;
1116 	scn.sysctl_idata = 777;
1117 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
1118 	oldlen = sizeof(newscn);
1119 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1120 	if (oldlen != sizeof(newscn)) e(0);
1121 
1122 	memcpy(&tmpscn, &scn, sizeof(scn));
1123 
1124 	if (newscn.sysctl_num != TEST_DYNAMIC) e(0);
1125 	if (SYSCTL_TYPE(newscn.sysctl_flags) != CTLTYPE_INT) e(0);
1126 	if (SYSCTL_FLAGS(newscn.sysctl_flags) !=
1127 	    (CTLFLAG_READONLY | CTLFLAG_IMMEDIATE)) e(0);
1128 	if (SYSCTL_VERS(newscn.sysctl_flags) != SYSCTL_VERSION) e(0);
1129 	if (strcmp(newscn.sysctl_name, "dynamic")) e(0);
1130 	if (newscn.sysctl_ver == 0) e(0);
1131 	if (newscn.sysctl_size != sizeof(int)) e(0);
1132 	if (newscn.sysctl_idata != 777) e(0);
1133 
1134 	/* Can we also read its value? */
1135 	mib[2] = TEST_DYNAMIC;
1136 	i = 0;
1137 	oldlen = sizeof(i);
1138 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1139 	if (oldlen != sizeof(i)) e(0);
1140 	if (i != 777) e(0);
1141 
1142 	/* For now, we assume that basic node destruction works. */
1143 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1144 
1145 	/* Try some variants of invalid new node data. */
1146 	mib[2] = CTL_CREATE;
1147 	memcpy(&scn, &tmpscn, sizeof(scn));
1148 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
1149 	if (errno != EINVAL) e(0);
1150 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn) - 1) != -1) e(0);
1151 	if (errno != EINVAL) e(0);
1152 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn) + 1) != -1) e(0);
1153 	if (errno != EINVAL) e(0);
1154 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
1155 	if (errno != EFAULT) e(0);
1156 
1157 	/* Try with an invalid flags field. */
1158 	scn.sysctl_flags =
1159 	    (scn.sysctl_flags & ~SYSCTL_VERS_MASK) | SYSCTL_VERS_0;
1160 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1161 	if (errno != EINVAL) e(0);
1162 
1163 	scn.sysctl_flags &= ~SYSCTL_TYPEMASK; /* type 0 does not exist */
1164 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1165 	if (errno != EINVAL) e(0);
1166 
1167 	for (i = 0; i < __arraycount(badflags); i++) {
1168 		memcpy(&scn, &tmpscn, sizeof(scn));
1169 		scn.sysctl_flags |= badflags[i];
1170 		if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1171 		if (errno != EINVAL) e(i);
1172 	}
1173 
1174 	/* Try successful creation (and destruction) once more. */
1175 	memcpy(&scn, &tmpscn, sizeof(scn));
1176 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1177 
1178 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1179 
1180 	/* Try a combination of most valid flags. */
1181 	memcpy(&scn, &tmpscn, sizeof(scn));
1182 	scn.sysctl_flags &= ~CTLFLAG_READONLY; /* noop */
1183 	scn.sysctl_flags |= CTLFLAG_READWRITE | CTLFLAG_ANYWRITE |
1184 	    CTLFLAG_PRIVATE | CTLFLAG_HEX | CTLFLAG_HIDDEN | CTLFLAG_UNSIGNED;
1185 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1186 
1187 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1188 
1189 	/* Try invalid integer sizes.  We will get to other types in a bit. */
1190 	for (i = 0; i < __arraycount(badintsizes); i++) {
1191 		memcpy(&scn, &tmpscn, sizeof(scn));
1192 		scn.sysctl_size = badintsizes[i];
1193 		if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1194 		if (errno != EINVAL) e(i);
1195 	}
1196 
1197 	/*
1198 	 * For the value, we can supply IMMEDIATE, OWNDATA, or neither.  For
1199 	 * IMMEDIATE, the integer value is taken directly from sysctl_idata.
1200 	 * If OWNDATA is set, sysctl_data may be set, in which case the integer
1201 	 * value is copied in from there.  If sysctl_data is NULL, the integer
1202 	 * is initalized to zero.  If neither flag is set, sysctl_data must be
1203 	 * NULL, since we do not support kernel addresses, and the integer will
1204 	 * similarly be initialized to zero.  If both flags are set, the call
1205 	 * fails with EINVAL.
1206 	 */
1207 	memcpy(&scn, &tmpscn, sizeof(scn));
1208 	scn.sysctl_flags |= CTLFLAG_OWNDATA; /* both flags are now set */
1209 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1210 	if (errno != EINVAL) e(0);
1211 
1212 	scn.sysctl_flags &= ~(CTLFLAG_IMMEDIATE | CTLFLAG_OWNDATA);
1213 	scn.sysctl_data = &i;
1214 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1215 	if (errno != EINVAL) e(0);
1216 
1217 	scn.sysctl_data = NULL;
1218 	oldlen = sizeof(newscn);
1219 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1220 	if (oldlen != sizeof(newscn)) e(0);
1221 	if (newscn.sysctl_flags & CTLFLAG_IMMEDIATE) e(0);
1222 	if (!(newscn.sysctl_flags & CTLFLAG_OWNDATA)) e(0); /* auto-set */
1223 	if (newscn.sysctl_idata != 0) e(0);
1224 
1225 	mib[2] = TEST_DYNAMIC;
1226 	oldlen = sizeof(i);
1227 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1228 	if (oldlen != sizeof(i)) e(0);
1229 	if (i != 0) e(0);
1230 
1231 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1232 
1233 	mib[2] = CTL_CREATE;
1234 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1235 	scn.sysctl_data = NULL;
1236 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1237 
1238 	mib[2] = TEST_DYNAMIC;
1239 	i = -1;
1240 	oldlen = sizeof(i);
1241 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1242 	if (oldlen != sizeof(i)) e(0);
1243 	if (i != 0) e(0);
1244 
1245 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1246 
1247 	mib[2] = CTL_CREATE;
1248 	scn.sysctl_data = bad_ptr;
1249 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1250 	if (errno != EFAULT) e(0);
1251 
1252 	i = 999;
1253 	scn.sysctl_data = (void *)&i;
1254 	oldlen = sizeof(newscn);
1255 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1256 	if (oldlen != sizeof(newscn)) e(0);
1257 	if ((newscn.sysctl_flags & (CTLFLAG_IMMEDIATE | CTLFLAG_OWNDATA)) !=
1258 	    CTLFLAG_OWNDATA) e(0);
1259 	if (newscn.sysctl_idata != 0) e(0);
1260 
1261 	mib[2] = TEST_DYNAMIC;
1262 	oldlen = sizeof(i);
1263 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
1264 	if (oldlen != sizeof(i)) e(0);
1265 	if (i != 999) e(0);
1266 
1267 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1268 
1269 	/* The user may never supply a function pointer or a parent. */
1270 	mib[2] = CTL_CREATE;
1271 	memcpy(&scn, &tmpscn, sizeof(scn));
1272 	scn.sysctl_func = (sysctlfn)test87c;
1273 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1274 	if (errno != EINVAL) e(0);
1275 
1276 	memcpy(&scn, &tmpscn, sizeof(scn));
1277 	scn.sysctl_parent = &scn;
1278 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1279 	if (errno != EINVAL) e(0);
1280 
1281 	/* Test some good and bad node names. */
1282 	for (i = 0; i < __arraycount(goodnames); i++) {
1283 		memcpy(&scn, &tmpscn, sizeof(scn));
1284 		len = strlen(goodnames[i]);
1285 		memcpy(scn.sysctl_name, goodnames[i], len);
1286 		memset(&scn.sysctl_name[len], 0, SYSCTL_NAMELEN - len);
1287 		if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(i);
1288 
1289 		if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(i);
1290 	}
1291 
1292 	for (i = 0; i < __arraycount(badnames); i++) {
1293 		memcpy(&scn, &tmpscn, sizeof(scn));
1294 		len = strlen(badnames[i]);
1295 		memcpy(scn.sysctl_name, badnames[i], len);
1296 		memset(&scn.sysctl_name[len], 0, SYSCTL_NAMELEN - len);
1297 		if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(i);
1298 		if (errno != EINVAL) e(i);
1299 	}
1300 
1301 	/*
1302 	 * Check for ID and name conflicts with existing nodes, starting with
1303 	 * the basics.
1304 	 */
1305 	memcpy(&scn, &tmpscn, sizeof(scn));
1306 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1307 
1308 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1309 	if (errno != EEXIST) e(0);
1310 
1311 	oldlen = sizeof(oldscn);
1312 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1313 	if (errno != EEXIST) e(0);
1314 	if (oldlen != sizeof(oldscn)) e(0);
1315 	if (oldscn.sysctl_ver == 0) e(0);
1316 	oldscn.sysctl_ver = 0;
1317 	if (memcmp(&oldscn, &tmpscn, sizeof(oldscn))) e(0);
1318 
1319 	oldlen = sizeof(oldscn) - 1;
1320 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1321 	if (errno != EEXIST) e(0); /* ..we should not get ENOMEM now */
1322 	if (oldlen != sizeof(oldscn)) e(0);
1323 
1324 	oldlen = sizeof(oldscn);
1325 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1326 	if (errno != EEXIST) e(0); /* ..we should not get EFAULT now */
1327 	if (oldlen != 0) e(0); /* this is arguably an implementation detail */
1328 
1329 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1330 
1331 	/* Test ID and name conflicts against static nodes. */
1332 	if (create_node(mib, 2, &tmpscn, TEST_INT, "dynamic", TEST_INT,
1333 	    "int") != -1) e(0);
1334 	if (create_node(mib, 2, &tmpscn, TEST_SECRET, "dynamic", TEST_SECRET,
1335 	    "secret") != -1) e(0);
1336 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "quad", TEST_QUAD,
1337 	    "quad") != -1) e(0);
1338 
1339 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
1340 	    NULL) != TEST_DYNAMIC) e(0);
1341 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1342 
1343 	/* Test unique ID generation and LL back insertion. */
1344 	if ((id[0] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id0", -1,
1345 	    NULL)) == -1) e(0);
1346 	if ((id[1] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id1", -1,
1347 	    NULL)) == -1) e(0);
1348 	if ((id[2] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id2", -1,
1349 	    NULL)) == -1) e(0);
1350 	if (id[0] < CREATE_BASE || id[1] < CREATE_BASE || id[2] < CREATE_BASE)
1351 		e(0);
1352 	if (id[0] == id[1] || id[1] == id[2] || id[0] == id[2]) e(0);
1353 
1354 	if (destroy_node(mib, 2, id[1]) != 0) e(0);
1355 
1356 	/* Test ID and name conflicts against dynamic nodes. */
1357 	if (create_node(mib, 2, &tmpscn, id[0], "id1", id[0],
1358 	    "id0") != -1) e(0);
1359 	if (create_node(mib, 2, &tmpscn, id[2], "id1", id[2],
1360 	    "id2") != -1) e(0);
1361 	if (create_node(mib, 2, &tmpscn, id[1], "id0", id[0],
1362 	    "id0") != -1) e(0);
1363 	if (create_node(mib, 2, &tmpscn, id[1], "id2", id[2],
1364 	    "id2") != -1) e(0);
1365 
1366 	/* Test name conflicts before and after LL insertion point. */
1367 	if (create_node(mib, 2, &tmpscn, CTL_CREATE, "id0", id[0],
1368 	    "id0") != -1) e(0);
1369 	if (create_node(mib, 2, &tmpscn, CTL_CREATE, "id2", id[2],
1370 	    "id2") != -1) e(0);
1371 
1372 	/* Test recreation by ID and LL middle insertion. */
1373 	if (create_node(mib, 2, &tmpscn, id[1], "id1", -1, NULL) == -1) e(0);
1374 	if (destroy_node(mib, 2, id[1]) != 0) e(0);
1375 
1376 	/* Test dynamic recreation and more LL middle insertion. */
1377 	if ((id[1] = create_node(mib, 2, &tmpscn, CTL_CREATE, "id1", -1,
1378 	    NULL)) == -1) e(0);
1379 	if (id[1] < CREATE_BASE) e(0);
1380 	if (id[1] == id[0] || id[1] == id[2]) e(0);
1381 
1382 	/* Test LL front insertion. */
1383 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
1384 	    NULL) == -1) e(0);
1385 
1386 	/* Ensure that all dynamic nodes show up in a query. */
1387 	mib[2] = CTL_QUERY;
1388 	oldlen = sizeof(scnset);
1389 	memset(seen, 0, sizeof(seen));
1390 	memset(scnset, 0, sizeof(scnset));
1391 	if (sysctl(mib, 3, scnset, &oldlen, NULL, 0) != 0) e(0);
1392 	if (oldlen % sizeof(scn)) e(0);
1393 	for (i = 0; (unsigned int)i < oldlen / sizeof(scn); i++) {
1394 		if (scnset[i].sysctl_num == TEST_INT) {
1395 			if (strcmp(scnset[i].sysctl_name, "int")) e(0);
1396 			seen[0]++;
1397 		} else if (scnset[i].sysctl_num == TEST_DYNAMIC) {
1398 			if (strcmp(scnset[i].sysctl_name, "dynamic")) e(0);
1399 			seen[1]++;
1400 		} else if (scnset[i].sysctl_num == id[0]) {
1401 			if (strcmp(scnset[i].sysctl_name, "id0")) e(0);
1402 			seen[2]++;
1403 		} else if (scnset[i].sysctl_num == id[1]) {
1404 			if (strcmp(scnset[i].sysctl_name, "id1")) e(0);
1405 			seen[3]++;
1406 		} else if (scnset[i].sysctl_num == id[2]) {
1407 			if (strcmp(scnset[i].sysctl_name, "id2")) e(0);
1408 			seen[4]++;
1409 		}
1410 	}
1411 	for (i = 0; i < 5; i++)
1412 		if (seen[i] != 1) e(i);
1413 
1414 	/* Compare the parent's statistics with those obtained earlier. */
1415 	if (query_node(mib, 1, MINIX_TEST, &scn) != 0) e(0);
1416 	if (scn.sysctl_clen != pscn.sysctl_clen + 4) e(0);
1417 	if (scn.sysctl_csize != pscn.sysctl_csize + 4) e(0);
1418 
1419 	/* Clean up. */
1420 	if (destroy_node(mib, 2, id[0]) != 0) e(0);
1421 	if (destroy_node(mib, 2, id[1]) != 0) e(0);
1422 	if (destroy_node(mib, 2, id[2]) != 0) e(0);
1423 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1424 
1425 	/* Copy-out errors should not result in the node not being created. */
1426 	mib[2] = CTL_CREATE;
1427 	memcpy(&scn, &tmpscn, sizeof(scn));
1428 	oldlen = sizeof(newscn) - 1;
1429 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1430 	if (errno != ENOMEM) e(0);
1431 	if (oldlen != sizeof(newscn)) e(0);
1432 
1433 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1434 
1435 	oldlen = sizeof(newscn);
1436 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
1437 	if (errno != EFAULT) e(0);
1438 
1439 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1440 
1441 	oldlen = sizeof(newscn) + 1;
1442 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
1443 	if (oldlen != sizeof(newscn)) e(0);
1444 
1445 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1446 
1447 	/*
1448 	 * Now that we are done with the integer template, try other data
1449 	 * types, starting with booleans.  A big part of these tests is that
1450 	 * the creation results in a usable node, regardless of the way its
1451 	 * contents were initialized.
1452 	 */
1453 	tmpscn.sysctl_flags =
1454 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_BOOL;
1455 	tmpscn.sysctl_size = sizeof(b);
1456 	tmpscn.sysctl_data = NULL;
1457 
1458 	mib[2] = CTL_CREATE;
1459 	memcpy(&scn, &tmpscn, sizeof(scn));
1460 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1461 
1462 	mib[2] = TEST_DYNAMIC;
1463 	oldlen = sizeof(b);
1464 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1465 	if (oldlen != sizeof(b)) e(0);
1466 	if (b != false) e(0);
1467 
1468 	b = true;
1469 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
1470 
1471 	oldlen = sizeof(b);
1472 	b = false;
1473 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1474 	if (oldlen != sizeof(b)) e(0);
1475 	if (b != true) e(0);
1476 
1477 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1478 
1479 	mib[2] = CTL_CREATE;
1480 	memcpy(&scn, &tmpscn, sizeof(scn));
1481 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1482 	scn.sysctl_bdata = true;
1483 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1484 
1485 	mib[2] = TEST_DYNAMIC;
1486 	oldlen = sizeof(b);
1487 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1488 	if (oldlen != sizeof(b)) e(0);
1489 	if (b != true) e(0);
1490 
1491 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1492 
1493 	mib[2] = CTL_CREATE;
1494 	scn.sysctl_bdata = false;
1495 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1496 
1497 	mib[2] = TEST_DYNAMIC;
1498 	oldlen = sizeof(b);
1499 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1500 	if (oldlen != sizeof(b)) e(0);
1501 	if (b != false) e(0);
1502 
1503 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1504 
1505 	mib[2] = CTL_CREATE;
1506 	memcpy(&scn, &tmpscn, sizeof(scn));
1507 	scn.sysctl_data = &b;
1508 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1509 	if (errno != EINVAL) e(0);
1510 
1511 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1512 	scn.sysctl_size++;
1513 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1514 	if (errno != EINVAL) e(0);
1515 
1516 	scn.sysctl_size--;
1517 	scn.sysctl_data = bad_ptr;
1518 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1519 	if (errno != EFAULT) e(0);
1520 
1521 	b = true;
1522 	scn.sysctl_data = &b;
1523 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1524 
1525 	mib[2] = TEST_DYNAMIC;
1526 	oldlen = sizeof(b);
1527 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1528 	if (oldlen != sizeof(b)) e(0);
1529 	if (b != true) e(0);
1530 
1531 	b = false;
1532 	oldlen = sizeof(b);
1533 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1534 	if (oldlen != sizeof(b)) e(0);
1535 	if (b != true) e(0);
1536 
1537 	b = false;
1538 	if (sysctl(mib, 3, NULL, NULL, &b, sizeof(b)) != 0) e(0);
1539 
1540 	oldlen = sizeof(b);
1541 	b = true;
1542 	if (sysctl(mib, 3, &b, &oldlen, NULL, 0) != 0) e(0);
1543 	if (oldlen != sizeof(b)) e(0);
1544 	if (b != false) e(0);
1545 
1546 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1547 
1548 	/* Test quads next. */
1549 	tmpscn.sysctl_flags =
1550 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_QUAD;
1551 	tmpscn.sysctl_size = sizeof(q);
1552 
1553 	mib[2] = CTL_CREATE;
1554 	memcpy(&scn, &tmpscn, sizeof(scn));
1555 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1556 
1557 	mib[2] = TEST_DYNAMIC;
1558 	oldlen = sizeof(q);
1559 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1560 	if (oldlen != sizeof(q)) e(0);
1561 	if (q != 0) e(0);
1562 
1563 	q = ~0ULL;
1564 	if (sysctl(mib, 3, NULL, NULL, &q, sizeof(q)) != 0) e(0);
1565 
1566 	oldlen = sizeof(q);
1567 	q = 0;
1568 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1569 	if (oldlen != sizeof(q)) e(0);
1570 	if (q != ~0ULL) e(0);
1571 
1572 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1573 
1574 	mib[2] = CTL_CREATE;
1575 	memcpy(&scn, &tmpscn, sizeof(scn));
1576 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1577 	scn.sysctl_qdata = 1ULL << 48;
1578 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1579 
1580 	mib[2] = TEST_DYNAMIC;
1581 	oldlen = sizeof(q);
1582 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1583 	if (oldlen != sizeof(q)) e(0);
1584 	if (q != (1ULL << 48)) e(0);
1585 
1586 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1587 
1588 	mib[2] = CTL_CREATE;
1589 	memcpy(&scn, &tmpscn, sizeof(scn));
1590 	scn.sysctl_data = &q;
1591 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1592 	if (errno != EINVAL) e(0);
1593 
1594 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1595 	scn.sysctl_size <<= 1;
1596 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1597 	if (errno != EINVAL) e(0);
1598 
1599 	scn.sysctl_size >>= 1;
1600 	scn.sysctl_data = bad_ptr;
1601 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1602 	if (errno != EFAULT) e(0);
1603 
1604 	q = 123ULL << 31;
1605 	scn.sysctl_data = &q;
1606 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1607 
1608 	mib[2] = TEST_DYNAMIC;
1609 	oldlen = sizeof(q);
1610 	if (sysctl(mib, 3, &q, &oldlen, NULL, 0) != 0) e(0);
1611 	if (oldlen != sizeof(q)) e(0);
1612 	if (q != (123ULL << 31)) e(0);
1613 
1614 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1615 
1616 	/* Test strings. */
1617 	tmpscn.sysctl_flags =
1618 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_STRING;
1619 	tmpscn.sysctl_size = 7;
1620 
1621 	mib[2] = CTL_CREATE;
1622 	memcpy(&scn, &tmpscn, sizeof(scn));
1623 	scn.sysctl_data = buf;
1624 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1625 	if (errno != EINVAL) e(0);
1626 
1627 	scn.sysctl_data = NULL;
1628 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1629 
1630 	mib[2] = TEST_DYNAMIC;
1631 	memset(buf, 0x7f, sizeof(buf));
1632 	oldlen = sizeof(buf);
1633 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1634 	if (oldlen != 1) e(0);
1635 	if (buf[0] != '\0') e(0);
1636 	if (buf[1] != 0x7f) e(0);
1637 
1638 	if (sysctl(mib, 3, NULL, NULL, "woobie!", 8) != -1) e(0);
1639 	if (errno != EINVAL) e(0);
1640 	if (sysctl(mib, 3, NULL, NULL, "woobie!", 7) != -1) e(0);
1641 	if (errno != EINVAL) e(0);
1642 	if (sysctl(mib, 3, NULL, NULL, "woobie", 7) != 0) e(0);
1643 
1644 	memset(buf, 0x7f, sizeof(buf));
1645 	oldlen = sizeof(buf);
1646 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1647 	if (oldlen != 7) e(0);
1648 	if (strcmp(buf, "woobie")) e(0);
1649 	if (buf[7] != 0x7f) e(0);
1650 
1651 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1652 
1653 	mib[2] = CTL_CREATE;
1654 	memcpy(&scn, &tmpscn, sizeof(scn));
1655 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1656 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1657 	if (errno != EINVAL) e(0);
1658 
1659 	memcpy(&scn, &tmpscn, sizeof(scn));
1660 	scn.sysctl_size = 0;
1661 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1662 	if (errno != EINVAL) e(0);
1663 
1664 	scn.sysctl_data = buf;
1665 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1666 	if (errno != EINVAL) e(0);
1667 
1668 	memcpy(&scn, &tmpscn, sizeof(scn));
1669 	scn.sysctl_size = SSIZE_MAX + 1;
1670 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1671 	if (errno != EINVAL) e(0);
1672 
1673 	memcpy(&scn, &tmpscn, sizeof(scn));
1674 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1675 	scn.sysctl_data = bad_ptr;
1676 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1677 	if (errno != EFAULT) e(0);
1678 
1679 	memcpy(&scn, &tmpscn, sizeof(scn));
1680 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1681 	scn.sysctl_data = "abc123?";
1682 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1683 	if (errno != EINVAL) e(0);
1684 
1685 	scn.sysctl_data = "abc123";
1686 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1687 
1688 	mib[2] = TEST_DYNAMIC;
1689 	memset(buf, 0x7f, sizeof(buf));
1690 	oldlen = sizeof(buf);
1691 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1692 	if (oldlen != 7) e(0);
1693 	if (strcmp(buf, "abc123")) e(0);
1694 	if (buf[7] != 0x7f) e(0);
1695 
1696 	if (sysctl(mib, 3, NULL, NULL, "", 1) != 0) e(0);
1697 
1698 	memset(buf, 0x7f, sizeof(buf));
1699 	oldlen = sizeof(buf);
1700 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1701 	if (oldlen != 1) e(0);
1702 	if (buf[0] != '\0') e(0);
1703 	if (buf[1] != 0x7f) e(0);
1704 
1705 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1706 
1707 	mib[2] = CTL_CREATE;
1708 	scn.sysctl_data = "";
1709 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1710 
1711 	mib[2] = TEST_DYNAMIC;
1712 	memset(buf, 0x7f, sizeof(buf));
1713 	oldlen = sizeof(buf);
1714 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1715 	if (oldlen != 1) e(0);
1716 	if (buf[0] != '\0') e(0);
1717 	if (buf[7] != 0x7f) e(0);
1718 
1719 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1720 
1721 	/*
1722 	 * For strings, a zero node size means that the string length
1723 	 * determines the buffer size.
1724 	 */
1725 	mib[2] = CTL_CREATE;
1726 	scn.sysctl_size = 0;
1727 	scn.sysctl_data = NULL;
1728 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1729 	if (errno != EINVAL) e(0);
1730 
1731 	scn.sysctl_data = bad_ptr;
1732 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1733 	if (errno != EFAULT) e(0);
1734 
1735 	scn.sysctl_data = "This is a string initializer."; /* size 29+1 */
1736 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1737 
1738 	mib[2] = TEST_DYNAMIC;
1739 	memset(buf, 0x7f, sizeof(buf));
1740 	oldlen = sizeof(buf);
1741 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1742 	if (oldlen != strlen(scn.sysctl_data) + 1) e(0);
1743 	if (buf[oldlen - 1] != '\0') e(0);
1744 	if (buf[oldlen] != 0x7f) e(0);
1745 
1746 	if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
1747 	if (newscn.sysctl_size != strlen(scn.sysctl_data) + 1) e(0);
1748 
1749 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1750 
1751 	/* Test structs. */
1752 	tmpscn.sysctl_flags =
1753 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_STRUCT;
1754 	tmpscn.sysctl_size = 21;
1755 
1756 	mib[2] = CTL_CREATE;
1757 	memcpy(&scn, &tmpscn, sizeof(scn));
1758 	scn.sysctl_data = buf;
1759 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1760 	if (errno != EINVAL) e(0);
1761 
1762 	scn.sysctl_data = NULL;
1763 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1764 
1765 	mib[2] = TEST_DYNAMIC;
1766 	memset(buf, 0x7f, sizeof(buf));
1767 	oldlen = sizeof(buf);
1768 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1769 	if (oldlen != 21) e(0);
1770 	for (i = 0; i < 21; i++)
1771 		if (buf[i] != 0) e(i);
1772 	if (buf[i] != 0x7f) e(0);
1773 
1774 	memset(buf, 'x', 32);
1775 	if (sysctl(mib, 3, NULL, NULL, buf, 20) != -1) e(0);
1776 	if (errno != EINVAL) e(0);
1777 	if (sysctl(mib, 3, NULL, NULL, buf, 22) != -1) e(0);
1778 	if (errno != EINVAL) e(0);
1779 	if (sysctl(mib, 3, NULL, NULL, buf, 21) != 0) e(0);
1780 
1781 	memset(buf, 0x7f, sizeof(buf));
1782 	oldlen = sizeof(buf);
1783 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1784 	if (oldlen != 21) e(0);
1785 	for (i = 0; i < 21; i++)
1786 		if (buf[i] != 'x') e(i);
1787 	if (buf[i] != 0x7f) e(0);
1788 
1789 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1790 
1791 	mib[2] = CTL_CREATE;
1792 	memcpy(&scn, &tmpscn, sizeof(scn));
1793 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1794 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1795 	if (errno != EINVAL) e(0);
1796 
1797 	memcpy(&scn, &tmpscn, sizeof(scn));
1798 	scn.sysctl_size = 0;
1799 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1800 	if (errno != EINVAL) e(0);
1801 
1802 	scn.sysctl_data = buf;
1803 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1804 	if (errno != EINVAL) e(0);
1805 
1806 	memcpy(&scn, &tmpscn, sizeof(scn));
1807 	scn.sysctl_size = SSIZE_MAX + 1;
1808 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1809 	if (errno != EINVAL) e(0);
1810 
1811 	memcpy(&scn, &tmpscn, sizeof(scn));
1812 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1813 	scn.sysctl_data = bad_ptr;
1814 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1815 	if (errno != EFAULT) e(0);
1816 
1817 	memcpy(&scn, &tmpscn, sizeof(scn));
1818 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1819 	for (i = 0; i < sizeof(buf); i++)
1820 		buf[i] = i;
1821 	scn.sysctl_data = buf;
1822 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1823 
1824 	mib[2] = TEST_DYNAMIC;
1825 	memset(buf, 0x7f, sizeof(buf));
1826 	oldlen = sizeof(buf);
1827 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
1828 	if (oldlen != 21) e(0);
1829 	for (i = 0; i < 21; i++)
1830 		if (buf[i] != i) e(i);
1831 	if (buf[i] != 0x7f) e(0);
1832 
1833 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1834 
1835 	/* Finally, test node-type nodes. */
1836 	tmpscn.sysctl_flags =
1837 	    SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
1838 	tmpscn.sysctl_size = 0;
1839 
1840 	mib[2] = CTL_CREATE;
1841 	memcpy(&scn, &tmpscn, sizeof(scn));
1842 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1843 
1844 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1845 
1846 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1847 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1848 	if (errno != EINVAL) e(0);
1849 
1850 	memcpy(&scn, &tmpscn, sizeof(scn));
1851 	scn.sysctl_flags |= CTLFLAG_IMMEDIATE;
1852 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1853 	if (errno != EINVAL) e(0);
1854 
1855 	scn.sysctl_size = sizeof(scn);
1856 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1857 	if (errno != EINVAL) e(0);
1858 
1859 	scn.sysctl_flags &= ~CTLFLAG_IMMEDIATE;
1860 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1861 	if (errno != EINVAL) e(0);
1862 
1863 	scn.sysctl_flags |= CTLFLAG_OWNDATA;
1864 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1865 	if (errno != EINVAL) e(0);
1866 
1867 	memcpy(&scn, &tmpscn, sizeof(scn));
1868 	scn.sysctl_csize = 8;
1869 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1870 	if (errno != EINVAL) e(0);
1871 
1872 	memcpy(&scn, &tmpscn, sizeof(scn));
1873 	scn.sysctl_clen = 1;
1874 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1875 	if (errno != EINVAL) e(0);
1876 
1877 	memcpy(&scn, &tmpscn, sizeof(scn));
1878 	scn.sysctl_child = &scn;
1879 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1880 	if (errno != EINVAL) e(0);
1881 
1882 	memcpy(&scn, &tmpscn, sizeof(scn));
1883 	scn.sysctl_parent = &scn;
1884 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1885 	if (errno != EINVAL) e(0);
1886 
1887 	memcpy(&scn, &tmpscn, sizeof(scn));
1888 	scn.sysctl_func = (sysctlfn)test87c;
1889 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
1890 	if (errno != EINVAL) e(0);
1891 
1892 	memcpy(&scn, &tmpscn, sizeof(scn));
1893 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1894 
1895 	if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1896 	if (scn.sysctl_csize != 0) e(0);
1897 	if (scn.sysctl_clen != 0) e(0);
1898 
1899 	mib[2] = TEST_DYNAMIC;
1900 
1901 	for (i = 3; i < CTL_MAXNAME; i++) {
1902 		memcpy(&scn, &tmpscn, sizeof(scn));
1903 		if (i % 2)
1904 			scn.sysctl_num = i - 3;
1905 		else
1906 			scn.sysctl_num = CTL_CREATE;
1907 		/*
1908 		 * Test both names with different length (depthN vs depthNN)
1909 		 * and cross-directory name duplicates (depth7.depth7).
1910 		 */
1911 		snprintf(scn.sysctl_name, sizeof(scn.sysctl_name), "depth%u",
1912 		    7 + i / 2);
1913 		mib[i] = CTL_CREATE;
1914 
1915 		oldlen = sizeof(newscn);
1916 		if (sysctl(mib, i + 1, &newscn, &oldlen, &scn,
1917 		    sizeof(scn)) != 0) e(0);
1918 		mib[i] = newscn.sysctl_num;
1919 	}
1920 
1921 	id[0] = mib[i - 1];
1922 	mib[i - 1] = CTL_CREATE;
1923 	memset(&scn, 0, sizeof(scn));
1924 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READONLY |
1925 	    CTLFLAG_OWNDATA | CTLTYPE_STRING;
1926 	scn.sysctl_num = id[0] + 1;
1927 	scn.sysctl_data = "bar";
1928 	scn.sysctl_size = strlen(scn.sysctl_data) + 1;
1929 	strlcpy(scn.sysctl_name, "foo", sizeof(scn.sysctl_name));
1930 	if (sysctl(mib, i, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1931 	mib[i - 1] = id[0] + 1;
1932 
1933 	oldlen = sizeof(buf);
1934 	if (sysctl(mib, i, buf, &oldlen, NULL, 0) != 0) e(0);
1935 	if (oldlen != strlen(scn.sysctl_data) + 1) e(0);
1936 	if (strcmp(buf, scn.sysctl_data)) e(0);
1937 
1938 	if (query_node(mib, i - 2, mib[i - 2], &scn) != 0) e(0);
1939 	if (scn.sysctl_csize != 2) e(0);
1940 	if (scn.sysctl_clen != 2) e(0);
1941 
1942 	if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1943 	if (scn.sysctl_csize != 1) e(0);
1944 	if (scn.sysctl_clen != 1) e(0);
1945 
1946 	if (destroy_node(mib, i - 1, mib[i - 1]) != 0) e(0);
1947 	mib[i - 1]--;
1948 
1949 	for (i--; i > 2; i--)
1950 		if (destroy_node(mib, i, mib[i]) != 0) e(0);
1951 
1952 	if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
1953 	if (scn.sysctl_csize != 0) e(0);
1954 	if (scn.sysctl_clen != 0) e(0);
1955 
1956 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1957 
1958 	/*
1959 	 * Finally, ensure that unprivileged processes cannot create nodes,
1960 	 * even in the most friendly place possible.
1961 	 */
1962 	mib[2] = CTL_CREATE;
1963 	memcpy(&scn, &tmpscn, sizeof(scn));
1964 	scn.sysctl_flags |= CTLFLAG_ANYWRITE;
1965 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
1966 
1967 	(void)test_nonroot(sub87c);
1968 
1969 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
1970 
1971 	/*
1972 	 * Now that we are done, compare the parent's statistics with those
1973 	 * obtained earlier once more.  There must be no differences.
1974 	 */
1975 	if (query_node(mib, 1, MINIX_TEST, &scn) != 0) e(0);
1976 	if (scn.sysctl_clen != pscn.sysctl_clen) e(0);
1977 	if (scn.sysctl_csize != pscn.sysctl_csize) e(0);
1978 
1979 	/* Do some more path-related error code tests unrelated to the rest. */
1980 	memcpy(&scn, &tmpscn, sizeof(scn));
1981 	mib[1] = INT_MAX;
1982 	if (create_node(mib, 2, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1983 	if (errno != ENOENT) e(0);
1984 
1985 	mib[1] = MINIX_TEST;
1986 	mib[2] = TEST_INT;
1987 	if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1988 	if (errno != ENOTDIR) e(0);
1989 
1990 	mib[2] = TEST_BOOL;
1991 	if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1992 	if (errno != ENOTDIR) e(0);
1993 
1994 	mib[2] = CTL_CREATE;
1995 	if (create_node(mib, 3, &scn, TEST_DYNAMIC, "d", -1, NULL) != -1) e(0);
1996 	if (errno != EINVAL) e(0);
1997 
1998 	/* Finally, try to create a node in a read-only directory node. */
1999 	mib[2] = TEST_SECRET;
2000 	if (create_node(mib, 3, &scn, -1, "d", -1, NULL) != -1) e(0);
2001 	if (errno != EPERM) e(0);
2002 }
2003 
2004 /*
2005  * Test unprivileged node destruction.
2006  */
2007 static void
2008 sub87d(void)
2009 {
2010 	struct sysctlnode scn;
2011 	int mib[3];
2012 
2013 	mib[0] = CTL_MINIX;
2014 	mib[1] = MINIX_TEST;
2015 	mib[2] = CTL_DESTROY;
2016 
2017 	memset(&scn, 0, sizeof(scn));
2018 	scn.sysctl_flags = SYSCTL_VERSION;
2019 	scn.sysctl_num = TEST_ANYWRITE;
2020 
2021 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2022 	if (errno != EPERM) e(0);
2023 
2024 	mib[0] = CTL_DESTROY;
2025 	scn.sysctl_num = CTL_MINIX;
2026 	if (sysctl(mib, 1, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2027 	if (errno != EPERM) e(0);
2028 }
2029 
2030 /*
2031  * Test sysctl(2) node destruction.
2032  */
2033 static void
2034 test87d(void)
2035 {
2036 	struct sysctlnode scn, oldscn, newscn, tmpscn;
2037 	size_t oldlen;
2038 	char buf[16];
2039 	int i, r, mib[4], id[15];
2040 
2041 	subtest = 3;
2042 
2043 	mib[0] = CTL_MINIX;
2044 	mib[1] = MINIX_TEST;
2045 	(void)destroy_node(mib, 2, TEST_DYNAMIC);
2046 
2047 	/* Start with the path-related error code tests this time. */
2048 	mib[1] = INT_MAX;
2049 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2050 	if (errno != ENOENT) e(0);
2051 
2052 	mib[1] = MINIX_TEST;
2053 	mib[2] = TEST_INT;
2054 	if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2055 	if (errno != ENOTDIR) e(0);
2056 
2057 	mib[2] = TEST_BOOL;
2058 	if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2059 	if (errno != ENOTDIR) e(0);
2060 
2061 	mib[2] = CTL_DESTROY;
2062 	if (destroy_node(mib, 3, TEST_DYNAMIC) != -1) e(0);
2063 	if (errno != EINVAL) e(0);
2064 
2065 	/* Actual API tests. */
2066 	mib[1] = MINIX_TEST;
2067 	mib[2] = CTL_CREATE;
2068 	memset(&scn, 0, sizeof(scn));
2069 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2070 	    CTLFLAG_READONLY | CTLTYPE_INT;
2071 	scn.sysctl_size = sizeof(int);
2072 	scn.sysctl_num = TEST_DYNAMIC;
2073 	scn.sysctl_idata = 31415926;
2074 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2075 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2076 
2077 	memcpy(&tmpscn, &scn, sizeof(scn));
2078 
2079 	mib[2] = CTL_DESTROY;
2080 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
2081 	if (errno != EINVAL) e(0);
2082 
2083 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
2084 	if (errno != EFAULT) e(0);
2085 
2086 	memset(&scn, 0, sizeof(scn));
2087 	scn.sysctl_flags = SYSCTL_VERS_0;
2088 	scn.sysctl_num = TEST_DYNAMIC;
2089 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2090 	if (errno != EINVAL) e(0);
2091 
2092 	scn.sysctl_flags = SYSCTL_VERSION;
2093 	scn.sysctl_num = INT_MAX; /* anything not valid */
2094 	oldlen = sizeof(scn);
2095 	if (sysctl(mib, 3, NULL, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2096 	if (errno != ENOENT) e(0);
2097 	if (oldlen != 0) e(0);
2098 
2099 	scn.sysctl_num = TEST_PERM;
2100 	oldlen = sizeof(scn);
2101 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2102 	if (errno != EPERM) e(0);
2103 	if (oldlen != 0) e(0);
2104 
2105 	scn.sysctl_num = TEST_SECRET;
2106 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2107 	if (errno != ENOTEMPTY) e(0);
2108 
2109 	scn.sysctl_num = -1;
2110 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2111 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2112 	if (errno != ENOENT) e(0);
2113 
2114 	scn.sysctl_num = TEST_DYNAMIC;
2115 	strlcpy(scn.sysctl_name, "dynami", sizeof(scn.sysctl_name));
2116 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2117 	if (errno != EINVAL) e(0);
2118 
2119 	strlcpy(scn.sysctl_name, "dynamic2", sizeof(scn.sysctl_name));
2120 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2121 	if (errno != EINVAL) e(0);
2122 
2123 	memset(scn.sysctl_name, 'd', sizeof(scn.sysctl_name));
2124 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2125 	if (errno != EINVAL) e(0);
2126 
2127 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2128 	oldlen = sizeof(oldscn);
2129 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
2130 	if (oldlen != sizeof(oldscn)) e(0);
2131 	if (oldscn.sysctl_ver == 0) e(0);
2132 	oldscn.sysctl_ver = 0;
2133 	if (memcmp(&oldscn, &tmpscn, sizeof(oldscn))) e(0);
2134 
2135 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2136 	if (errno != ENOENT) e(0);
2137 
2138 	/*
2139 	 * We already tested destruction of one static node, by destroying
2140 	 * TEST_DYNAMIC on the first run.  We now do a second deletion of a
2141 	 * static node, TEST_DESTROY2, to test proper adjustment of parent
2142 	 * stats.  We do a third static node deletion (on TEST_DESTROY1) later,
2143 	 * to see that static nodes with dynamic descriptions can be freed.
2144 	 */
2145 	if (query_node(mib, 1, MINIX_TEST, &oldscn) != 0) e(0);
2146 
2147 	memset(&scn, 0, sizeof(scn));
2148 	scn.sysctl_flags = SYSCTL_VERSION;
2149 	scn.sysctl_num = TEST_DESTROY2;
2150 	r = sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn));
2151 	if (r != 0 && r != -1) e(0);
2152 	if (r == -1 && errno != ENOENT) e(0);
2153 
2154 	if (query_node(mib, 1, MINIX_TEST, &newscn) != 0) e(0);
2155 
2156 	if (newscn.sysctl_csize != oldscn.sysctl_csize) e(0);
2157 	if (newscn.sysctl_clen != oldscn.sysctl_clen - !r) e(0);
2158 
2159 	/* Try to destroy a (static) node in a read-only directory node. */
2160 	mib[2] = TEST_SECRET;
2161 	if (destroy_node(mib, 3, SECRET_VALUE) != -1) e(0);
2162 	if (errno != EPERM) e(0);
2163 
2164 	/*
2165 	 * Errors during data copy-out of the destroyed node should not undo
2166 	 * its destruction.
2167 	 */
2168 	mib[2] = CTL_CREATE;
2169 	memcpy(&scn, &tmpscn, sizeof(scn));
2170 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2171 
2172 	mib[2] = TEST_DYNAMIC;
2173 	i = 0;
2174 	oldlen = sizeof(i);
2175 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != 0) e(0);
2176 	if (oldlen != sizeof(i)) e(0);
2177 	if (i != 31415926) e(0);
2178 
2179 	mib[2] = CTL_DESTROY;
2180 	oldlen = sizeof(scn);
2181 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2182 	if (errno != EFAULT) e(0);
2183 
2184 	mib[2] = TEST_DYNAMIC;
2185 	i = 0;
2186 	oldlen = sizeof(i);
2187 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != -1) e(0);
2188 	if (errno != ENOENT) e(0);
2189 	if (oldlen != 0) e(0);
2190 	if (i != 0) e(0);
2191 
2192 	mib[2] = CTL_CREATE;
2193 	memcpy(&scn, &tmpscn, sizeof(scn));
2194 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2195 
2196 	mib[2] = CTL_DESTROY;
2197 	oldlen = sizeof(scn) - 1;
2198 	if (sysctl(mib, 3, &scn, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2199 	if (errno != ENOMEM) e(0);
2200 
2201 	mib[2] = TEST_DYNAMIC;
2202 	oldlen = sizeof(i);
2203 	if (sysctl(mib, 3, &i, &oldlen, NULL, 0) != -1) e(0);
2204 	if (errno != ENOENT) e(0);
2205 
2206 	/*
2207 	 * Now create and destroy a whole bunch of nodes in a subtree, mostly
2208 	 * test linked list manipulation, but also to ensure that a nonempty
2209 	 * tree node cannot be destroyed.
2210 	 */
2211 	memset(&scn, 0, sizeof(scn));
2212 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
2213 	if (create_node(mib, 2, &scn, TEST_DYNAMIC, "dynamic", -1, NULL) == -1)
2214 		e(0);
2215 
2216 	for (i = 0; i < 15; i++) {
2217 		snprintf(buf, sizeof(buf), "node%d", i);
2218 		if ((id[i] = create_node(mib, 3, &scn, -1, buf, -1,
2219 		    NULL)) == -1) e(i);
2220 
2221 		if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(i);
2222 		if (errno != ENOTEMPTY) e(i);
2223 	}
2224 
2225 	for (i = 0; i < 15; i += 2)
2226 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2227 
2228 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2229 	if (errno != ENOTEMPTY) e(0);
2230 
2231 	for (i = 0; i < 15; i += 2) {
2232 		snprintf(buf, sizeof(buf), "node%d", i);
2233 		if ((id[i] = create_node(mib, 3, &scn, -1, buf, -1,
2234 		    NULL)) == -1) e(i);
2235 	}
2236 
2237 	for (i = 0; i < 3; i++)
2238 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2239 
2240 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2241 	if (errno != ENOTEMPTY) e(0);
2242 
2243 	for (i = 12; i < 15; i++)
2244 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2245 
2246 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2247 	if (errno != ENOTEMPTY) e(0);
2248 
2249 	for (i = 6; i < 9; i++)
2250 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2251 
2252 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2253 	if (errno != ENOTEMPTY) e(0);
2254 
2255 	for (i = 3; i < 6; i++)
2256 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2257 
2258 	if (destroy_node(mib, 2, TEST_DYNAMIC) != -1) e(0);
2259 	if (errno != ENOTEMPTY) e(0);
2260 
2261 	for (i = 9; i < 12; i++)
2262 		if (destroy_node(mib, 3, id[i]) != 0) e(i);
2263 
2264 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2265 
2266 	/* Finally, ensure that unprivileged users cannot destroy nodes. */
2267 	(void)test_nonroot(sub87d);
2268 }
2269 
2270 /*
2271  * Get or a set the description for a particular node.  Compare the results
2272  * with the given description.  Return 0 on success, or -1 on failure with
2273  * errno set.
2274  */
2275 static int
2276 describe_node(const int * path, unsigned int pathlen, int id,
2277 	const char * desc, int set)
2278 {
2279 	char buf[256], *p;
2280 	struct sysctlnode scn;
2281 	struct sysctldesc *scd;
2282 	size_t oldlen;
2283 	int mib[CTL_MAXNAME];
2284 
2285 	if (pathlen >= CTL_MAXNAME) e(0);
2286 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
2287 	mib[pathlen] = CTL_DESCRIBE;
2288 
2289 	memset(&scn, 0, sizeof(scn));
2290 	memset(buf, 0, sizeof(buf));
2291 	oldlen = sizeof(buf);
2292 	scn.sysctl_flags = SYSCTL_VERSION;
2293 	scn.sysctl_num = id;
2294 	if (set)
2295 		scn.sysctl_desc = desc;
2296 	if (sysctl(mib, pathlen + 1, buf, &oldlen, &scn, sizeof(scn)) != 0)
2297 		return -1;
2298 
2299 	scd = (struct sysctldesc *)buf;
2300 	if (scd->descr_num != id) e(0);
2301 	if (scd->descr_ver == 0) e(0);
2302 	if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2303 	if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2304 	if (strcmp(scd->descr_str, desc)) e(0);
2305 	if (oldlen != (size_t)((char *)NEXT_DESCR(scd) - buf)) e(0);
2306 	for (p = scd->descr_str + scd->descr_len; p != &buf[oldlen]; p++)
2307 		if (*p != '\0') e(0);
2308 	return 0;
2309 }
2310 
2311 /*
2312  * Test getting descriptions from an unprivileged process.
2313  */
2314 static void
2315 sub87e(void)
2316 {
2317 	static char buf[2048];
2318 	char seen[32], *p;
2319 	struct sysctldesc *scd, *endscd;
2320 	size_t oldlen;
2321 	int mib[4];
2322 
2323 	mib[0] = CTL_MINIX;
2324 	mib[1] = MINIX_TEST;
2325 	mib[2] = CTL_DESCRIBE;
2326 
2327 	memset(buf, 0, sizeof(buf));
2328 	oldlen = sizeof(buf);
2329 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2330 	if (oldlen == 0) e(0);
2331 
2332 	scd = (struct sysctldesc *)buf;
2333 	endscd = (struct sysctldesc *)&buf[oldlen];
2334 	memset(seen, 0, sizeof(seen));
2335 
2336 	while (scd < endscd) {
2337 		if (scd->descr_num >= __arraycount(seen)) e(0);
2338 		if (seen[scd->descr_num]++) e(0);
2339 
2340 		if (scd->descr_ver == 0) e(0);
2341 		if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2342 		if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2343 
2344 		p = scd->descr_str + scd->descr_len;
2345 		while (p != (char *)NEXT_DESCR(scd))
2346 			if (*p++ != '\0') e(0);
2347 
2348 		scd = NEXT_DESCR(scd);
2349 	}
2350 	if (scd != endscd) e(0);
2351 
2352 	if (!seen[TEST_INT]) e(0);
2353 	if (!seen[TEST_BOOL]) e(0);
2354 	if (!seen[TEST_QUAD]) e(0);
2355 	if (!seen[TEST_STRING]) e(0);
2356 	if (!seen[TEST_STRUCT]) e(0);
2357 	if (seen[TEST_PRIVATE]) e(0);
2358 	if (!seen[TEST_ANYWRITE]) e(0);
2359 	if (seen[TEST_SECRET]) e(0);
2360 	if (!seen[TEST_PERM]) e(0);
2361 
2362 	if (describe_node(mib, 2, TEST_INT, "Value test field", 0) != 0) e(0);
2363 	if (describe_node(mib, 2, TEST_PRIVATE, "", 0) != -1) e(0);
2364 	if (errno != EPERM) e(0);
2365 	if (describe_node(mib, 2, TEST_SECRET, "", 0) != -1) e(0);
2366 	if (errno != EPERM) e(0);
2367 	if (describe_node(mib, 2, TEST_PERM, "", 0) != 0) e(0);
2368 
2369 	mib[2] = TEST_SECRET;
2370 	mib[3] = CTL_DESCRIBE;
2371 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != -1) e(0);
2372 	if (errno != EPERM) e(0);
2373 
2374 	if (describe_node(mib, 3, SECRET_VALUE, "", 0) != -1) e(0);
2375 	if (errno != EPERM) e(0);
2376 }
2377 
2378 /*
2379  * Test sysctl(2) node descriptions, part 1: getting descriptions.
2380  */
2381 static void
2382 test87e(void)
2383 {
2384 	static char buf[2048];
2385 	char seen[32], *p;
2386 	struct sysctldesc *scd, *endscd;
2387 	struct sysctlnode scn;
2388 	size_t oldlen, len, sublen;
2389 	int mib[4];
2390 
2391 	subtest = 4;
2392 
2393 	mib[0] = CTL_MINIX;
2394 	mib[1] = MINIX_TEST;
2395 	mib[2] = CTL_DESCRIBE;
2396 	memset(&scn, 0, sizeof(scn));
2397 
2398 	/* Start with tests for getting a description listing. */
2399 	if (sysctl(mib, 3, NULL, NULL, NULL, 0) != 0) e(0);
2400 
2401 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
2402 	if (oldlen == 0) e(0);
2403 	len = oldlen;
2404 
2405 	memset(buf, 0, sizeof(buf));
2406 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2407 	if (oldlen != len) e(0);
2408 
2409 	scd = (struct sysctldesc *)buf;
2410 	endscd = (struct sysctldesc *)&buf[len];
2411 	memset(seen, 0, sizeof(seen));
2412 
2413 	sublen = (size_t)((char *)NEXT_DESCR(scd) - buf);
2414 
2415 	while (scd < endscd) {
2416 		if (scd->descr_num >= __arraycount(seen)) e(0);
2417 		if (seen[scd->descr_num]++) e(0);
2418 
2419 		if (scd->descr_ver == 0) e(0);
2420 		if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2421 		if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2422 
2423 		/*
2424 		 * This is not supposed to be complete.  We test different
2425 		 * string lengths, private fields, and empty descriptions.
2426 		 */
2427 		switch (scd->descr_num) {
2428 		case TEST_INT:
2429 			if (strcmp(scd->descr_str, "Value test field")) e(0);
2430 			break;
2431 		case TEST_BOOL:
2432 			if (strcmp(scd->descr_str, "Boolean test field")) e(0);
2433 			break;
2434 		case TEST_QUAD:
2435 			if (strcmp(scd->descr_str, "Quad test field")) e(0);
2436 			break;
2437 		case TEST_STRING:
2438 			if (strcmp(scd->descr_str, "String test field")) e(0);
2439 			break;
2440 		case TEST_PRIVATE:
2441 			if (strcmp(scd->descr_str, "Private test field")) e(0);
2442 			break;
2443 		case TEST_SECRET:
2444 			if (strcmp(scd->descr_str, "Private subtree")) e(0);
2445 			break;
2446 		case TEST_PERM:
2447 			if (strcmp(scd->descr_str, "")) e(0);
2448 			break;
2449 		}
2450 
2451 		/*
2452 		 * If there are padding bytes, they must be zero, whether it is
2453 		 * because we set them or the MIB service copied out zeroes.
2454 		 */
2455 		p = scd->descr_str + scd->descr_len;
2456 		while (p != (char *)NEXT_DESCR(scd))
2457 			if (*p++ != '\0') e(0);
2458 
2459 		scd = NEXT_DESCR(scd);
2460 	}
2461 	if (scd != endscd) e(0);
2462 
2463 	if (!seen[TEST_INT]) e(0);
2464 	if (!seen[TEST_BOOL]) e(0);
2465 	if (!seen[TEST_QUAD]) e(0);
2466 	if (!seen[TEST_STRING]) e(0);
2467 	if (!seen[TEST_STRUCT]) e(0);
2468 	if (!seen[TEST_PRIVATE]) e(0);
2469 	if (!seen[TEST_ANYWRITE]) e(0);
2470 	if (!seen[TEST_SECRET]) e(0);
2471 	if (!seen[TEST_PERM]) e(0);
2472 
2473 	memset(buf, 0, sizeof(buf));
2474 	oldlen = sublen;
2475 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != -1) e(0);
2476 	if (errno != ENOMEM) e(0);
2477 
2478 	scd = (struct sysctldesc *)buf;
2479 	if (scd->descr_num != TEST_INT) e(0);
2480 	if (scd->descr_ver == 0) e(0);
2481 	if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2482 	if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2483 	if (strcmp(scd->descr_str, "Value test field")) e(0);
2484 
2485 	/* Next up, tests for getting a particular node's description. */
2486 	memset(buf, 0, sizeof(buf));
2487 	oldlen = sizeof(buf);
2488 	if (sysctl(mib, 3, bad_ptr, &oldlen, NULL, 0) != -1) e(0);
2489 	if (errno != EFAULT) e(0);
2490 
2491 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn) - 1) != -1) e(0);
2492 	if (errno != EINVAL) e(0);
2493 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn) + 1) != -1) e(0);
2494 	if (errno != EINVAL) e(0);
2495 	if (sysctl(mib, 3, NULL, NULL, bad_ptr, sizeof(scn)) != -1) e(0);
2496 	if (errno != EFAULT) e(0);
2497 
2498 	memset(&scn, 0, sizeof(scn));
2499 	scn.sysctl_flags = SYSCTL_VERS_0;
2500 	scn.sysctl_num = INT_MAX;
2501 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2502 	if (errno != EINVAL) e(0);
2503 
2504 	scn.sysctl_flags = SYSCTL_VERSION;
2505 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2506 	if (errno != ENOENT) e(0);
2507 
2508 	scn.sysctl_num = TEST_BOOL;
2509 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2510 
2511 	oldlen = sizeof(buf);
2512 	scn.sysctl_num = TEST_INT;
2513 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2514 	if (errno != EFAULT) e(0);
2515 
2516 	oldlen = sublen - 1;
2517 	scn.sysctl_num = TEST_INT;
2518 	if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2519 	if (errno != ENOMEM) e(0);
2520 	if (oldlen != sublen) e(0);
2521 
2522 	if (describe_node(mib, 2, TEST_INT, "Value test field", 0) != 0) e(0);
2523 	if (describe_node(mib, 2, TEST_QUAD, "Quad test field", 0) != 0) e(0);
2524 	if (describe_node(mib, 2, TEST_PRIVATE, "Private test field",
2525 	    0) != 0) e(0);
2526 	if (describe_node(mib, 2, TEST_SECRET, "Private subtree",
2527 	    0) != 0) e(0);
2528 	if (describe_node(mib, 2, TEST_PERM, "", 0) != 0) e(0);
2529 
2530 	/*
2531 	 * Make sure that unprivileged users cannot access privileged nodes'
2532 	 * descriptions.  It doesn't sound too bad to me if they could, but
2533 	 * these are apparently the rules..
2534 	 */
2535 	(void)test_nonroot(sub87e);
2536 
2537 	/* Do some more path-related error code tests unrelated to the rest. */
2538 	mib[1] = INT_MAX;
2539 	if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != -1) e(0);
2540 	if (errno != ENOENT) e(0);
2541 
2542 	mib[1] = MINIX_TEST;
2543 	mib[2] = TEST_INT;
2544 	if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2545 	if (errno != ENOTDIR) e(0);
2546 
2547 	mib[2] = TEST_BOOL;
2548 	if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2549 	if (errno != ENOTDIR) e(0);
2550 
2551 	mib[2] = CTL_DESCRIBE;
2552 	if (describe_node(mib, 3, TEST_DYNAMIC, "", 0) != -1) e(0);
2553 	if (errno != EINVAL) e(0);
2554 }
2555 
2556 /*
2557  * Test setting descriptions from an unprivileged process.
2558  */
2559 static void
2560 sub87f(void)
2561 {
2562 	struct sysctlnode scn;
2563 	int mib[3];
2564 
2565 	mib[0] = CTL_MINIX;
2566 	mib[1] = MINIX_TEST;
2567 	mib[2] = CTL_DESCRIBE;
2568 
2569 	memset(&scn, 0, sizeof(scn));
2570 	scn.sysctl_flags = SYSCTL_VERSION;
2571 	scn.sysctl_num = TEST_DYNAMIC;
2572 	scn.sysctl_desc = "Description.";
2573 
2574 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2575 	if (errno != EPERM) e(0);
2576 }
2577 
2578 /*
2579  * Test sysctl(2) node descriptions, part 2: setting descriptions.
2580  */
2581 static void
2582 test87f(void)
2583 {
2584 	static char buf[2048];
2585 	char seen, *p;
2586 	struct sysctlnode scn, tmpscn, scnset[3];
2587 	struct sysctldesc *scd, *endscd, *scdset[2];
2588 	size_t oldlen, len;
2589 	int i, r, mib[4], id[2];
2590 
2591 	subtest = 5;
2592 
2593 	/*
2594 	 * All tests that experiment with dynamic nodes must start with trying
2595 	 * to destroy the TEST_DYNAMIC node first, as tests may be run
2596 	 * individually, and this node exists as a static node after booting.
2597 	 */
2598 	mib[0] = CTL_MINIX;
2599 	mib[1] = MINIX_TEST;
2600 	(void)destroy_node(mib, 2, TEST_DYNAMIC);
2601 
2602 	/*
2603 	 * First try setting and retrieving the description of a dynamic node
2604 	 * in a directory full of static nodes.
2605 	 */
2606 	mib[2] = CTL_CREATE;
2607 	memset(&scn, 0, sizeof(scn));
2608 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2609 	    CTLFLAG_READONLY | CTLTYPE_INT;
2610 	scn.sysctl_size = sizeof(int);
2611 	scn.sysctl_num = TEST_DYNAMIC;
2612 	scn.sysctl_idata = 27182818;
2613 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2614 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2615 
2616 	memcpy(&tmpscn, &scn, sizeof(tmpscn));
2617 
2618 	/* We should get an empty description for the node in a listing. */
2619 	mib[2] = CTL_DESCRIBE;
2620 	memset(buf, 0, sizeof(buf));
2621 	oldlen = sizeof(buf);
2622 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2623 
2624 	scd = (struct sysctldesc *)buf;
2625 	endscd = (struct sysctldesc *)&buf[oldlen];
2626 	seen = 0;
2627 
2628 	while (scd < endscd) {
2629 		if (scd->descr_num == TEST_DYNAMIC) {
2630 			if (seen++) e(0);
2631 
2632 			if (scd->descr_len != 1) e(0);
2633 			if (scd->descr_str[0] != '\0') e(0);
2634 		}
2635 
2636 		if (scd->descr_ver == 0) e(0);
2637 		if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2638 		if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2639 
2640 		p = scd->descr_str + scd->descr_len;
2641 		while (p != (char *)NEXT_DESCR(scd))
2642 			if (*p++ != '\0') e(0);
2643 
2644 		scd = NEXT_DESCR(scd);
2645 	}
2646 	if (scd != endscd) e(0);
2647 
2648 	if (!seen) e(0);
2649 
2650 	/* We should get an empty description quering the node directly. */
2651 	if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != 0) e(0);
2652 
2653 	/* Attempt to set a description with a bad description pointer. */
2654 	if (describe_node(mib, 2, TEST_DYNAMIC, bad_ptr, 1) != -1) e(0);
2655 	if (errno != EFAULT) e(0);
2656 
2657 	/* Attempt to set a description that is longer than allowed. */
2658 	memset(buf, 'A', sizeof(buf) - 1);
2659 	buf[sizeof(buf) - 1] = '\0';
2660 	if (describe_node(mib, 2, TEST_DYNAMIC, buf, 1) != -1) e(0);
2661 	if (errno != EINVAL) e(0);
2662 
2663 	/* Now actually set a description. */
2664 	if (describe_node(mib, 2, TEST_DYNAMIC, "Dynamic node", 1) != 0) e(0);
2665 	len = strlen("Dynamic node") + 1;
2666 
2667 	/* We should get the new description for the node in a listing. */
2668 	memset(buf, 0, sizeof(buf));
2669 	oldlen = sizeof(buf);
2670 	if (sysctl(mib, 3, buf, &oldlen, NULL, 0) != 0) e(0);
2671 
2672 	scd = (struct sysctldesc *)buf;
2673 	endscd = (struct sysctldesc *)&buf[oldlen];
2674 	seen = 0;
2675 
2676 	while (scd < endscd) {
2677 		if (scd->descr_num == TEST_DYNAMIC) {
2678 			if (seen++) e(0);
2679 
2680 			if (scd->descr_len != len) e(0);
2681 			if (strcmp(scd->descr_str, "Dynamic node")) e(0);
2682 		}
2683 
2684 		if (scd->descr_ver == 0) e(0);
2685 		if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2686 		if (scd->descr_len != strlen(scd->descr_str) + 1) e(0);
2687 
2688 		p = scd->descr_str + scd->descr_len;
2689 		while (p != (char *)NEXT_DESCR(scd))
2690 			if (*p++ != '\0') e(0);
2691 
2692 		scd = NEXT_DESCR(scd);
2693 	}
2694 	if (scd != endscd) e(0);
2695 
2696 	if (!seen) e(0);
2697 
2698 	/* We should get the new description quering the node directly. */
2699 	if (describe_node(mib, 2, TEST_DYNAMIC, "Dynamic node", 0) != 0) e(0);
2700 
2701 	mib[2] = CTL_DESCRIBE;
2702 	memset(&scn, 0, sizeof(scn));
2703 	scn.sysctl_flags = SYSCTL_VERS_0;
2704 	scn.sysctl_num = TEST_INT;
2705 	scn.sysctl_desc = "Test description";
2706 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2707 	if (errno != EINVAL) e(0);
2708 
2709 	/* It is not possible to replace an existing static description. */
2710 	scn.sysctl_flags = SYSCTL_VERSION;
2711 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2712 	if (errno != EPERM) e(0);
2713 
2714 	/* Nonexistent nodes cannot be given a description. */
2715 	scn.sysctl_num = INT_MAX;
2716 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2717 	if (errno != ENOENT) e(0);
2718 
2719 	/* It is not possible to replace an existing dynamic description. */
2720 	scn.sysctl_num = TEST_DYNAMIC;
2721 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2722 	if (errno != EPERM) e(0);
2723 
2724 	/* It is not possible to set a description on a permanent node. */
2725 	scn.sysctl_num = TEST_PERM;
2726 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
2727 	if (errno != EPERM) e(0);
2728 
2729 	/* Verify that TEST_DYNAMIC now has CTLFLAG_OWNDESC set. */
2730 	if (query_node(mib, 2, TEST_DYNAMIC, &scn) != 0) e(0);
2731 	if (!(scn.sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2732 
2733 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2734 
2735 	/*
2736 	 * Set a description on a static node, ensure that CTLFLAG_OWNDESC is
2737 	 * set, and then destroy the static node.  This should still free the
2738 	 * memory allocated for the description.  We cannot test whether the
2739 	 * memory is really freed, but at least we can trigger this case at
2740 	 * all, and leave the rest up to memory checkers or whatever.  Since we
2741 	 * destroy the static node, we can not do this more than once, and thus
2742 	 * we skip this test if the static node does not exist.
2743 	 */
2744 	r = describe_node(mib, 2, TEST_DESTROY1, "Destroy me", 1);
2745 
2746 	if (r == -1 && errno != ENOENT) e(0);
2747 	else if (r == 0) {
2748 		if (query_node(mib, 2, TEST_DESTROY1, &scn) != 0) e(0);
2749 		if (!(scn.sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2750 
2751 		if (describe_node(mib, 2, TEST_DESTROY1, "Destroy me", 0) != 0)
2752 			e(0);
2753 
2754 		if (destroy_node(mib, 2, TEST_DESTROY1) != 0) e(0);
2755 	}
2756 
2757 	/*
2758 	 * Test queries and description listings in subtrees.
2759 	 */
2760 	mib[2] = CTL_CREATE;
2761 	memset(&scn, 0, sizeof(scn));
2762 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
2763 	scn.sysctl_num = TEST_DYNAMIC;
2764 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
2765 	scn.sysctl_desc = "This will not be set.";
2766 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
2767 
2768 	/* Setting sysctl_desc should have no effect during creation. */
2769 	if (describe_node(mib, 2, TEST_DYNAMIC, "", 0) != 0) e(0);
2770 
2771 	mib[2] = TEST_DYNAMIC;
2772 	id[0] = create_node(mib, 3, &tmpscn, CTL_CREATE, "NodeA", -1, NULL);
2773 	if (id[0] < 0) e(0);
2774 	id[1] = create_node(mib, 3, &tmpscn, CTL_CREATE, "NodeB", -1, NULL);
2775 	if (id[1] < 0) e(0);
2776 	if (id[0] == id[1]) e(0);
2777 
2778 	mib[3] = CTL_QUERY;
2779 	oldlen = sizeof(scnset);
2780 	if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2781 	if (oldlen != sizeof(scnset[0]) * 2) e(0);
2782 	i = (scnset[0].sysctl_num != id[0]);
2783 	if (scnset[i].sysctl_num != id[0]) e(0);
2784 	if (scnset[1 - i].sysctl_num != id[1]) e(0);
2785 	if (scnset[i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2786 	if (scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2787 
2788 	mib[3] = CTL_DESCRIBE;
2789 	memset(buf, 0, sizeof(buf));
2790 	oldlen = sizeof(buf);
2791 	if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2792 	if (oldlen == 0) e(0);
2793 
2794 	scdset[0] = (struct sysctldesc *)buf;
2795 	scdset[1] = NEXT_DESCR(scdset[0]);
2796 	if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2797 	i = (scdset[0]->descr_num != id[0]);
2798 	if (scdset[i]->descr_num != id[0]) e(0);
2799 	if (scdset[i]->descr_ver == 0) e(0);
2800 	if (scdset[i]->descr_len != 1) e(0);
2801 	if (scdset[i]->descr_str[0] != '\0') e(0);
2802 	if (scdset[1 - i]->descr_num != id[1]) e(0);
2803 	if (scdset[1 - i]->descr_ver == 0) e(0);
2804 	if (scdset[1 - i]->descr_len != 1) e(0);
2805 	if (scdset[1 - i]->descr_str[0] != '\0') e(0);
2806 
2807 	if (describe_node(mib, 3, id[0], "Description A", 1) != 0) e(0);
2808 
2809 	mib[3] = CTL_QUERY;
2810 	oldlen = sizeof(scnset);
2811 	if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2812 	if (oldlen != sizeof(scnset[0]) * 2) e(0);
2813 	i = (scnset[0].sysctl_num != id[0]);
2814 	if (scnset[i].sysctl_num != id[0]) e(0);
2815 	if (scnset[1 - i].sysctl_num != id[1]) e(0);
2816 	if (!(scnset[i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2817 	if (scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC) e(0);
2818 
2819 	mib[3] = CTL_DESCRIBE;
2820 	memset(buf, 0, sizeof(buf));
2821 	oldlen = sizeof(buf);
2822 	if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2823 	if (oldlen == 0) e(0);
2824 
2825 	scdset[0] = (struct sysctldesc *)buf;
2826 	scdset[1] = NEXT_DESCR(scdset[0]);
2827 	if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2828 	i = (scdset[0]->descr_num != id[0]);
2829 	if (scdset[i]->descr_num != id[0]) e(0);
2830 	if (scdset[i]->descr_ver == 0) e(0);
2831 	if (strcmp(scdset[i]->descr_str, "Description A")) e(0);
2832 	if (scdset[i]->descr_len != strlen(scdset[i]->descr_str) + 1) e(0);
2833 	if (scdset[1 - i]->descr_num != id[1]) e(0);
2834 	if (scdset[1 - i]->descr_ver == 0) e(0);
2835 	if (scdset[1 - i]->descr_len != 1) e(0);
2836 	if (scdset[1 - i]->descr_str[0] != '\0') e(0);
2837 
2838 	if (describe_node(mib, 3, id[1], "Description B", 1) != 0) e(0);
2839 
2840 	mib[3] = CTL_QUERY;
2841 	oldlen = sizeof(scnset);
2842 	if (sysctl(mib, 4, scnset, &oldlen, NULL, 0) != 0) e(0);
2843 	if (oldlen != sizeof(scnset[0]) * 2) e(0);
2844 	i = (scnset[0].sysctl_num != id[0]);
2845 	if (scnset[i].sysctl_num != id[0]) e(0);
2846 	if (scnset[1 - i].sysctl_num != id[1]) e(0);
2847 	if (!(scnset[i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2848 	if (!(scnset[1 - i].sysctl_flags & CTLFLAG_OWNDESC)) e(0);
2849 
2850 	mib[3] = CTL_DESCRIBE;
2851 	memset(buf, 0, sizeof(buf));
2852 	oldlen = sizeof(buf);
2853 	if (sysctl(mib, 4, buf, &oldlen, NULL, 0) != 0) e(0);
2854 	if (oldlen == 0) e(0);
2855 
2856 	scdset[0] = (struct sysctldesc *)buf;
2857 	scdset[1] = NEXT_DESCR(scdset[0]);
2858 	if ((char *)NEXT_DESCR(scdset[1]) != &buf[oldlen]) e(0);
2859 	i = (scdset[0]->descr_num != id[0]);
2860 	if (scdset[i]->descr_num != id[0]) e(0);
2861 	if (scdset[i]->descr_ver == 0) e(0);
2862 	if (strcmp(scdset[i]->descr_str, "Description A")) e(0);
2863 	if (scdset[i]->descr_len != strlen(scdset[i]->descr_str) + 1) e(0);
2864 	if (scdset[1 - i]->descr_num != id[1]) e(0);
2865 	if (scdset[1 - i]->descr_ver == 0) e(0);
2866 	if (strcmp(scdset[1 - i]->descr_str, "Description B")) e(0);
2867 	if (scdset[1 - i]->descr_len != strlen(scdset[1 - i]->descr_str) + 1)
2868 		e(0);
2869 
2870 	if (destroy_node(mib, 3, id[0]) != 0) e(0);
2871 	if (destroy_node(mib, 3, id[1]) != 0) e(0);
2872 
2873 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2874 
2875 	/*
2876 	 * Test that the resulting description is copied out after setting it,
2877 	 * and that copy failures do not undo the description getting set.
2878 	 */
2879 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2880 	    NULL) == -1) e(0);
2881 
2882 	mib[2] = CTL_DESCRIBE;
2883 	memset(&scn, 0, sizeof(scn));
2884 	scn.sysctl_flags = SYSCTL_VERSION;
2885 	scn.sysctl_num = TEST_DYNAMIC;
2886 	scn.sysctl_desc = "Testing..";
2887 	memset(buf, 0, sizeof(buf));
2888 	oldlen = sizeof(buf);
2889 	if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != 0) e(0);
2890 	if (oldlen == 0) e(0);
2891 	len = oldlen;
2892 
2893 	scd = (struct sysctldesc *)buf;
2894 	if (scd->descr_str[scd->descr_len - 1] != '\0') e(0);
2895 	if (scd->descr_len != strlen(scn.sysctl_desc) + 1) e(0);
2896 	if (strcmp(scd->descr_str, scn.sysctl_desc)) e(0);
2897 	if (oldlen != (size_t)((char *)NEXT_DESCR(scd) - buf)) e(0);
2898 	p = scd->descr_str + scd->descr_len;
2899 	while (p != (char *)NEXT_DESCR(scd))
2900 		if (*p++ != '\0') e(0);
2901 
2902 	if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2903 
2904 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2905 
2906 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2907 	    NULL) == -1) e(0);
2908 
2909 	memset(buf, 0, sizeof(buf));
2910 	oldlen = len - 1;
2911 	if (sysctl(mib, 3, buf, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2912 	if (errno != ENOMEM) e(0);
2913 	if (oldlen != len) e(0);
2914 
2915 	if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2916 
2917 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2918 
2919 	if (create_node(mib, 2, &tmpscn, TEST_DYNAMIC, "dynamic", -1,
2920 	    NULL) == -1) e(0);
2921 
2922 	memset(buf, 0, sizeof(buf));
2923 	oldlen = len;
2924 	if (sysctl(mib, 3, bad_ptr, &oldlen, &scn, sizeof(scn)) != -1) e(0);
2925 	if (errno != EFAULT) e(0);
2926 
2927 	if (describe_node(mib, 2, TEST_DYNAMIC, "Testing..", 0) != 0) e(0);
2928 
2929 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2930 
2931 	/* Finally, ensure that unprivileged users cannot set descriptions. */
2932 	memcpy(&scn, &tmpscn, sizeof(scn));
2933 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
2934 	    CTLFLAG_READWRITE | CTLFLAG_ANYWRITE | CTLTYPE_INT;
2935 	if (create_node(mib, 2, &scn, TEST_DYNAMIC, "dynamic", -1,
2936 	    NULL) == -1) e(0);
2937 
2938 	(void)test_nonroot(sub87f);
2939 
2940 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
2941 }
2942 
2943 /*
2944  * Set or test buffer contents.  When setting, the buffer is filled with a
2945  * sequence of bytes that is a) free of null characters and b) likely to cause
2946  * detection of wrongly copied subsequences.  When testing, for any size up to
2947  * the size used to set the buffer contents, 0 is returned if the buffer
2948  * contents match expectations, or -1 if they do not.
2949  */
2950 static int
2951 test_buf(unsigned char * buf, unsigned char c, size_t size, int set)
2952 {
2953 	int step;
2954 
2955 	for (step = 1; size > 0; size--) {
2956 		if (set)
2957 			*buf++ = c;
2958 		else if (*buf++ != c)
2959 			return -1;
2960 
2961 		c += step;
2962 		if (c == 0) {
2963 			if (++step == 256)
2964 				step = 1;
2965 			c += step;
2966 		}
2967 	}
2968 
2969 	return 0;
2970 }
2971 
2972 /*
2973  * Test large data sizes from an unprivileged process.
2974  */
2975 static void
2976 sub87g(void)
2977 {
2978 	char *ptr;
2979 	size_t size, oldlen;
2980 	int id, mib[3];
2981 
2982 	size = getpagesize() * 3;
2983 
2984 	if ((ptr = mmap(NULL, size, PROT_READ, MAP_ANON | MAP_PRIVATE, -1,
2985 	    0)) == MAP_FAILED) e(0);
2986 	memset(ptr, 0x2f, size);
2987 
2988 	mib[0] = CTL_MINIX;
2989 	mib[1] = MINIX_TEST;
2990 	mib[2] = TEST_DYNAMIC;
2991 	oldlen = size - 2;
2992 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
2993 	if (oldlen != size - 2) e(0);
2994 	if (test_buf(ptr, 'D', size - 2, 0) != 0) e(0);
2995 
2996 	/*
2997 	 * Given the large data size, we currently expect this attempt to
2998 	 * write to the structure to be blocked by the MIB service.
2999 	 */
3000 	if (sysctl(mib, 3, NULL, NULL, ptr, oldlen) != -1) e(0);
3001 	if (errno != EPERM) e(0);
3002 
3003 	/* Get the ID of the second dynamic node. */
3004 	mib[2] = TEST_ANYWRITE;
3005 	oldlen = sizeof(id);
3006 	if (sysctl(mib, 3, &id, &oldlen, NULL, 0) != 0) e(0);
3007 	if (oldlen != sizeof(id)) e(0);
3008 	if (id < 0) e(0);
3009 
3010 	/*
3011 	 * Test data size limits for strings as well, although here we can also
3012 	 * ensure that we hit the right check by testing with a shorter string.
3013 	 */
3014 	mib[2] = id;
3015 	oldlen = size;
3016 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3017 	if (oldlen != size) e(0);
3018 	if (test_buf(ptr, 'f', size - 1, 0) != 0) e(0);
3019 	if (ptr[size - 1] != '\0') e(0);
3020 
3021 	test_buf(ptr, 'h', size - 1, 1);
3022 	if (sysctl(mib, 3, NULL, NULL, ptr, size) != -1) e(0);
3023 	if (errno != EPERM) e(0);
3024 
3025 	if (sysctl(mib, 3, NULL, NULL, ptr, getpagesize() - 1) != 0) e(0);
3026 
3027 	if (munmap(ptr, size) != 0) e(0);
3028 }
3029 
3030 /*
3031  * Test large data sizes and mid-data page faults.
3032  */
3033 static void
3034 test87g(void)
3035 {
3036 	struct sysctlnode scn, newscn;
3037 	char *ptr;
3038 	size_t pgsz, size, oldlen;
3039 	int id, mib[3];
3040 
3041 	subtest = 6;
3042 
3043 	/*
3044 	 * No need to go overboard with sizes here; it will just cause the MIB
3045 	 * service's memory usage to grow - permanently.  Three pages followed
3046 	 * by an unmapped page is plenty for this test.
3047 	 */
3048 	pgsz = getpagesize();
3049 	size = pgsz * 3;
3050 
3051 	if ((ptr = mmap(NULL, size + pgsz, PROT_READ, MAP_ANON | MAP_PRIVATE,
3052 	    -1, 0)) == MAP_FAILED) e(0);
3053 	if (munmap(ptr + size, pgsz) != 0) e(0);
3054 
3055 	(void)destroy_node(mib, 2, TEST_DYNAMIC);
3056 
3057 	/* Test string creation initializers with an accurate length. */
3058 	mib[0] = CTL_MINIX;
3059 	mib[1] = MINIX_TEST;
3060 	mib[2] = CTL_CREATE;
3061 	memset(&scn, 0, sizeof(scn));
3062 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3063 	    CTLFLAG_READWRITE | CTLTYPE_STRING;
3064 	scn.sysctl_num = TEST_DYNAMIC;
3065 	scn.sysctl_data = ptr;
3066 	scn.sysctl_size = size;
3067 	strlcpy(scn.sysctl_name, "dynamic", sizeof(scn.sysctl_name));
3068 	test_buf(ptr, 'a', size, 1);
3069 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3070 	if (errno != EINVAL) e(0); /* no null terminator */
3071 
3072 	scn.sysctl_size++;
3073 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3074 	if (errno != EFAULT) e(0);
3075 
3076 	scn.sysctl_size--;
3077 	ptr[size - 1] = '\0';
3078 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3079 
3080 	mib[2] = TEST_DYNAMIC;
3081 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
3082 	if (oldlen != size) e(0);
3083 
3084 	memset(ptr, 0, size);
3085 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3086 	if (oldlen != size) e(0);
3087 	if (ptr[size - 1] != '\0') e(0);
3088 	if (test_buf(ptr, 'a', size - 1, 0) != 0) e(0);
3089 
3090 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3091 
3092 	/* Test string creation initializers with no length. */
3093 	mib[2] = CTL_CREATE;
3094 	scn.sysctl_size = 0;
3095 	test_buf(ptr, 'b', size, 1);
3096 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3097 	if (errno != EFAULT) e(0);
3098 
3099 	test_buf(ptr, 'b', size - 1, 1);
3100 	ptr[size - 1] = '\0';
3101 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3102 
3103 	if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
3104 	if (newscn.sysctl_size != size) e(0);
3105 
3106 	mib[2] = TEST_DYNAMIC;
3107 	if (sysctl(mib, 3, NULL, &oldlen, NULL, 0) != 0) e(0);
3108 	if (oldlen != size) e(0);
3109 
3110 	memset(ptr, 0x7e, size);
3111 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3112 	if (oldlen != size) e(0);
3113 	if (ptr[size - 1] != '\0') e(0);
3114 	if (test_buf(ptr, 'b', size - 1, 0) != 0) e(0);
3115 
3116 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3117 
3118 	/*
3119 	 * Test string creation initializers with a length exceeding the string
3120 	 * length.  If the string is properly null terminated, this should not
3121 	 * result in a fault.
3122 	 */
3123 	mib[2] = CTL_CREATE;
3124 	scn.sysctl_size = size;
3125 	scn.sysctl_data = &ptr[size - pgsz - 5];
3126 	test_buf(&ptr[size - pgsz - 5], 'c', pgsz + 5, 1);
3127 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3128 	if (errno != EFAULT) e(0);
3129 
3130 	ptr[size - 1] = '\0';
3131 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3132 
3133 	if (query_node(mib, 2, TEST_DYNAMIC, &newscn) != 0) e(0);
3134 	if (newscn.sysctl_size != size) e(0);
3135 
3136 	mib[2] = TEST_DYNAMIC;
3137 	oldlen = size - pgsz - 6;
3138 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3139 	if (oldlen != pgsz + 5) e(0);
3140 	/* We rely on only the actual string getting copied out here. */
3141 	if (memcmp(ptr, &ptr[size - pgsz - 5], pgsz + 5)) e(0);
3142 
3143 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3144 
3145 	/* Test structure creation initializers. */
3146 	mib[2] = CTL_CREATE;
3147 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3148 	    CTLFLAG_ANYWRITE | CTLFLAG_READWRITE | CTLTYPE_STRUCT;
3149 	scn.sysctl_size = size - 2;
3150 	scn.sysctl_data = &ptr[3];
3151 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3152 	if (errno != EFAULT) e(0);
3153 
3154 	scn.sysctl_data = &ptr[2];
3155 	test_buf(&ptr[2], 'd', size - 2, 1);
3156 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3157 
3158 	mib[2] = TEST_DYNAMIC;
3159 	memset(ptr, 0x3b, size);
3160 	oldlen = size - 2;
3161 	if (sysctl(mib, 3, &ptr[3], &oldlen, NULL, 0) != -1) e(0);
3162 	if (errno != EFAULT) e(0);
3163 	oldlen = size - 2;
3164 	if (sysctl(mib, 3, &ptr[2], &oldlen, NULL, 0) != 0) e(0);
3165 	if (oldlen != size - 2) e(0);
3166 	if (test_buf(&ptr[2], 'd', size - 2, 0) != 0) e(0);
3167 
3168 	/*
3169 	 * Test setting new values.  We already have a structure node, so let's
3170 	 * start there.
3171 	 */
3172 	test_buf(&ptr[2], 'D', size - 2, 1);
3173 	if (sysctl(mib, 3, NULL, NULL, &ptr[3], size - 2) != -1) e(0);
3174 	if (errno != EFAULT) e(0);
3175 
3176 	/* Did the mid-data fault cause a partial update?  It better not. */
3177 	memset(ptr, 0x4c, size);
3178 	oldlen = size - 2;
3179 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3180 	if (oldlen != size - 2) e(0);
3181 	if (test_buf(ptr, 'd', size - 2, 0) != 0) e(0);
3182 
3183 	test_buf(&ptr[2], 'D', size - 2, 1);
3184 	if (sysctl(mib, 3, NULL, NULL, &ptr[2], size - 2) != 0) e(0);
3185 
3186 	memset(ptr, 0x5d, size);
3187 	oldlen = size - 2;
3188 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3189 	if (oldlen != size - 2) e(0);
3190 	if (test_buf(ptr, 'D', size - 2, 0) != 0) e(0);
3191 
3192 	/*
3193 	 * We are going to reuse TEST_DYNAMIC for the non-root test later, so
3194 	 * create a new node for string tests.
3195 	 */
3196 	mib[2] = CTL_CREATE;
3197 	memset(&scn, 0, sizeof(scn));
3198 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_OWNDATA |
3199 	    CTLFLAG_ANYWRITE | CTLFLAG_READWRITE | CTLTYPE_STRING;
3200 	scn.sysctl_num = CTL_CREATE;
3201 	scn.sysctl_size = size;
3202 	scn.sysctl_data = ptr;
3203 	test_buf(ptr, 'e', size - 1, 1);
3204 	ptr[size - 1] = '\0';
3205 	strlcpy(scn.sysctl_name, "dynamic2", sizeof(scn.sysctl_name));
3206 	oldlen = sizeof(newscn);
3207 	if (sysctl(mib, 3, &newscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3208 	if (oldlen != sizeof(newscn)) e(0);
3209 	id = newscn.sysctl_num;
3210 	if (id < 0) e(0);
3211 
3212 	/*
3213 	 * Test setting a short but faulty string, ensuring that no partial
3214 	 * update on the field contents takes place.
3215 	 */
3216 	mib[2] = id;
3217 	memcpy(&ptr[size - 3], "XYZ", 3);
3218 	if (sysctl(mib, 3, NULL, NULL, &ptr[size - 3], 4) != -1) e(0);
3219 	if (errno != EFAULT) e(0);
3220 
3221 	oldlen = size;
3222 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3223 	if (oldlen != size) e(0);
3224 	if (test_buf(ptr, 'e', size - 1, 0) != 0) e(0);
3225 	if (ptr[size - 1] != '\0') e(0);
3226 
3227 	memcpy(&ptr[size - 3], "XYZ", 3);
3228 	if (sysctl(mib, 3, NULL, NULL, &ptr[size - 3], 3) != 0) e(0);
3229 
3230 	oldlen = size;
3231 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3232 	if (oldlen != 4) e(0);
3233 	if (strcmp(ptr, "XYZ")) e(0);
3234 
3235 	test_buf(&ptr[1], 'f', size - 1, 1);
3236 	if (sysctl(mib, 3, NULL, NULL, &ptr[1], size - 1) != 0) e(0);
3237 
3238 	test_buf(&ptr[1], 'G', size - 1, 1);
3239 	if (sysctl(mib, 3, NULL, NULL, &ptr[1], size) != -1) e(0);
3240 	if (errno != EFAULT) e(0);
3241 
3242 	oldlen = size;
3243 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3244 	if (oldlen != size) e(0);
3245 	if (test_buf(ptr, 'f', size - 1, 0) != 0) e(0);
3246 	if (ptr[size - 1] != '\0') e(0);
3247 
3248 	/*
3249 	 * Test descriptions as well.  First, the MIB service does not allow
3250 	 * for overly long descriptions, although the limit is not exposed.
3251 	 * Three memory pages worth of text is way too long though.
3252 	 */
3253 	memset(ptr, 'A', size);
3254 	if (describe_node(mib, 2, id, ptr, 1) != -1) e(0);
3255 	if (errno != EINVAL) e(0); /* not EFAULT, should never get that far */
3256 
3257 	ptr[size - 1] = '\0';
3258 	if (describe_node(mib, 2, id, ptr, 1) != -1) e(0);
3259 	if (errno != EINVAL) e(0);
3260 
3261 	if (describe_node(mib, 2, id, "", 0) != 0) e(0);
3262 
3263 	/*
3264 	 * Second, the description routine must deal with faults occurring
3265 	 * while it is trying to find the string end.
3266 	 */
3267 	ptr[size - 2] = 'B';
3268 	ptr[size - 1] = 'C';
3269 	if (describe_node(mib, 2, id, &ptr[size - 3], 1) != -1) e(0);
3270 	if (errno != EFAULT) e(0);
3271 
3272 	if (describe_node(mib, 2, id, "", 0) != 0) e(0);
3273 
3274 	ptr[size - 1] = '\0';
3275 	if (describe_node(mib, 2, id, &ptr[size - 3], 1) != 0) e(0);
3276 
3277 	if (describe_node(mib, 2, id, "AB", 0) != 0) e(0);
3278 
3279 	/* Pass the second dynamic node ID to the unprivileged child. */
3280 	mib[2] = TEST_ANYWRITE;
3281 	if (sysctl(mib, 3, NULL, NULL, &id, sizeof(id)) != 0) e(0);
3282 
3283 	(void)test_nonroot(sub87g);
3284 
3285 	mib[2] = id;
3286 	oldlen = size;
3287 	if (sysctl(mib, 3, ptr, &oldlen, NULL, 0) != 0) e(0);
3288 	if (oldlen != pgsz) e(0);
3289 	if (test_buf(ptr, 'h', pgsz - 1, 1) != 0) e(0);
3290 	if (ptr[pgsz - 1] != '\0') e(0);
3291 
3292 	if (destroy_node(mib, 2, TEST_DYNAMIC) != 0) e(0);
3293 	if (destroy_node(mib, 2, id) != 0) e(0);
3294 
3295 	munmap(ptr, size);
3296 }
3297 
3298 /*
3299  * Verify whether the given node on the given path has the given node version.
3300  * Return 0 if the version matches, or -1 if it does not or a failure occurred.
3301  */
3302 static int
3303 check_version(const int * path, unsigned int pathlen, int id, uint32_t ver)
3304 {
3305 	struct sysctlnode scn;
3306 	struct sysctldesc scd;
3307 	size_t oldlen;
3308 	int r, mib[CTL_MAXNAME];
3309 
3310 	assert(pathlen < CTL_MAXNAME);
3311 	memcpy(mib, path, sizeof(mib[0]) * pathlen);
3312 	mib[pathlen] = CTL_DESCRIBE;
3313 
3314 	/*
3315 	 * For some reason, when retrieving a particular description (as
3316 	 * opposed to setting one), the node version number is not checked.
3317 	 * In order to test this, we deliberately pass in a node version number
3318 	 * that, if checked, would eventually cause failures.
3319 	 */
3320 	memset(&scn, 0, sizeof(scn));
3321 	scn.sysctl_flags = SYSCTL_VERSION;
3322 	scn.sysctl_num = id;
3323 	scn.sysctl_ver = 1;
3324 	oldlen = sizeof(scd);
3325 	r = sysctl(mib, pathlen + 1, &scd, &oldlen, &scn, sizeof(scn));
3326 	if (r == -1 && errno != ENOMEM) e(0);
3327 
3328 	return (scd.descr_ver == ver) ? 0 : -1;
3329 }
3330 
3331 /*
3332  * Test sysctl(2) node versioning.
3333  */
3334 static void
3335 test87h(void)
3336 {
3337 	struct sysctlnode scn, oldscn;
3338 	size_t oldlen;
3339 	uint32_t ver[4];
3340 	int mib[4], id[4];
3341 
3342 	/*
3343 	 * The other tests have already tested sufficiently that a zero version
3344 	 * is always accepted in calls.  Here, we test that node versions
3345 	 * actually change when creating and destroying nodes, and that the
3346 	 * right version test is implemented for all of the four node meta-
3347 	 * operations (query, create, destroy, describe).  Why did we not do
3348 	 * this earlier, you ask?  Well, versioning was implemented later on.
3349 	 */
3350 	subtest = 7;
3351 
3352 	/*
3353 	 * Test versioning with node creation.
3354 	 */
3355 	mib[0] = CTL_MINIX;
3356 	mib[1] = MINIX_TEST;
3357 	mib[2] = CTL_CREATE;
3358 	memset(&scn, 0, sizeof(scn));
3359 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | CTLTYPE_NODE;
3360 	scn.sysctl_num = CTL_CREATE;
3361 	strlcpy(scn.sysctl_name, "NodeA", sizeof(scn.sysctl_name));
3362 	oldlen = sizeof(oldscn);
3363 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3364 	if (oldlen != sizeof(oldscn)) e(0);
3365 	id[0] = oldscn.sysctl_num;
3366 	ver[0] = oldscn.sysctl_ver;
3367 	if (ver[0] == 0) e(0);
3368 
3369 	if (check_version(mib, 0, CTL_MINIX, ver[0]) != 0) e(0);
3370 	if (check_version(mib, 1, MINIX_TEST, ver[0]) != 0) e(0);
3371 	if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3372 
3373 	strlcpy(scn.sysctl_name, "NodeB", sizeof(scn.sysctl_name));
3374 	oldlen = sizeof(oldscn);
3375 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3376 	if (oldlen != sizeof(oldscn)) e(0);
3377 	id[1] = oldscn.sysctl_num;
3378 	ver[1] = oldscn.sysctl_ver;
3379 	if (ver[1] == 0) e(0);
3380 	if (ver[1] != NEXT_VER(ver[0])) e(0);
3381 
3382 	if (check_version(mib, 0, CTL_MINIX, ver[1]) != 0) e(0);
3383 	if (check_version(mib, 1, MINIX_TEST, ver[1]) != 0) e(0);
3384 	if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3385 	if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3386 
3387 	/* A version that is too high should be rejected. */
3388 	mib[2] = id[0];
3389 	mib[3] = CTL_CREATE;
3390 	scn.sysctl_flags = SYSCTL_VERSION | CTLFLAG_IMMEDIATE |
3391 	    CTLFLAG_READWRITE | CTLTYPE_INT;
3392 	scn.sysctl_size = sizeof(int);
3393 	scn.sysctl_ver = NEXT_VER(ver[1]);
3394 	strlcpy(scn.sysctl_name, "ValueA", sizeof(scn.sysctl_name));
3395 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3396 	if (errno != EINVAL) e(0);
3397 
3398 	/* The version of the parent node should be accepted. */
3399 	scn.sysctl_ver = ver[0]; /* different from the root node version */
3400 	oldlen = sizeof(oldscn);
3401 	if (sysctl(mib, 4, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3402 	if (oldlen != sizeof(oldscn)) e(0);
3403 	id[2] = oldscn.sysctl_num;
3404 	ver[2] = oldscn.sysctl_ver;
3405 	if (ver[2] == 0) e(0);
3406 	if (ver[2] != NEXT_VER(ver[1])) e(0);
3407 
3408 	if (check_version(mib, 0, CTL_MINIX, ver[2]) != 0) e(0);
3409 	if (check_version(mib, 1, MINIX_TEST, ver[2]) != 0) e(0);
3410 	if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3411 	if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3412 	if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3413 
3414 	/* A version that is too low (old) should be rejected. */
3415 	mib[2] = id[1];
3416 
3417 	scn.sysctl_ver = ver[0];
3418 	strlcpy(scn.sysctl_name, "ValueB", sizeof(scn.sysctl_name));
3419 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3420 	if (errno != EINVAL) e(0);
3421 
3422 	/* The version of the root node should be accepted. */
3423 	scn.sysctl_ver = ver[2]; /* different from the parent node version */
3424 	oldlen = sizeof(oldscn);
3425 	if (sysctl(mib, 4, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3426 	if (oldlen != sizeof(oldscn)) e(0);
3427 	id[3] = oldscn.sysctl_num;
3428 	ver[3] = oldscn.sysctl_ver;
3429 	if (ver[3] == 0) e(0);
3430 	if (ver[3] != NEXT_VER(ver[2])) e(0);
3431 
3432 	if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3433 	if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3434 	if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3435 	if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3436 	if (check_version(mib, 3, id[3], ver[3]) != 0) e(0);
3437 	mib[2] = id[0];
3438 	if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3439 
3440 	/*
3441 	 * Test versioning with node queries.
3442 	 */
3443 	mib[3] = CTL_QUERY;
3444 	memset(&scn, 0, sizeof(scn));
3445 	scn.sysctl_flags = SYSCTL_VERSION;
3446 	scn.sysctl_ver = ver[0]; /* previous parent version */
3447 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3448 	if (errno != EINVAL) e(0);
3449 
3450 	scn.sysctl_ver = ver[2]; /* parent version */
3451 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3452 
3453 	scn.sysctl_ver = ver[2]; /* root version */
3454 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3455 
3456 	scn.sysctl_ver = NEXT_VER(ver[3]); /* nonexistent version */
3457 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3458 	if (errno != EINVAL) e(0);
3459 
3460 	/*
3461 	 * Test versioning with node description.
3462 	 */
3463 	mib[2] = CTL_DESCRIBE;
3464 	scn.sysctl_num = id[0];
3465 	scn.sysctl_ver = ver[3]; /* root and parent, but not target version */
3466 	scn.sysctl_desc = "Parent A";
3467 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3468 	if (errno != EINVAL) e(0);
3469 
3470 	scn.sysctl_ver = ver[1]; /* another bad version */
3471 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3472 	if (errno != EINVAL) e(0);
3473 
3474 	scn.sysctl_ver = ver[2]; /* target version */
3475 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3476 
3477 	/* Neither querying nor description should have changed versions. */
3478 	if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3479 	if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3480 	if (check_version(mib, 2, id[0], ver[2]) != 0) e(0);
3481 	if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3482 	mib[2] = id[1];
3483 	if (check_version(mib, 3, id[3], ver[3]) != 0) e(0);
3484 	mib[2] = id[0];
3485 	if (check_version(mib, 3, id[2], ver[2]) != 0) e(0);
3486 
3487 	/*
3488 	 * Test versioning with node destruction.
3489 	 */
3490 	mib[3] = CTL_DESTROY;
3491 	memset(&scn, 0, sizeof(scn));
3492 	scn.sysctl_flags = SYSCTL_VERSION;
3493 	scn.sysctl_num = id[2];
3494 	scn.sysctl_ver = ver[3]; /* root but not target version */
3495 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3496 	if (errno != EINVAL) e(0);
3497 
3498 	scn.sysctl_ver = ver[2]; /* target (and parent) version */
3499 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3500 
3501 	/* Fortunately, versions are predictable. */
3502 	ver[0] = NEXT_VER(ver[3]);
3503 
3504 	if (check_version(mib, 0, CTL_MINIX, ver[0]) != 0) e(0);
3505 	if (check_version(mib, 1, MINIX_TEST, ver[0]) != 0) e(0);
3506 	if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3507 	if (check_version(mib, 2, id[1], ver[3]) != 0) e(0);
3508 
3509 	mib[2] = id[1];
3510 	scn.sysctl_num = id[3];
3511 	scn.sysctl_ver = ver[0]; /* root but not target version */
3512 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3513 	if (errno != EINVAL) e(0);
3514 
3515 	scn.sysctl_ver = ver[3]; /* target (and parent) version */
3516 	if (sysctl(mib, 4, NULL, NULL, &scn, sizeof(scn)) != 0) e(0);
3517 
3518 	ver[1] = NEXT_VER(ver[0]);
3519 
3520 	if (check_version(mib, 0, CTL_MINIX, ver[1]) != 0) e(0);
3521 	if (check_version(mib, 1, MINIX_TEST, ver[1]) != 0) e(0);
3522 	if (check_version(mib, 2, id[0], ver[0]) != 0) e(0);
3523 	if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3524 
3525 	mib[2] = CTL_DESTROY;
3526 	scn.sysctl_num = id[0];
3527 	scn.sysctl_ver = ver[1]; /* root and parent, but not target version */
3528 	if (sysctl(mib, 3, NULL, NULL, &scn, sizeof(scn)) != -1) e(0);
3529 	if (errno != EINVAL) e(0);
3530 
3531 	scn.sysctl_ver = ver[0]; /* target version */
3532 	oldlen = sizeof(oldscn);
3533 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3534 	if (oldlen != sizeof(oldscn)) e(0);
3535 	if (oldscn.sysctl_num != id[0]) e(0);
3536 	if (oldscn.sysctl_ver != ver[0]) e(0);
3537 
3538 	ver[2] = NEXT_VER(ver[1]);
3539 
3540 	if (check_version(mib, 0, CTL_MINIX, ver[2]) != 0) e(0);
3541 	if (check_version(mib, 1, MINIX_TEST, ver[2]) != 0) e(0);
3542 	if (check_version(mib, 2, id[1], ver[1]) != 0) e(0);
3543 
3544 	/* For the last destruction, just see if we get the old version. */
3545 	scn.sysctl_num = id[1];
3546 	scn.sysctl_ver = 0;
3547 	oldlen = sizeof(oldscn);
3548 	if (sysctl(mib, 3, &oldscn, &oldlen, &scn, sizeof(scn)) != 0) e(0);
3549 	if (oldlen != sizeof(oldscn)) e(0);
3550 	if (oldscn.sysctl_num != id[1]) e(0);
3551 	if (oldscn.sysctl_ver != ver[1]) e(0);
3552 
3553 	ver[3] = NEXT_VER(ver[2]);
3554 
3555 	if (check_version(mib, 0, CTL_MINIX, ver[3]) != 0) e(0);
3556 	if (check_version(mib, 1, MINIX_TEST, ver[3]) != 0) e(0);
3557 }
3558 
3559 /*
3560  * Perform pre-test initialization.
3561  */
3562 static void
3563 test87_init(void)
3564 {
3565 	size_t oldlen;
3566 	int mib[3];
3567 
3568 	subtest = 99;
3569 
3570 	if ((bad_ptr = mmap(NULL, getpagesize(), PROT_READ,
3571 	    MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED) e(0);
3572 	if (munmap(bad_ptr, getpagesize()) != 0) e(0);
3573 
3574 	mib[0] = CTL_MINIX;
3575 	mib[1] = MINIX_MIB;
3576 	mib[2] = MIB_NODES;
3577 	oldlen = sizeof(nodes);
3578 	if (sysctl(mib, 3, &nodes, &oldlen, NULL, 0) != 0) e(0);
3579 	if (oldlen != sizeof(nodes)) e(0);
3580 
3581 	mib[2] = MIB_OBJECTS;
3582 	oldlen = sizeof(objects);
3583 	if (sysctl(mib, 3, &objects, &oldlen, NULL, 0) != 0) e(0);
3584 	if (oldlen != sizeof(objects)) e(0);
3585 }
3586 
3587 /*
3588  * Perform post-test checks.
3589  */
3590 static void
3591 test87_check(void)
3592 {
3593 	unsigned int newnodes, newobjects;
3594 	size_t oldlen;
3595 	int mib[3];
3596 
3597 	subtest = 99;
3598 
3599 	mib[0] = CTL_MINIX;
3600 	mib[1] = MINIX_MIB;
3601 	mib[2] = MIB_NODES;
3602 	oldlen = sizeof(newnodes);
3603 	if (sysctl(mib, 3, &newnodes, &oldlen, NULL, 0) != 0) e(0);
3604 	if (oldlen != sizeof(newnodes)) e(0);
3605 
3606 	/*
3607 	 * Upon the first run, the total number of nodes must actually go down,
3608 	 * as we destroy number of static nodes.  Upon subsequent runs, the
3609 	 * number of nodes should remain stable.  Thus, we can safely test that
3610 	 * the number of nodes has not gone up as a result of the test.
3611 	 */
3612 	if (newnodes > nodes) e(0);
3613 
3614 	mib[2] = MIB_OBJECTS;
3615 	oldlen = sizeof(newobjects);
3616 	if (sysctl(mib, 3, &newobjects, &oldlen, NULL, 0) != 0) e(0);
3617 	if (oldlen != sizeof(newobjects)) e(0);
3618 
3619 	/*
3620 	 * The number of dynamically allocated objects should remain the same
3621 	 * across the test.
3622 	 */
3623 	if (newobjects != objects) e(0);
3624 }
3625 
3626 /*
3627  * Test program for sysctl(2).
3628  */
3629 int
3630 main(int argc, char ** argv)
3631 {
3632 	int i, m;
3633 
3634 	start(87);
3635 
3636 	if (argc == 2)
3637 		m = atoi(argv[1]);
3638 	else
3639 		m = 0xFF;
3640 
3641 	test87_init();
3642 
3643 	for (i = 0; i < ITERATIONS; i++) {
3644 		if (m & 0x001) test87a();
3645 		if (m & 0x002) test87b();
3646 		if (m & 0x004) test87c();
3647 		if (m & 0x008) test87d();
3648 		if (m & 0x010) test87e();
3649 		if (m & 0x020) test87f();
3650 		if (m & 0x040) test87g();
3651 		if (m & 0x080) test87h();
3652 	}
3653 
3654 	test87_check();
3655 
3656 	quit();
3657 }
3658