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