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