1/* 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 * 28 * 29 * Copyright (c) 1982, 1986, 1989, 1993 30 * The Regents of the University of California. All rights reserved. 31 * 32 * This code is derived from software contributed to Berkeley by 33 * Mike Karels at Berkeley Software Design, Inc. 34 * 35 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD 36 * project, to make these variables more userfriendly. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the University of 49 * California, Berkeley and its contributors. 50 * 4. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 67 */ 68 69 70#include <sys/param.h> 71#include <sys/buf.h> 72#include <sys/kernel.h> 73#include <sys/sysctl.h> 74#include <sys/malloc.h> 75#include <sys/proc_internal.h> 76#include <sys/systm.h> 77 78#include <security/audit/audit.h> 79 80/* 81struct sysctl_oid_list sysctl__debug_children; 82struct sysctl_oid_list sysctl__kern_children; 83struct sysctl_oid_list sysctl__net_children; 84struct sysctl_oid_list sysctl__sysctl_children; 85*/ 86 87lck_rw_t * sysctl_geometry_lock = NULL; 88 89/* 90 * Conditionally allow dtrace to see these functions for debugging purposes. 91 */ 92#ifdef STATIC 93#undef STATIC 94#endif 95#if 0 96#define STATIC 97#else 98#define STATIC static 99#endif 100 101/* forward declarations of static functions */ 102STATIC funnel_t *spl_kernel_funnel(void); 103STATIC void sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i); 104STATIC int sysctl_sysctl_debug(struct sysctl_oid *oidp, void *arg1, 105 int arg2, struct sysctl_req *req); 106STATIC int sysctl_sysctl_name(struct sysctl_oid *oidp, void *arg1, 107 int arg2, struct sysctl_req *req); 108STATIC int sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, 109 int *name, u_int namelen, int *next, int *len, int level, 110 struct sysctl_oid **oidpp); 111STATIC int sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l); 112STATIC int sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l); 113STATIC int name2oid (char *name, int *oid, int *len); 114STATIC int sysctl_sysctl_name2oid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req); 115STATIC int sysctl_sysctl_next(struct sysctl_oid *oidp, void *arg1, int arg2, 116 struct sysctl_req *req); 117STATIC int sysctl_sysctl_oidfmt(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req); 118STATIC void splx_kernel_funnel(funnel_t *saved); 119STATIC int sysctl_old_user(struct sysctl_req *req, const void *p, size_t l); 120STATIC int sysctl_new_user(struct sysctl_req *req, void *p, size_t l); 121STATIC int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); 122STATIC int sysctlnametomib(const char *name, int *mibp, size_t *sizep); 123 124 125 126/* 127 * Locking and stats 128 */ 129 130/* 131 * XXX this does not belong here 132 */ 133STATIC funnel_t * 134spl_kernel_funnel(void) 135{ 136 funnel_t *cfunnel; 137 138 cfunnel = thread_funnel_get(); 139 if (cfunnel != kernel_flock) { 140 if (cfunnel != NULL) 141 thread_funnel_set(cfunnel, FALSE); 142 thread_funnel_set(kernel_flock, TRUE); 143 } 144 return(cfunnel); 145} 146 147STATIC void 148splx_kernel_funnel(funnel_t *saved) 149{ 150 if (saved != kernel_flock) { 151 thread_funnel_set(kernel_flock, FALSE); 152 if (saved != NULL) 153 thread_funnel_set(saved, TRUE); 154 } 155} 156 157STATIC int sysctl_root SYSCTL_HANDLER_ARGS; 158 159struct sysctl_oid_list sysctl__children; /* root list */ 160 161/* 162 * Initialization of the MIB tree. 163 * 164 * Order by number in each list. 165 */ 166 167void 168sysctl_register_oid(struct sysctl_oid *new_oidp) 169{ 170 struct sysctl_oid *oidp = NULL; 171 struct sysctl_oid_list *parent = new_oidp->oid_parent; 172 struct sysctl_oid *p; 173 struct sysctl_oid *q; 174 int n; 175 funnel_t *fnl = NULL; /* compiler doesn't notice CTLFLAG_LOCKED */ 176 177 /* 178 * The OID can be old-style (needs copy), new style without an earlier 179 * version (also needs copy), or new style with a matching version (no 180 * copy needed). Later versions are rejected (presumably, the OID 181 * structure was changed for a necessary reason). 182 */ 183 if (!(new_oidp->oid_kind & CTLFLAG_OID2)) { 184 /* 185 * XXX: M_TEMP is perhaps not the most apropriate zone, as it 186 * XXX: will subject us to use-after-free by other consumers. 187 */ 188 MALLOC(oidp, struct sysctl_oid *, sizeof(*oidp), M_TEMP, M_WAITOK | M_ZERO); 189 if (oidp == NULL) 190 return; /* reject: no memory */ 191 192 /* 193 * Copy the structure only through the oid_fmt field, which 194 * is the last field in a non-OID2 OID structure. 195 * 196 * Note: We may want to set the oid_descr to the 197 * oid_name (or "") at some future date. 198 */ 199 memcpy(oidp, new_oidp, offsetof(struct sysctl_oid, oid_descr)); 200 } else { 201 /* It's a later version; handle the versions we know about */ 202 switch (new_oidp->oid_version) { 203 case SYSCTL_OID_VERSION: 204 /* current version */ 205 oidp = new_oidp; 206 break; 207 default: 208 return; /* rejects unknown version */ 209 } 210 } 211 212 /* 213 * If it's a locked OID being registered, we can assume that the 214 * caller is doing their own reentrancy locking before calling us. 215 */ 216 if (!(oidp->oid_kind & CTLFLAG_LOCKED)) 217 fnl = spl_kernel_funnel(); 218 219 if(sysctl_geometry_lock == NULL) 220 { 221 /* 222 * Initialise the geometry lock for reading/modifying the 223 * sysctl tree. This is done here because IOKit registers 224 * some sysctl's before bsd_init() calls 225 * sysctl_register_fixed(). 226 */ 227 228 lck_grp_t* lck_grp = lck_grp_alloc_init("sysctl", NULL); 229 sysctl_geometry_lock = lck_rw_alloc_init(lck_grp, NULL); 230 } 231 /* Get the write lock to modify the geometry */ 232 lck_rw_lock_exclusive(sysctl_geometry_lock); 233 234 /* 235 * If this oid has a number OID_AUTO, give it a number which 236 * is greater than any current oid. Make sure it is at least 237 * OID_AUTO_START to leave space for pre-assigned oid numbers. 238 */ 239 if (oidp->oid_number == OID_AUTO) { 240 /* First, find the highest oid in the parent list >OID_AUTO_START-1 */ 241 n = OID_AUTO_START; 242 SLIST_FOREACH(p, parent, oid_link) { 243 if (p->oid_number > n) 244 n = p->oid_number; 245 } 246 oidp->oid_number = n + 1; 247 /* 248 * Reflect the number in an llocated OID into the template 249 * of the caller for sysctl_unregister_oid() compares. 250 */ 251 if (oidp != new_oidp) 252 new_oidp->oid_number = oidp->oid_number; 253 } 254 255 /* 256 * Insert the oid into the parent's list in order. 257 */ 258 q = NULL; 259 SLIST_FOREACH(p, parent, oid_link) { 260 if (oidp->oid_number < p->oid_number) 261 break; 262 q = p; 263 } 264 if (q) 265 SLIST_INSERT_AFTER(q, oidp, oid_link); 266 else 267 SLIST_INSERT_HEAD(parent, oidp, oid_link); 268 269 /* Release the write lock */ 270 lck_rw_unlock_exclusive(sysctl_geometry_lock); 271 272 if (!(oidp->oid_kind & CTLFLAG_LOCKED)) 273 splx_kernel_funnel(fnl); 274} 275 276void 277sysctl_unregister_oid(struct sysctl_oid *oidp) 278{ 279 struct sysctl_oid *removed_oidp = NULL; /* OID removed from tree */ 280 struct sysctl_oid *old_oidp = NULL; /* OID compatibility copy */ 281 funnel_t *fnl = NULL; /* compiler doesn't notice CTLFLAG_LOCKED */ 282 283 if (!(oidp->oid_kind & CTLFLAG_LOCKED)) 284 fnl = spl_kernel_funnel(); 285 286 /* Get the write lock to modify the geometry */ 287 lck_rw_lock_exclusive(sysctl_geometry_lock); 288 289 if (!(oidp->oid_kind & CTLFLAG_OID2)) { 290 /* 291 * We're using a copy so we can get the new fields in an 292 * old structure, so we have to iterate to compare the 293 * partial structure; when we find a match, we remove it 294 * normally and free the memory. 295 */ 296 SLIST_FOREACH(old_oidp, oidp->oid_parent, oid_link) { 297 if (!memcmp(&oidp->oid_number, &old_oidp->oid_number, (offsetof(struct sysctl_oid, oid_descr)-offsetof(struct sysctl_oid, oid_number)))) { 298 break; 299 } 300 } 301 if (old_oidp != NULL) { 302 SLIST_REMOVE(old_oidp->oid_parent, old_oidp, sysctl_oid, oid_link); 303 removed_oidp = old_oidp; 304 } 305 } else { 306 /* It's a later version; handle the versions we know about */ 307 switch (oidp->oid_version) { 308 case SYSCTL_OID_VERSION: 309 /* We can just remove the OID directly... */ 310 SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link); 311 removed_oidp = oidp; 312 break; 313 default: 314 /* XXX: Can't happen; probably tree coruption.*/ 315 break; /* rejects unknown version */ 316 } 317 } 318 319 /* 320 * We've removed it from the list at this point, but we don't want 321 * to return to the caller until all handler references have drained 322 * out. Doing things in this order prevent other people coming in 323 * and starting new operations against the OID node we want removed. 324 * 325 * Note: oidp could be NULL if it wasn't found. 326 */ 327 while(removed_oidp && removed_oidp->oid_refcnt) { 328 lck_rw_sleep(sysctl_geometry_lock, LCK_SLEEP_EXCLUSIVE, &removed_oidp->oid_refcnt, THREAD_UNINT); 329 } 330 331 /* Release the write lock */ 332 lck_rw_unlock_exclusive(sysctl_geometry_lock); 333 334 /* If it was allocated, free it after dropping the lock */ 335 if (old_oidp != NULL) { 336 FREE(old_oidp, M_TEMP); 337 } 338 339 /* And drop the funnel interlock, if needed */ 340 if (!(oidp->oid_kind & CTLFLAG_LOCKED)) 341 splx_kernel_funnel(fnl); 342} 343 344/* 345 * Bulk-register all the oids in a linker_set. 346 */ 347void 348sysctl_register_set(const char *set) 349{ 350 struct sysctl_oid **oidpp, *oidp; 351 352 LINKER_SET_FOREACH(oidpp, struct sysctl_oid **, set) { 353 oidp = *oidpp; 354 if (!(oidp->oid_kind & CTLFLAG_NOAUTO)) { 355 sysctl_register_oid(oidp); 356 } 357 } 358} 359 360void 361sysctl_unregister_set(const char *set) 362{ 363 struct sysctl_oid **oidpp, *oidp; 364 365 LINKER_SET_FOREACH(oidpp, struct sysctl_oid **, set) { 366 oidp = *oidpp; 367 if (!(oidp->oid_kind & CTLFLAG_NOAUTO)) { 368 sysctl_unregister_oid(oidp); 369 } 370 } 371} 372 373 374/* 375 * Register the kernel's oids on startup. 376 */ 377 378void 379sysctl_register_all() 380{ 381 sysctl_register_set("__sysctl_set"); 382} 383 384void 385sysctl_register_fixed(void) 386{ 387 sysctl_register_all(); 388} 389 390/* 391 * New handler interface 392 * If the sysctl caller (user mode or kernel mode) is interested in the 393 * value (req->oldptr != NULL), we copy the data (bigValue etc.) out, 394 * if the caller wants to set the value (req->newptr), we copy 395 * the data in (*pValue etc.). 396 */ 397 398int 399sysctl_io_number(struct sysctl_req *req, long long bigValue, size_t valueSize, void *pValue, int *changed) { 400 int smallValue; 401 int error; 402 403 if (changed) *changed = 0; 404 405 /* 406 * Handle the various combinations of caller buffer size and 407 * data value size. We are generous in the case where the 408 * caller has specified a 32-bit buffer but the value is 64-bit 409 * sized. 410 */ 411 412 /* 32 bit value expected or 32 bit buffer offered */ 413 if (((valueSize == sizeof(int)) || 414 ((req->oldlen == sizeof(int)) && (valueSize == sizeof(long long)))) 415 && (req->oldptr)) { 416 smallValue = (int)bigValue; 417 if ((long long)smallValue != bigValue) 418 return(ERANGE); 419 error = SYSCTL_OUT(req, &smallValue, sizeof(smallValue)); 420 } else { 421 /* any other case is either size-equal or a bug */ 422 error = SYSCTL_OUT(req, &bigValue, valueSize); 423 } 424 /* error or nothing to set */ 425 if (error || !req->newptr) 426 return(error); 427 428 /* set request for constant */ 429 if (pValue == NULL) 430 return(EPERM); 431 432 /* set request needs to convert? */ 433 if ((req->newlen == sizeof(int)) && (valueSize == sizeof(long long))) { 434 /* new value is 32 bits, upconvert to 64 bits */ 435 error = SYSCTL_IN(req, &smallValue, sizeof(smallValue)); 436 if (!error) 437 *(long long *)pValue = (long long)smallValue; 438 } else if ((req->newlen == sizeof(long long)) && (valueSize == sizeof(int))) { 439 /* new value is 64 bits, downconvert to 32 bits and range check */ 440 error = SYSCTL_IN(req, &bigValue, sizeof(bigValue)); 441 if (!error) { 442 smallValue = (int)bigValue; 443 if ((long long)smallValue != bigValue) 444 return(ERANGE); 445 *(int *)pValue = smallValue; 446 } 447 } else { 448 /* sizes match, just copy in */ 449 error = SYSCTL_IN(req, pValue, valueSize); 450 } 451 if (!error && changed) 452 *changed = 1; 453 return(error); 454} 455 456int 457sysctl_io_string(struct sysctl_req *req, char *pValue, size_t valueSize, int trunc, int *changed) 458{ 459 int error; 460 461 if (changed) *changed = 0; 462 463 if (trunc && req->oldptr && req->oldlen && (req->oldlen<strlen(pValue) + 1)) { 464 /* If trunc != 0, if you give it a too small (but larger than 465 * 0 bytes) buffer, instead of returning ENOMEM, it truncates the 466 * returned string to the buffer size. This preserves the semantics 467 * of some library routines implemented via sysctl, which truncate 468 * their returned data, rather than simply returning an error. The 469 * returned string is always NUL terminated. */ 470 error = SYSCTL_OUT(req, pValue, req->oldlen-1); 471 if (!error) { 472 char c = 0; 473 error = SYSCTL_OUT(req, &c, 1); 474 } 475 } else { 476 /* Copy string out */ 477 error = SYSCTL_OUT(req, pValue, strlen(pValue) + 1); 478 } 479 480 /* error or no new value */ 481 if (error || !req->newptr) 482 return(error); 483 484 /* attempt to set read-only value */ 485 if (valueSize == 0) 486 return(EPERM); 487 488 /* make sure there's room for the new string */ 489 if (req->newlen >= valueSize) 490 return(EINVAL); 491 492 /* copy the string in and force NUL termination */ 493 error = SYSCTL_IN(req, pValue, req->newlen); 494 pValue[req->newlen] = '\0'; 495 496 if (!error && changed) 497 *changed = 1; 498 return(error); 499} 500 501int sysctl_io_opaque(struct sysctl_req *req,void *pValue, size_t valueSize, int *changed) 502{ 503 int error; 504 505 if (changed) *changed = 0; 506 507 /* Copy blob out */ 508 error = SYSCTL_OUT(req, pValue, valueSize); 509 510 /* error or nothing to set */ 511 if (error || !req->newptr) 512 return(error); 513 514 error = SYSCTL_IN(req, pValue, valueSize); 515 516 if (!error && changed) 517 *changed = 1; 518 return(error); 519} 520 521/* 522 * "Staff-functions" 523 * 524 * These functions implement a presently undocumented interface 525 * used by the sysctl program to walk the tree, and get the type 526 * so it can print the value. 527 * This interface is under work and consideration, and should probably 528 * be killed with a big axe by the first person who can find the time. 529 * (be aware though, that the proper interface isn't as obvious as it 530 * may seem, there are various conflicting requirements. 531 * 532 * {0,0} printf the entire MIB-tree. 533 * {0,1,...} return the name of the "..." OID. 534 * {0,2,...} return the next OID. 535 * {0,3} return the OID of the name in "new" 536 * {0,4,...} return the kind & format info for the "..." OID. 537 */ 538 539/* 540 * sysctl_sysctl_debug_dump_node 541 * 542 * Description: Dump debug information for a given sysctl_oid_list at the 543 * given oid depth out to the kernel log, via printf 544 * 545 * Parameters: l sysctl_oid_list pointer 546 * i current node depth 547 * 548 * Returns: (void) 549 * 550 * Implicit: kernel log, modified 551 * 552 * Locks: Assumes sysctl_geometry_lock is held prior to calling 553 * 554 * Notes: This function may call itself recursively to resolve Node 555 * values, which potentially have an inferioer sysctl_oid_list 556 * 557 * This function is only callable indirectly via the function 558 * sysctl_sysctl_debug() 559 * 560 * Bugs: The node depth indentation does not work; this may be an 561 * artifact of leading space removal by the log daemon itself 562 * or some intermediate routine. 563 */ 564STATIC void 565sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i) 566{ 567 int k; 568 struct sysctl_oid *oidp; 569 570 SLIST_FOREACH(oidp, l, oid_link) { 571 572 for (k=0; k<i; k++) 573 printf(" "); 574 575 printf("%d %s ", oidp->oid_number, oidp->oid_name); 576 577 printf("%c%c%c", 578 oidp->oid_kind & CTLFLAG_LOCKED ? 'L':' ', 579 oidp->oid_kind & CTLFLAG_RD ? 'R':' ', 580 oidp->oid_kind & CTLFLAG_WR ? 'W':' '); 581 582 if (oidp->oid_handler) 583 printf(" *Handler"); 584 585 switch (oidp->oid_kind & CTLTYPE) { 586 case CTLTYPE_NODE: 587 printf(" Node\n"); 588 if (!oidp->oid_handler) { 589 sysctl_sysctl_debug_dump_node( 590 oidp->oid_arg1, i+2); 591 } 592 break; 593 case CTLTYPE_INT: printf(" Int\n"); break; 594 case CTLTYPE_STRING: printf(" String\n"); break; 595 case CTLTYPE_QUAD: printf(" Quad\n"); break; 596 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 597 default: printf("\n"); 598 } 599 600 } 601} 602 603/* 604 * sysctl_sysctl_debug 605 * 606 * Description: This function implements the "sysctl.debug" portion of the 607 * OID space for sysctl. 608 * 609 * OID: 0, 0 610 * 611 * Parameters: __unused 612 * 613 * Returns: ENOENT 614 * 615 * Implicit: kernel log, modified 616 * 617 * Locks: Acquires and then releases a read lock on the 618 * sysctl_geometry_lock 619 */ 620STATIC int 621sysctl_sysctl_debug(__unused struct sysctl_oid *oidp, __unused void *arg1, 622 __unused int arg2, __unused struct sysctl_req *req) 623{ 624 lck_rw_lock_shared(sysctl_geometry_lock); 625 sysctl_sysctl_debug_dump_node(&sysctl__children, 0); 626 lck_rw_done(sysctl_geometry_lock); 627 return ENOENT; 628} 629 630SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD | CTLFLAG_LOCKED, 631 0, 0, sysctl_sysctl_debug, "-", ""); 632 633/* 634 * sysctl_sysctl_name 635 * 636 * Description: Convert an OID into a string name; this is used by the user 637 * space sysctl() command line utility; this is done in a purely 638 * advisory capacity (e.g. to provide node names for "sysctl -A" 639 * output). 640 * 641 * OID: 0, 1 642 * 643 * Parameters: oidp __unused 644 * arg1 A pointer to the OID name list 645 * integer array, beginning at 646 * adjusted option base 2 647 * arg2 The number of elements which 648 * remain in the name array 649 * 650 * Returns: 0 Success 651 * SYSCTL_OUT:EPERM Permission denied 652 * SYSCTL_OUT:EFAULT Bad user supplied buffer 653 * SYSCTL_OUT:??? Return value from user function 654 * for SYSCTL_PROC leaf node 655 * 656 * Implict: Contents of user request buffer, modified 657 * 658 * Locks: Acquires and then releases a read lock on the 659 * sysctl_geometry_lock 660 * 661 * Notes: SPI (System Programming Interface); this is subject to change 662 * and may not be relied upon by third party applications; use 663 * a subprocess to communicate with the "sysctl" command line 664 * command instead, if you believe you need this functionality. 665 * Preferrably, use sysctlbyname() instead. 666 * 667 * Setting of the NULL termination of the output string is 668 * delayed until after the geometry lock is dropped. If there 669 * are no Entries remaining in the OID name list when this 670 * function is called, it will still write out the termination 671 * byte. 672 * 673 * This function differs from other sysctl functions in that 674 * it can not take an output buffer length of 0 to determine the 675 * space which will be required. It is suggested that the buffer 676 * length be PATH_MAX, and that authors of new sysctl's refrain 677 * from exceeding this string length. 678 */ 679STATIC int 680sysctl_sysctl_name(__unused struct sysctl_oid *oidp, void *arg1, int arg2, 681 struct sysctl_req *req) 682{ 683 int *name = (int *) arg1; 684 u_int namelen = arg2; 685 int error = 0; 686 struct sysctl_oid *oid; 687 struct sysctl_oid_list *lsp = &sysctl__children, *lsp2; 688 char tempbuf[10]; 689 690 lck_rw_lock_shared(sysctl_geometry_lock); 691 while (namelen) { 692 if (!lsp) { 693 snprintf(tempbuf,sizeof(tempbuf),"%d",*name); 694 if (req->oldidx) 695 error = SYSCTL_OUT(req, ".", 1); 696 if (!error) 697 error = SYSCTL_OUT(req, tempbuf, strlen(tempbuf)); 698 if (error) { 699 lck_rw_done(sysctl_geometry_lock); 700 return (error); 701 } 702 namelen--; 703 name++; 704 continue; 705 } 706 lsp2 = 0; 707 SLIST_FOREACH(oid, lsp, oid_link) { 708 if (oid->oid_number != *name) 709 continue; 710 711 if (req->oldidx) 712 error = SYSCTL_OUT(req, ".", 1); 713 if (!error) 714 error = SYSCTL_OUT(req, oid->oid_name, 715 strlen(oid->oid_name)); 716 if (error) { 717 lck_rw_done(sysctl_geometry_lock); 718 return (error); 719 } 720 721 namelen--; 722 name++; 723 724 if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) 725 break; 726 727 if (oid->oid_handler) 728 break; 729 730 lsp2 = (struct sysctl_oid_list *)oid->oid_arg1; 731 break; 732 } 733 lsp = lsp2; 734 } 735 lck_rw_done(sysctl_geometry_lock); 736 return (SYSCTL_OUT(req, "", 1)); 737} 738 739SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_name, ""); 740 741/* 742 * sysctl_sysctl_next_ls 743 * 744 * Description: For a given OID name value, return the next consecutive OID 745 * name value within the geometry tree 746 * 747 * Parameters: lsp The OID list to look in 748 * name The OID name to start from 749 * namelen The length of the OID name 750 * next Pointer to new oid storage to 751 * fill in 752 * len Pointer to receive new OID 753 * length value of storage written 754 * level OID tree depth (used to compute 755 * len value) 756 * oidpp Pointer to OID list entry 757 * pointer; used to walk the list 758 * forward across recursion 759 * 760 * Returns: 0 Returning a new entry 761 * 1 End of geometry list reached 762 * 763 * Implicit: *next Modified to contain the new OID 764 * *len Modified to contain new length 765 * 766 * Locks: Assumes sysctl_geometry_lock is held prior to calling 767 * 768 * Notes: This function will not return OID values that have special 769 * handlers, since we can not tell wheter these handlers consume 770 * elements from the OID space as parameters. For this reason, 771 * we STRONGLY discourage these types of handlers 772 */ 773STATIC int 774sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen, 775 int *next, int *len, int level, struct sysctl_oid **oidpp) 776{ 777 struct sysctl_oid *oidp; 778 779 *len = level; 780 SLIST_FOREACH(oidp, lsp, oid_link) { 781 *next = oidp->oid_number; 782 *oidpp = oidp; 783 784 if (!namelen) { 785 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 786 return 0; 787 if (oidp->oid_handler) 788 /* We really should call the handler here...*/ 789 return 0; 790 lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 791 792 if (!SLIST_FIRST(lsp)) 793 /* This node had no children - skip it! */ 794 continue; 795 796 if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1, 797 len, level+1, oidpp)) 798 return 0; 799 goto next; 800 } 801 802 if (oidp->oid_number < *name) 803 continue; 804 805 if (oidp->oid_number > *name) { 806 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 807 return 0; 808 if (oidp->oid_handler) 809 return 0; 810 lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 811 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, 812 next+1, len, level+1, oidpp)) 813 return (0); 814 goto next; 815 } 816 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 817 continue; 818 819 if (oidp->oid_handler) 820 continue; 821 822 lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 823 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1, 824 len, level+1, oidpp)) 825 return (0); 826 next: 827 namelen = 1; 828 *len = level; 829 } 830 return 1; 831} 832 833/* 834 * sysctl_sysctl_next 835 * 836 * Description: This is an iterator function designed to iterate the oid tree 837 * and provide a list of OIDs for use by the user space "sysctl" 838 * command line tool 839 * 840 * OID: 0, 2 841 * 842 * Parameters: oidp __unused 843 * arg1 Pointer to start OID name 844 * arg2 Start OID name length 845 * req Pointer to user request buffer 846 * 847 * Returns: 0 Success 848 * ENOENT Reached end of OID space 849 * SYSCTL_OUT:EPERM Permission denied 850 * SYSCTL_OUT:EFAULT Bad user supplied buffer 851 * SYSCTL_OUT:??? Return value from user function 852 * for SYSCTL_PROC leaf node 853 * 854 * Implict: Contents of user request buffer, modified 855 * 856 * Locks: Acquires and then releases a read lock on the 857 * sysctl_geometry_lock 858 * 859 * Notes: SPI (System Programming Interface); this is subject to change 860 * and may not be relied upon by third party applications; use 861 * a subprocess to communicate with the "sysctl" command line 862 * command instead, if you believe you need this functionality. 863 * Preferrably, use sysctlbyname() instead. 864 * 865 * This function differs from other sysctl functions in that 866 * it can not take an output buffer length of 0 to determine the 867 * space which will be required. It is suggested that the buffer 868 * length be PATH_MAX, and that authors of new sysctl's refrain 869 * from exceeding this string length. 870 */ 871STATIC int 872sysctl_sysctl_next(__unused struct sysctl_oid *oidp, void *arg1, int arg2, 873 struct sysctl_req *req) 874{ 875 int *name = (int *) arg1; 876 u_int namelen = arg2; 877 int i, j, error; 878 struct sysctl_oid *oid; 879 struct sysctl_oid_list *lsp = &sysctl__children; 880 int newoid[CTL_MAXNAME]; 881 882 lck_rw_lock_shared(sysctl_geometry_lock); 883 i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid); 884 lck_rw_done(sysctl_geometry_lock); 885 if (i) 886 return ENOENT; 887 error = SYSCTL_OUT(req, newoid, j * sizeof (int)); 888 return (error); 889} 890 891SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_next, ""); 892 893/* 894 * name2oid 895 * 896 * Description: Support function for use by sysctl_sysctl_name2oid(); looks 897 * up an OID name given a string name. 898 * 899 * Parameters: name NULL terminated string name 900 * oid Pointer to receive OID name 901 * len Pointer to receive OID length 902 * pointer value (see "Notes") 903 * 904 * Returns: 0 Success 905 * ENOENT Entry not found 906 * 907 * Implicit: *oid Modified to contain OID value 908 * *len Modified to contain OID length 909 * 910 * Locks: Assumes sysctl_geometry_lock is held prior to calling 911 */ 912STATIC int 913name2oid (char *name, int *oid, int *len) 914{ 915 int i; 916 struct sysctl_oid *oidp; 917 struct sysctl_oid_list *lsp = &sysctl__children; 918 char *p; 919 920 if (!*name) 921 return ENOENT; 922 923 p = name + strlen(name) - 1 ; 924 if (*p == '.') 925 *p = '\0'; 926 927 *len = 0; 928 929 for (p = name; *p && *p != '.'; p++) 930 ; 931 i = *p; 932 if (i == '.') 933 *p = '\0'; 934 935 oidp = SLIST_FIRST(lsp); 936 937 while (oidp && *len < CTL_MAXNAME) { 938 if (strcmp(name, oidp->oid_name)) { 939 oidp = SLIST_NEXT(oidp, oid_link); 940 continue; 941 } 942 *oid++ = oidp->oid_number; 943 (*len)++; 944 945 if (!i) { 946 return (0); 947 } 948 949 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 950 break; 951 952 if (oidp->oid_handler) 953 break; 954 955 lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 956 oidp = SLIST_FIRST(lsp); 957 name = p+1; 958 for (p = name; *p && *p != '.'; p++) 959 ; 960 i = *p; 961 if (i == '.') 962 *p = '\0'; 963 } 964 return ENOENT; 965} 966 967/* 968 * sysctl_sysctl_name2oid 969 * 970 * Description: Translate a string name to an OID name value; this is used by 971 * the sysctlbyname() function as well as by the "sysctl" command 972 * line command. 973 * 974 * OID: 0, 3 975 * 976 * Parameters: oidp __unused 977 * arg1 __unused 978 * arg2 __unused 979 * req Request structure 980 * 981 * Returns: ENOENT Input length too short 982 * ENAMETOOLONG Input length too long 983 * ENOMEM Could not allocate work area 984 * SYSCTL_IN/OUT:EPERM Permission denied 985 * SYSCTL_IN/OUT:EFAULT Bad user supplied buffer 986 * SYSCTL_IN/OUT:??? Return value from user function 987 * name2oid:ENOENT Not found 988 * 989 * Implicit: *req Contents of request, modified 990 * 991 * Locks: Acquires and then releases a read lock on the 992 * sysctl_geometry_lock 993 * 994 * Notes: SPI (System Programming Interface); this is subject to change 995 * and may not be relied upon by third party applications; use 996 * a subprocess to communicate with the "sysctl" command line 997 * command instead, if you believe you need this functionality. 998 * Preferrably, use sysctlbyname() instead. 999 * 1000 * This function differs from other sysctl functions in that 1001 * it can not take an output buffer length of 0 to determine the 1002 * space which will be required. It is suggested that the buffer 1003 * length be PATH_MAX, and that authors of new sysctl's refrain 1004 * from exceeding this string length. 1005 */ 1006STATIC int 1007sysctl_sysctl_name2oid(__unused struct sysctl_oid *oidp, __unused void *arg1, 1008 __unused int arg2, struct sysctl_req *req) 1009{ 1010 char *p; 1011 int error, oid[CTL_MAXNAME]; 1012 int len = 0; /* set by name2oid() */ 1013 1014 if (req->newlen < 1) 1015 return ENOENT; 1016 if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */ 1017 return (ENAMETOOLONG); 1018 1019 MALLOC(p, char *,req->newlen+1, M_TEMP, M_WAITOK); 1020 if (!p) 1021 return ENOMEM; 1022 1023 error = SYSCTL_IN(req, p, req->newlen); 1024 if (error) { 1025 FREE(p, M_TEMP); 1026 return (error); 1027 } 1028 1029 p [req->newlen] = '\0'; 1030 1031 /* 1032 * Note: We acquire and release the geometry lock here to 1033 * avoid making name2oid needlessly complex. 1034 */ 1035 lck_rw_lock_shared(sysctl_geometry_lock); 1036 error = name2oid(p, oid, &len); 1037 lck_rw_done(sysctl_geometry_lock); 1038 1039 FREE(p, M_TEMP); 1040 1041 if (error) 1042 return (error); 1043 1044 error = SYSCTL_OUT(req, oid, len * sizeof *oid); 1045 return (error); 1046} 1047 1048SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY|CTLFLAG_KERN | CTLFLAG_LOCKED, 0, 0, 1049 sysctl_sysctl_name2oid, "I", ""); 1050 1051/* 1052 * sysctl_sysctl_oidfmt 1053 * 1054 * Description: For a given OID name, determine the format of the data which 1055 * is associated with it. This is used by the "sysctl" command 1056 * line command. 1057 * 1058 * OID: 0, 4 1059 * 1060 * Parameters: oidp __unused 1061 * arg1 The OID name to look up 1062 * arg2 The length of the OID name 1063 * req Pointer to user request buffer 1064 * 1065 * Returns: 0 Success 1066 * EISDIR Malformed request 1067 * ENOENT No such OID name 1068 * SYSCTL_OUT:EPERM Permission denied 1069 * SYSCTL_OUT:EFAULT Bad user supplied buffer 1070 * SYSCTL_OUT:??? Return value from user function 1071 * 1072 * Implict: Contents of user request buffer, modified 1073 * 1074 * Locks: Acquires and then releases a read lock on the 1075 * sysctl_geometry_lock 1076 * 1077 * Notes: SPI (System Programming Interface); this is subject to change 1078 * and may not be relied upon by third party applications; use 1079 * a subprocess to communicate with the "sysctl" command line 1080 * command instead, if you believe you need this functionality. 1081 * 1082 * This function differs from other sysctl functions in that 1083 * it can not take an output buffer length of 0 to determine the 1084 * space which will be required. It is suggested that the buffer 1085 * length be PATH_MAX, and that authors of new sysctl's refrain 1086 * from exceeding this string length. 1087 */ 1088STATIC int 1089sysctl_sysctl_oidfmt(__unused struct sysctl_oid *oidp, void *arg1, int arg2, 1090 struct sysctl_req *req) 1091{ 1092 int *name = (int *) arg1; 1093 int error = ENOENT; /* default error: not found */ 1094 u_int namelen = arg2; 1095 u_int indx; 1096 struct sysctl_oid *oid; 1097 struct sysctl_oid_list *lsp = &sysctl__children; 1098 1099 lck_rw_lock_shared(sysctl_geometry_lock); 1100 oid = SLIST_FIRST(lsp); 1101 1102 indx = 0; 1103 while (oid && indx < CTL_MAXNAME) { 1104 if (oid->oid_number == name[indx]) { 1105 indx++; 1106 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1107 if (oid->oid_handler) 1108 goto found; 1109 if (indx == namelen) 1110 goto found; 1111 lsp = (struct sysctl_oid_list *)oid->oid_arg1; 1112 oid = SLIST_FIRST(lsp); 1113 } else { 1114 if (indx != namelen) { 1115 error = EISDIR; 1116 goto err; 1117 } 1118 goto found; 1119 } 1120 } else { 1121 oid = SLIST_NEXT(oid, oid_link); 1122 } 1123 } 1124 /* Not found */ 1125 goto err; 1126 1127found: 1128 if (!oid->oid_fmt) 1129 goto err; 1130 error = SYSCTL_OUT(req, 1131 &oid->oid_kind, sizeof(oid->oid_kind)); 1132 if (!error) 1133 error = SYSCTL_OUT(req, oid->oid_fmt, 1134 strlen(oid->oid_fmt)+1); 1135err: 1136 lck_rw_done(sysctl_geometry_lock); 1137 return (error); 1138} 1139 1140SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_oidfmt, ""); 1141 1142 1143/* 1144 * Default "handler" functions. 1145 */ 1146 1147/* 1148 * Handle an int, signed or unsigned. 1149 * Two cases: 1150 * a variable: point arg1 at it. 1151 * a constant: pass it in arg2. 1152 */ 1153 1154int 1155sysctl_handle_int(__unused struct sysctl_oid *oidp, void *arg1, int arg2, 1156 struct sysctl_req *req) 1157{ 1158 return sysctl_io_number(req, arg1? *(int*)arg1: arg2, sizeof(int), arg1, NULL); 1159} 1160 1161/* 1162 * Handle a long, signed or unsigned. arg1 points to it. 1163 */ 1164 1165int 1166sysctl_handle_long(__unused struct sysctl_oid *oidp, void *arg1, 1167 __unused int arg2, struct sysctl_req *req) 1168{ 1169 if (!arg1) 1170 return (EINVAL); 1171 return sysctl_io_number(req, *(long*)arg1, sizeof(long), arg1, NULL); 1172} 1173 1174/* 1175 * Handle a quad, signed or unsigned. arg1 points to it. 1176 */ 1177 1178int 1179sysctl_handle_quad(__unused struct sysctl_oid *oidp, void *arg1, 1180 __unused int arg2, struct sysctl_req *req) 1181{ 1182 if (!arg1) 1183 return (EINVAL); 1184 return sysctl_io_number(req, *(long long*)arg1, sizeof(long long), arg1, NULL); 1185} 1186 1187/* 1188 * Expose an int value as a quad. 1189 * 1190 * This interface allows us to support interfaces defined 1191 * as using quad values while the implementation is still 1192 * using ints. 1193 */ 1194int 1195sysctl_handle_int2quad(__unused struct sysctl_oid *oidp, void *arg1, 1196 __unused int arg2, struct sysctl_req *req) 1197{ 1198 int error = 0; 1199 long long val; 1200 int newval; 1201 1202 if (!arg1) 1203 return (EINVAL); 1204 val = (long long)*(int *)arg1; 1205 error = SYSCTL_OUT(req, &val, sizeof(long long)); 1206 1207 if (error || !req->newptr) 1208 return (error); 1209 1210 error = SYSCTL_IN(req, &val, sizeof(long long)); 1211 if (!error) { 1212 /* 1213 * Value must be representable; check by 1214 * casting and then casting back. 1215 */ 1216 newval = (int)val; 1217 if ((long long)newval != val) { 1218 error = ERANGE; 1219 } else { 1220 *(int *)arg1 = newval; 1221 } 1222 } 1223 return (error); 1224} 1225 1226/* 1227 * Handle our generic '\0' terminated 'C' string. 1228 * Two cases: 1229 * a variable string: point arg1 at it, arg2 is max length. 1230 * a constant string: point arg1 at it, arg2 is zero. 1231 */ 1232 1233int 1234sysctl_handle_string( __unused struct sysctl_oid *oidp, void *arg1, int arg2, 1235 struct sysctl_req *req) 1236{ 1237 return sysctl_io_string(req, arg1, arg2, 0, NULL); 1238} 1239 1240/* 1241 * Handle any kind of opaque data. 1242 * arg1 points to it, arg2 is the size. 1243 */ 1244 1245int 1246sysctl_handle_opaque(__unused struct sysctl_oid *oidp, void *arg1, int arg2, 1247 struct sysctl_req *req) 1248{ 1249 return sysctl_io_opaque(req, arg1, arg2, NULL); 1250} 1251 1252/* 1253 * Transfer functions to/from kernel space. 1254 */ 1255STATIC int 1256sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) 1257{ 1258 size_t i = 0; 1259 1260 if (req->oldptr) { 1261 i = l; 1262 if (i > req->oldlen - req->oldidx) 1263 i = req->oldlen - req->oldidx; 1264 if (i > 0) 1265 bcopy((const void*)p, CAST_DOWN(char *, (req->oldptr + req->oldidx)), i); 1266 } 1267 req->oldidx += l; 1268 if (req->oldptr && i != l) 1269 return (ENOMEM); 1270 return (0); 1271} 1272 1273STATIC int 1274sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) 1275{ 1276 if (!req->newptr) 1277 return 0; 1278 if (req->newlen - req->newidx < l) 1279 return (EINVAL); 1280 bcopy(CAST_DOWN(char *, (req->newptr + req->newidx)), p, l); 1281 req->newidx += l; 1282 return (0); 1283} 1284 1285int 1286kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen) 1287{ 1288 int error = 0; 1289 struct sysctl_req req; 1290 1291 /* 1292 * Construct request. 1293 */ 1294 bzero(&req, sizeof req); 1295 req.p = p; 1296 if (oldlenp) 1297 req.oldlen = *oldlenp; 1298 if (old) 1299 req.oldptr = CAST_USER_ADDR_T(old); 1300 if (newlen) { 1301 req.newlen = newlen; 1302 req.newptr = CAST_USER_ADDR_T(new); 1303 } 1304 req.oldfunc = sysctl_old_kernel; 1305 req.newfunc = sysctl_new_kernel; 1306 req.lock = 1; 1307 1308 /* make the request */ 1309 error = sysctl_root(0, name, namelen, &req); 1310 1311 /* unlock memory if required */ 1312 if (req.lock == 2) 1313 vsunlock(req.oldptr, (user_size_t)req.oldlen, B_WRITE); 1314 1315 if (error && error != ENOMEM) 1316 return (error); 1317 1318 if (oldlenp) 1319 *oldlenp = req.oldidx; 1320 1321 return (error); 1322} 1323 1324/* 1325 * Transfer function to/from user space. 1326 */ 1327STATIC int 1328sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) 1329{ 1330 int error = 0; 1331 size_t i = 0; 1332 1333 if (req->oldptr) { 1334 if (req->oldlen - req->oldidx < l) 1335 return (ENOMEM); 1336 i = l; 1337 if (i > req->oldlen - req->oldidx) 1338 i = req->oldlen - req->oldidx; 1339 if (i > 0) 1340 error = copyout((const void*)p, (req->oldptr + req->oldidx), i); 1341 } 1342 req->oldidx += l; 1343 if (error) 1344 return (error); 1345 if (req->oldptr && i < l) 1346 return (ENOMEM); 1347 return (0); 1348} 1349 1350STATIC int 1351sysctl_new_user(struct sysctl_req *req, void *p, size_t l) 1352{ 1353 int error; 1354 1355 if (!req->newptr) 1356 return 0; 1357 if (req->newlen - req->newidx < l) 1358 return (EINVAL); 1359 error = copyin((req->newptr + req->newidx), p, l); 1360 req->newidx += l; 1361 return (error); 1362} 1363 1364/* 1365 * Traverse our tree, and find the right node, execute whatever it points 1366 * at, and return the resulting error code. 1367 */ 1368 1369int 1370sysctl_root(__unused struct sysctl_oid *oidp, void *arg1, int arg2, 1371 struct sysctl_req *req) 1372{ 1373 int *name = (int *) arg1; 1374 u_int namelen = arg2; 1375 u_int indx; 1376 int i; 1377 struct sysctl_oid *oid; 1378 struct sysctl_oid_list *lsp = &sysctl__children; 1379 int error; 1380 funnel_t *fnl = NULL; 1381 boolean_t funnel_held = FALSE; 1382 1383 /* Get the read lock on the geometry */ 1384 lck_rw_lock_shared(sysctl_geometry_lock); 1385 1386 oid = SLIST_FIRST(lsp); 1387 1388 indx = 0; 1389 while (oid && indx < CTL_MAXNAME) { 1390 if (oid->oid_number == name[indx]) { 1391 indx++; 1392 if (!(oid->oid_kind & CTLFLAG_LOCKED)) 1393 { 1394/* 1395printf("sysctl_root: missing CTLFLAG_LOCKED: "); 1396for(i = 0; i < (int)(indx - 1); i++) 1397printf("oid[%d] = %d ", i, name[i]); 1398printf("\n"); 1399*/ 1400 funnel_held = TRUE; 1401 } 1402 if (oid->oid_kind & CTLFLAG_NOLOCK) 1403 req->lock = 0; 1404 /* 1405 * For SYSCTL_PROC() functions which are for sysctl's 1406 * which have parameters at the end of their OID 1407 * space, you need to OR CTLTYPE_NODE into their 1408 * access value. 1409 * 1410 * NOTE: For binary backward compatibility ONLY! Do 1411 * NOT add new sysctl's that do this! Existing 1412 * sysctl's which do this will eventually have 1413 * compatibility code in user space, and this method 1414 * will become unsupported. 1415 */ 1416 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1417 if (oid->oid_handler) 1418 goto found; 1419 if (indx == namelen) 1420 { 1421 error = ENOENT; 1422 goto err; 1423 } 1424 1425 lsp = (struct sysctl_oid_list *)oid->oid_arg1; 1426 oid = SLIST_FIRST(lsp); 1427 } else { 1428 if (indx != namelen) 1429 { 1430 error = EISDIR; 1431 goto err; 1432 } 1433 goto found; 1434 } 1435 } else { 1436 oid = SLIST_NEXT(oid, oid_link); 1437 } 1438 } 1439 error = ENOENT; 1440 goto err; 1441found: 1442 /* If writing isn't allowed */ 1443 if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) || 1444 ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) { 1445 error = (EPERM); 1446 goto err; 1447 } 1448 1449 /* 1450 * If we're inside the kernel, the OID must be marked as kernel-valid. 1451 * XXX This mechanism for testing is bad. 1452 */ 1453 if ((req->oldfunc == sysctl_old_kernel) && !(oid->oid_kind & CTLFLAG_KERN)) 1454 { 1455 error = (EPERM); 1456 goto err; 1457 } 1458 1459 /* 1460 * This is where legacy enforcement of permissions occurs. If the 1461 * flag does not say CTLFLAG_ANYBODY, then we prohibit anyone but 1462 * root from writing new values down. If local enforcement happens 1463 * at the leaf node, then it needs to be set as CTLFLAG_ANYBODY. In 1464 * addition, if the leaf node is set this way, then in order to do 1465 * specific enforcement, it has to be of type SYSCTL_PROC. 1466 */ 1467 if (!(oid->oid_kind & CTLFLAG_ANYBODY) && 1468 req->newptr && req->p && 1469 (error = proc_suser(req->p))) 1470 goto err; 1471 1472 if (!oid->oid_handler) { 1473 error = EINVAL; 1474 goto err; 1475 } 1476 1477 /* 1478 * Reference the OID and drop the geometry lock; this prevents the 1479 * OID from being deleted out from under the handler call, but does 1480 * not prevent other calls into handlers or calls to manage the 1481 * geometry elsewhere from blocking... 1482 */ 1483 OSAddAtomic(1, &oid->oid_refcnt); 1484 1485 lck_rw_done(sysctl_geometry_lock); 1486 1487 /* 1488 * ...however, we still have to grab the funnel for those calls which 1489 * may be into code whose reentrancy is protected by the funnel; a 1490 * blocking operation should not prevent reentrancy, at this point. 1491 */ 1492 if (funnel_held) 1493 { 1494 fnl = spl_kernel_funnel(); 1495 } 1496 1497 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1498 i = (oid->oid_handler) (oid, 1499 name + indx, namelen - indx, 1500 req); 1501 } else { 1502 i = (oid->oid_handler) (oid, 1503 oid->oid_arg1, oid->oid_arg2, 1504 req); 1505 } 1506 error = i; 1507 1508 if (funnel_held) 1509 { 1510 splx_kernel_funnel(fnl); 1511 } 1512 1513 /* 1514 * This is tricky... we re-grab the geometry lock in order to drop 1515 * the reference and wake on the address; since the geometry 1516 * lock is a reader/writer lock rather than a mutex, we have to 1517 * wake on all apparent 1->0 transitions. This abuses the drop 1518 * after the reference decrement in order to wake any lck_rw_sleep() 1519 * in progress in sysctl_unregister_oid() that slept because of a 1520 * non-zero reference count. 1521 * 1522 * Note: OSAddAtomic() is defined to return the previous value; 1523 * we use this and the fact that the lock itself is a 1524 * barrier to avoid waking every time through on "hot" 1525 * OIDs. 1526 */ 1527 lck_rw_lock_shared(sysctl_geometry_lock); 1528 if (OSAddAtomic(-1, &oid->oid_refcnt) == 1) 1529 wakeup(&oid->oid_refcnt); 1530 1531err: 1532 lck_rw_done(sysctl_geometry_lock); 1533 return (error); 1534} 1535 1536#ifndef _SYS_SYSPROTO_H_ 1537struct sysctl_args { 1538 int *name; 1539 u_int namelen; 1540 void *old; 1541 size_t *oldlenp; 1542 void *new; 1543 size_t newlen; 1544}; 1545#endif 1546 1547int 1548/* __sysctl(struct proc *p, struct sysctl_args *uap) */ 1549new_sysctl(struct proc *p, struct sysctl_args *uap) 1550{ 1551 int error, i, name[CTL_MAXNAME]; 1552 size_t j; 1553 1554 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 1555 return (EINVAL); 1556 1557 error = copyin(CAST_USER_ADDR_T(uap->name), &name, uap->namelen * sizeof(int)); 1558 if (error) 1559 return (error); 1560 1561 error = userland_sysctl(p, name, uap->namelen, 1562 CAST_USER_ADDR_T(uap->old), uap->oldlenp, 1563 CAST_USER_ADDR_T(uap->new), uap->newlen, &j); 1564 if (error && error != ENOMEM) 1565 return (error); 1566 if (uap->oldlenp) { 1567 i = copyout(&j, CAST_USER_ADDR_T(uap->oldlenp), sizeof(j)); 1568 if (i) 1569 return (i); 1570 } 1571 return (error); 1572} 1573 1574/* 1575 * This is used from various compatibility syscalls too. That's why name 1576 * must be in kernel space. 1577 */ 1578int 1579userland_sysctl(struct proc *p, int *name, u_int namelen, user_addr_t oldp, 1580 size_t *oldlenp, user_addr_t newp, size_t newlen, 1581 size_t *retval) 1582{ 1583 int error = 0; 1584 struct sysctl_req req, req2; 1585 1586 bzero(&req, sizeof req); 1587 1588 req.p = p; 1589 1590 if (oldlenp) { 1591 req.oldlen = *oldlenp; 1592 } 1593 1594 if (oldp) { 1595 req.oldptr = oldp; 1596 } 1597 1598 if (newlen) { 1599 req.newlen = newlen; 1600 req.newptr = newp; 1601 } 1602 1603 req.oldfunc = sysctl_old_user; 1604 req.newfunc = sysctl_new_user; 1605 req.lock = 1; 1606 1607 do { 1608 req2 = req; 1609 error = sysctl_root(0, name, namelen, &req2); 1610 } while (error == EAGAIN); 1611 1612 req = req2; 1613 1614 if (error && error != ENOMEM) 1615 return (error); 1616 1617 if (retval) { 1618 if (req.oldptr && req.oldidx > req.oldlen) 1619 *retval = req.oldlen; 1620 else 1621 *retval = req.oldidx; 1622 } 1623 return (error); 1624} 1625 1626/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ 1627#define KINFO_BSDI_SYSINFO (101<<8) 1628 1629/* 1630 * Kernel versions of the userland sysctl helper functions. 1631 * 1632 * These allow sysctl to be used in the same fashion in both 1633 * userland and the kernel. 1634 * 1635 * Note that some sysctl handlers use copyin/copyout, which 1636 * may not work correctly. 1637 */ 1638 1639STATIC int 1640sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) 1641{ 1642 1643 return(kernel_sysctl(current_proc(), name, namelen, oldp, oldlenp, newp, newlen)); 1644} 1645 1646STATIC int 1647sysctlnametomib(const char *name, int *mibp, size_t *sizep) 1648{ 1649 int oid[2]; 1650 int error; 1651 char *non_const_name; 1652 1653 /* 1654 * NOTE: This cast is safe because the service node does not modify 1655 * the contents of the string as part of its operation. 1656 */ 1657 non_const_name = __CAST_AWAY_QUALIFIER(name, const, char *); 1658 1659 /* magic service node */ 1660 oid[0] = 0; 1661 oid[1] = 3; 1662 1663 /* look up OID for name */ 1664 *sizep *= sizeof(int); 1665 error = sysctl(oid, 2, mibp, sizep, non_const_name, strlen(name)); 1666 *sizep /= sizeof(int); 1667 1668 return(error); 1669} 1670 1671int 1672sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) 1673{ 1674 int oid[CTL_MAXNAME + 2]; 1675 int error; 1676 size_t oidlen; 1677 1678 /* look up the OID */ 1679 oidlen = CTL_MAXNAME; 1680 error = sysctlnametomib(name, oid, &oidlen); 1681 1682 /* now use the OID */ 1683 if (error == 0) 1684 error = sysctl(oid, oidlen, oldp, oldlenp, newp, newlen); 1685 return(error); 1686} 1687 1688