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