kern_sysctl.c revision 186664
1/*- 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Mike Karels at Berkeley Software Design, Inc. 7 * 8 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD 9 * project, to make these variables more userfriendly. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 36 */ 37 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: head/sys/kern/kern_sysctl.c 186664 2009-01-01 00:19:51Z ed $"); 40 41#include "opt_compat.h" 42#include "opt_mac.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/kernel.h> 47#include <sys/sysctl.h> 48#include <sys/malloc.h> 49#include <sys/priv.h> 50#include <sys/proc.h> 51#include <sys/lock.h> 52#include <sys/mutex.h> 53#include <sys/sx.h> 54#include <sys/sysproto.h> 55#include <sys/uio.h> 56#include <sys/vimage.h> 57 58#include <security/mac/mac_framework.h> 59 60#include <vm/vm.h> 61#include <vm/vm_extern.h> 62 63static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic"); 64static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids"); 65static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer"); 66 67/* 68 * Locking - this locks the sysctl tree in memory. 69 */ 70static struct sx sysctllock; 71 72#define SYSCTL_LOCK() sx_xlock(&sysctllock) 73#define SYSCTL_UNLOCK() sx_xunlock(&sysctllock) 74#define SYSCTL_LOCK_ASSERT() sx_assert(&sysctllock, SX_XLOCKED) 75#define SYSCTL_INIT() sx_init(&sysctllock, "sysctl lock") 76 77static int sysctl_root(SYSCTL_HANDLER_ARGS); 78 79struct sysctl_oid_list sysctl__children; /* root list */ 80 81static struct sysctl_oid * 82sysctl_find_oidname(const char *name, struct sysctl_oid_list *list) 83{ 84 struct sysctl_oid *oidp; 85 86 SLIST_FOREACH(oidp, list, oid_link) { 87 if (strcmp(oidp->oid_name, name) == 0) { 88 return (oidp); 89 } 90 } 91 return (NULL); 92} 93 94/* 95 * Initialization of the MIB tree. 96 * 97 * Order by number in each list. 98 */ 99 100void 101sysctl_register_oid(struct sysctl_oid *oidp) 102{ 103 struct sysctl_oid_list *parent = oidp->oid_parent; 104 struct sysctl_oid *p; 105 struct sysctl_oid *q; 106 107 /* 108 * First check if another oid with the same name already 109 * exists in the parent's list. 110 */ 111 p = sysctl_find_oidname(oidp->oid_name, parent); 112 if (p != NULL) { 113 if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 114 p->oid_refcnt++; 115 return; 116 } else { 117 printf("can't re-use a leaf (%s)!\n", p->oid_name); 118 return; 119 } 120 } 121 /* 122 * If this oid has a number OID_AUTO, give it a number which 123 * is greater than any current oid. 124 * NOTE: DO NOT change the starting value here, change it in 125 * <sys/sysctl.h>, and make sure it is at least 256 to 126 * accomodate e.g. net.inet.raw as a static sysctl node. 127 */ 128 if (oidp->oid_number == OID_AUTO) { 129 static int newoid = CTL_AUTO_START; 130 131 oidp->oid_number = newoid++; 132 if (newoid == 0x7fffffff) 133 panic("out of oids"); 134 } 135#if 0 136 else if (oidp->oid_number >= CTL_AUTO_START) { 137 /* do not panic; this happens when unregistering sysctl sets */ 138 printf("static sysctl oid too high: %d", oidp->oid_number); 139 } 140#endif 141 142 /* 143 * Insert the oid into the parent's list in order. 144 */ 145 q = NULL; 146 SLIST_FOREACH(p, parent, oid_link) { 147 if (oidp->oid_number < p->oid_number) 148 break; 149 q = p; 150 } 151 if (q) 152 SLIST_INSERT_AFTER(q, oidp, oid_link); 153 else 154 SLIST_INSERT_HEAD(parent, oidp, oid_link); 155} 156 157void 158sysctl_unregister_oid(struct sysctl_oid *oidp) 159{ 160 struct sysctl_oid *p; 161 int error; 162 163 error = ENOENT; 164 if (oidp->oid_number == OID_AUTO) { 165 error = EINVAL; 166 } else { 167 SLIST_FOREACH(p, oidp->oid_parent, oid_link) { 168 if (p == oidp) { 169 SLIST_REMOVE(oidp->oid_parent, oidp, 170 sysctl_oid, oid_link); 171 error = 0; 172 break; 173 } 174 } 175 } 176 177 /* 178 * This can happen when a module fails to register and is 179 * being unloaded afterwards. It should not be a panic() 180 * for normal use. 181 */ 182 if (error) 183 printf("%s: failed to unregister sysctl\n", __func__); 184} 185 186/* Initialize a new context to keep track of dynamically added sysctls. */ 187int 188sysctl_ctx_init(struct sysctl_ctx_list *c) 189{ 190 191 if (c == NULL) { 192 return (EINVAL); 193 } 194 TAILQ_INIT(c); 195 return (0); 196} 197 198/* Free the context, and destroy all dynamic oids registered in this context */ 199int 200sysctl_ctx_free(struct sysctl_ctx_list *clist) 201{ 202 struct sysctl_ctx_entry *e, *e1; 203 int error; 204 205 error = 0; 206 /* 207 * First perform a "dry run" to check if it's ok to remove oids. 208 * XXX FIXME 209 * XXX This algorithm is a hack. But I don't know any 210 * XXX better solution for now... 211 */ 212 TAILQ_FOREACH(e, clist, link) { 213 error = sysctl_remove_oid(e->entry, 0, 0); 214 if (error) 215 break; 216 } 217 /* 218 * Restore deregistered entries, either from the end, 219 * or from the place where error occured. 220 * e contains the entry that was not unregistered 221 */ 222 if (error) 223 e1 = TAILQ_PREV(e, sysctl_ctx_list, link); 224 else 225 e1 = TAILQ_LAST(clist, sysctl_ctx_list); 226 while (e1 != NULL) { 227 sysctl_register_oid(e1->entry); 228 e1 = TAILQ_PREV(e1, sysctl_ctx_list, link); 229 } 230 if (error) 231 return(EBUSY); 232 /* Now really delete the entries */ 233 e = TAILQ_FIRST(clist); 234 while (e != NULL) { 235 e1 = TAILQ_NEXT(e, link); 236 error = sysctl_remove_oid(e->entry, 1, 0); 237 if (error) 238 panic("sysctl_remove_oid: corrupt tree, entry: %s", 239 e->entry->oid_name); 240 free(e, M_SYSCTLOID); 241 e = e1; 242 } 243 return (error); 244} 245 246/* Add an entry to the context */ 247struct sysctl_ctx_entry * 248sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) 249{ 250 struct sysctl_ctx_entry *e; 251 252 if (clist == NULL || oidp == NULL) 253 return(NULL); 254 e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK); 255 e->entry = oidp; 256 TAILQ_INSERT_HEAD(clist, e, link); 257 return (e); 258} 259 260/* Find an entry in the context */ 261struct sysctl_ctx_entry * 262sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) 263{ 264 struct sysctl_ctx_entry *e; 265 266 if (clist == NULL || oidp == NULL) 267 return(NULL); 268 TAILQ_FOREACH(e, clist, link) { 269 if(e->entry == oidp) 270 return(e); 271 } 272 return (e); 273} 274 275/* 276 * Delete an entry from the context. 277 * NOTE: this function doesn't free oidp! You have to remove it 278 * with sysctl_remove_oid(). 279 */ 280int 281sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) 282{ 283 struct sysctl_ctx_entry *e; 284 285 if (clist == NULL || oidp == NULL) 286 return (EINVAL); 287 e = sysctl_ctx_entry_find(clist, oidp); 288 if (e != NULL) { 289 TAILQ_REMOVE(clist, e, link); 290 free(e, M_SYSCTLOID); 291 return (0); 292 } else 293 return (ENOENT); 294} 295 296/* 297 * Remove dynamically created sysctl trees. 298 * oidp - top of the tree to be removed 299 * del - if 0 - just deregister, otherwise free up entries as well 300 * recurse - if != 0 traverse the subtree to be deleted 301 */ 302int 303sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse) 304{ 305 struct sysctl_oid *p; 306 int error; 307 308 if (oidp == NULL) 309 return(EINVAL); 310 if ((oidp->oid_kind & CTLFLAG_DYN) == 0) { 311 printf("can't remove non-dynamic nodes!\n"); 312 return (EINVAL); 313 } 314 /* 315 * WARNING: normal method to do this should be through 316 * sysctl_ctx_free(). Use recursing as the last resort 317 * method to purge your sysctl tree of leftovers... 318 * However, if some other code still references these nodes, 319 * it will panic. 320 */ 321 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 322 if (oidp->oid_refcnt == 1) { 323 SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) { 324 if (!recurse) 325 return (ENOTEMPTY); 326 error = sysctl_remove_oid(p, del, recurse); 327 if (error) 328 return (error); 329 } 330 if (del) 331 free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID); 332 } 333 } 334 if (oidp->oid_refcnt > 1 ) { 335 oidp->oid_refcnt--; 336 } else { 337 if (oidp->oid_refcnt == 0) { 338 printf("Warning: bad oid_refcnt=%u (%s)!\n", 339 oidp->oid_refcnt, oidp->oid_name); 340 return (EINVAL); 341 } 342 sysctl_unregister_oid(oidp); 343 if (del) { 344 if (oidp->oid_descr) 345 free((void *)(uintptr_t)(const void *)oidp->oid_descr, M_SYSCTLOID); 346 free((void *)(uintptr_t)(const void *)oidp->oid_name, 347 M_SYSCTLOID); 348 free(oidp, M_SYSCTLOID); 349 } 350 } 351 return (0); 352} 353 354/* 355 * Create new sysctls at run time. 356 * clist may point to a valid context initialized with sysctl_ctx_init(). 357 */ 358struct sysctl_oid * 359sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, 360 int number, const char *name, int kind, void *arg1, int arg2, 361 int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr) 362{ 363 struct sysctl_oid *oidp; 364 ssize_t len; 365 char *newname; 366 367 /* You have to hook up somewhere.. */ 368 if (parent == NULL) 369 return(NULL); 370 /* Check if the node already exists, otherwise create it */ 371 oidp = sysctl_find_oidname(name, parent); 372 if (oidp != NULL) { 373 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 374 oidp->oid_refcnt++; 375 /* Update the context */ 376 if (clist != NULL) 377 sysctl_ctx_entry_add(clist, oidp); 378 return (oidp); 379 } else { 380 printf("can't re-use a leaf (%s)!\n", name); 381 return (NULL); 382 } 383 } 384 oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO); 385 oidp->oid_parent = parent; 386 SLIST_NEXT(oidp, oid_link) = NULL; 387 oidp->oid_number = number; 388 oidp->oid_refcnt = 1; 389 len = strlen(name); 390 newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK); 391 bcopy(name, newname, len + 1); 392 newname[len] = '\0'; 393 oidp->oid_name = newname; 394 oidp->oid_handler = handler; 395 oidp->oid_kind = CTLFLAG_DYN | kind; 396 if ((kind & CTLTYPE) == CTLTYPE_NODE) { 397 /* Allocate space for children */ 398 SYSCTL_CHILDREN_SET(oidp, malloc(sizeof(struct sysctl_oid_list), 399 M_SYSCTLOID, M_WAITOK)); 400 SLIST_INIT(SYSCTL_CHILDREN(oidp)); 401 } else { 402 oidp->oid_arg1 = arg1; 403 oidp->oid_arg2 = arg2; 404 } 405 oidp->oid_fmt = fmt; 406 if (descr) { 407 int len = strlen(descr) + 1; 408 oidp->oid_descr = malloc(len, M_SYSCTLOID, M_WAITOK); 409 if (oidp->oid_descr) 410 strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr); 411 } 412 /* Update the context, if used */ 413 if (clist != NULL) 414 sysctl_ctx_entry_add(clist, oidp); 415 /* Register this oid */ 416 sysctl_register_oid(oidp); 417 return (oidp); 418} 419 420/* 421 * Rename an existing oid. 422 */ 423void 424sysctl_rename_oid(struct sysctl_oid *oidp, const char *name) 425{ 426 ssize_t len; 427 char *newname; 428 void *oldname; 429 430 oldname = (void *)(uintptr_t)(const void *)oidp->oid_name; 431 len = strlen(name); 432 newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK); 433 bcopy(name, newname, len + 1); 434 newname[len] = '\0'; 435 oidp->oid_name = newname; 436 free(oldname, M_SYSCTLOID); 437} 438 439/* 440 * Reparent an existing oid. 441 */ 442int 443sysctl_move_oid(struct sysctl_oid *oid, struct sysctl_oid_list *parent) 444{ 445 struct sysctl_oid *oidp; 446 447 if (oid->oid_parent == parent) 448 return (0); 449 oidp = sysctl_find_oidname(oid->oid_name, parent); 450 if (oidp != NULL) 451 return (EEXIST); 452 sysctl_unregister_oid(oid); 453 oid->oid_parent = parent; 454 oid->oid_number = OID_AUTO; 455 sysctl_register_oid(oid); 456 return (0); 457} 458 459/* 460 * Register the kernel's oids on startup. 461 */ 462SET_DECLARE(sysctl_set, struct sysctl_oid); 463 464static void 465sysctl_register_all(void *arg) 466{ 467 struct sysctl_oid **oidp; 468 469 SYSCTL_INIT(); 470 SET_FOREACH(oidp, sysctl_set) 471 sysctl_register_oid(*oidp); 472} 473SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0); 474 475/* 476 * "Staff-functions" 477 * 478 * These functions implement a presently undocumented interface 479 * used by the sysctl program to walk the tree, and get the type 480 * so it can print the value. 481 * This interface is under work and consideration, and should probably 482 * be killed with a big axe by the first person who can find the time. 483 * (be aware though, that the proper interface isn't as obvious as it 484 * may seem, there are various conflicting requirements. 485 * 486 * {0,0} printf the entire MIB-tree. 487 * {0,1,...} return the name of the "..." OID. 488 * {0,2,...} return the next OID. 489 * {0,3} return the OID of the name in "new" 490 * {0,4,...} return the kind & format info for the "..." OID. 491 * {0,5,...} return the description the "..." OID. 492 */ 493 494#ifdef SYSCTL_DEBUG 495static void 496sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i) 497{ 498 int k; 499 struct sysctl_oid *oidp; 500 501 SLIST_FOREACH(oidp, l, oid_link) { 502 503 for (k=0; k<i; k++) 504 printf(" "); 505 506 printf("%d %s ", oidp->oid_number, oidp->oid_name); 507 508 printf("%c%c", 509 oidp->oid_kind & CTLFLAG_RD ? 'R':' ', 510 oidp->oid_kind & CTLFLAG_WR ? 'W':' '); 511 512 if (oidp->oid_handler) 513 printf(" *Handler"); 514 515 switch (oidp->oid_kind & CTLTYPE) { 516 case CTLTYPE_NODE: 517 printf(" Node\n"); 518 if (!oidp->oid_handler) { 519 sysctl_sysctl_debug_dump_node( 520 oidp->oid_arg1, i+2); 521 } 522 break; 523 case CTLTYPE_INT: printf(" Int\n"); break; 524 case CTLTYPE_STRING: printf(" String\n"); break; 525 case CTLTYPE_QUAD: printf(" Quad\n"); break; 526 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; 527 default: printf("\n"); 528 } 529 530 } 531} 532 533static int 534sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS) 535{ 536 int error; 537 538 error = priv_check(req->td, PRIV_SYSCTL_DEBUG); 539 if (error) 540 return (error); 541 sysctl_sysctl_debug_dump_node(&sysctl__children, 0); 542 return (ENOENT); 543} 544 545SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, 546 0, 0, sysctl_sysctl_debug, "-", ""); 547#endif 548 549static int 550sysctl_sysctl_name(SYSCTL_HANDLER_ARGS) 551{ 552 int *name = (int *) arg1; 553 u_int namelen = arg2; 554 int error = 0; 555 struct sysctl_oid *oid; 556 struct sysctl_oid_list *lsp = &sysctl__children, *lsp2; 557 char buf[10]; 558 559 while (namelen) { 560 if (!lsp) { 561 snprintf(buf,sizeof(buf),"%d",*name); 562 if (req->oldidx) 563 error = SYSCTL_OUT(req, ".", 1); 564 if (!error) 565 error = SYSCTL_OUT(req, buf, strlen(buf)); 566 if (error) 567 return (error); 568 namelen--; 569 name++; 570 continue; 571 } 572 lsp2 = 0; 573 SLIST_FOREACH(oid, lsp, oid_link) { 574 if (oid->oid_number != *name) 575 continue; 576 577 if (req->oldidx) 578 error = SYSCTL_OUT(req, ".", 1); 579 if (!error) 580 error = SYSCTL_OUT(req, oid->oid_name, 581 strlen(oid->oid_name)); 582 if (error) 583 return (error); 584 585 namelen--; 586 name++; 587 588 if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) 589 break; 590 591 if (oid->oid_handler) 592 break; 593 594 lsp2 = (struct sysctl_oid_list *)oid->oid_arg1; 595 break; 596 } 597 lsp = lsp2; 598 } 599 return (SYSCTL_OUT(req, "", 1)); 600} 601 602static SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); 603 604static int 605sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, 606 int *next, int *len, int level, struct sysctl_oid **oidpp) 607{ 608 struct sysctl_oid *oidp; 609 610 *len = level; 611 SLIST_FOREACH(oidp, lsp, oid_link) { 612 *next = oidp->oid_number; 613 *oidpp = oidp; 614 615 if (oidp->oid_kind & CTLFLAG_SKIP) 616 continue; 617 618 if (!namelen) { 619 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 620 return (0); 621 if (oidp->oid_handler) 622 /* We really should call the handler here...*/ 623 return (0); 624 lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 625 if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, 626 len, level+1, oidpp)) 627 return (0); 628 goto emptynode; 629 } 630 631 if (oidp->oid_number < *name) 632 continue; 633 634 if (oidp->oid_number > *name) { 635 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 636 return (0); 637 if (oidp->oid_handler) 638 return (0); 639 lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 640 if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, 641 next+1, len, level+1, oidpp)) 642 return (0); 643 goto next; 644 } 645 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 646 continue; 647 648 if (oidp->oid_handler) 649 continue; 650 651 lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 652 if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, 653 len, level+1, oidpp)) 654 return (0); 655 next: 656 namelen = 1; 657 emptynode: 658 *len = level; 659 } 660 return (1); 661} 662 663static int 664sysctl_sysctl_next(SYSCTL_HANDLER_ARGS) 665{ 666 int *name = (int *) arg1; 667 u_int namelen = arg2; 668 int i, j, error; 669 struct sysctl_oid *oid; 670 struct sysctl_oid_list *lsp = &sysctl__children; 671 int newoid[CTL_MAXNAME]; 672 673 i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid); 674 if (i) 675 return (ENOENT); 676 error = SYSCTL_OUT(req, newoid, j * sizeof (int)); 677 return (error); 678} 679 680static SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, ""); 681 682static int 683name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp) 684{ 685 int i; 686 struct sysctl_oid *oidp; 687 struct sysctl_oid_list *lsp = &sysctl__children; 688 char *p; 689 690 SYSCTL_LOCK_ASSERT(); 691 692 if (!*name) 693 return (ENOENT); 694 695 p = name + strlen(name) - 1 ; 696 if (*p == '.') 697 *p = '\0'; 698 699 *len = 0; 700 701 for (p = name; *p && *p != '.'; p++) 702 ; 703 i = *p; 704 if (i == '.') 705 *p = '\0'; 706 707 oidp = SLIST_FIRST(lsp); 708 709 while (oidp && *len < CTL_MAXNAME) { 710 if (strcmp(name, oidp->oid_name)) { 711 oidp = SLIST_NEXT(oidp, oid_link); 712 continue; 713 } 714 *oid++ = oidp->oid_number; 715 (*len)++; 716 717 if (!i) { 718 if (oidpp) 719 *oidpp = oidp; 720 return (0); 721 } 722 723 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) 724 break; 725 726 if (oidp->oid_handler) 727 break; 728 729 lsp = (struct sysctl_oid_list *)oidp->oid_arg1; 730 oidp = SLIST_FIRST(lsp); 731 name = p+1; 732 for (p = name; *p && *p != '.'; p++) 733 ; 734 i = *p; 735 if (i == '.') 736 *p = '\0'; 737 } 738 return (ENOENT); 739} 740 741static int 742sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS) 743{ 744 char *p; 745 int error, oid[CTL_MAXNAME], len; 746 struct sysctl_oid *op = 0; 747 748 SYSCTL_LOCK_ASSERT(); 749 750 if (!req->newlen) 751 return (ENOENT); 752 if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */ 753 return (ENAMETOOLONG); 754 755 p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK); 756 757 error = SYSCTL_IN(req, p, req->newlen); 758 if (error) { 759 free(p, M_SYSCTL); 760 return (error); 761 } 762 763 p [req->newlen] = '\0'; 764 765 error = name2oid(p, oid, &len, &op); 766 767 free(p, M_SYSCTL); 768 769 if (error) 770 return (error); 771 772 error = SYSCTL_OUT(req, oid, len * sizeof *oid); 773 return (error); 774} 775 776SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, 777 sysctl_sysctl_name2oid, "I", ""); 778 779static int 780sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS) 781{ 782 struct sysctl_oid *oid; 783 int error; 784 785 error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); 786 if (error) 787 return (error); 788 789 if (!oid->oid_fmt) 790 return (ENOENT); 791 error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind)); 792 if (error) 793 return (error); 794 error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1); 795 return (error); 796} 797 798 799static SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, ""); 800 801static int 802sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS) 803{ 804 struct sysctl_oid *oid; 805 int error; 806 807 error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); 808 if (error) 809 return (error); 810 811 if (!oid->oid_descr) 812 return (ENOENT); 813 error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1); 814 return (error); 815} 816 817static SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, ""); 818 819/* 820 * Default "handler" functions. 821 */ 822 823/* 824 * Handle an int, signed or unsigned. 825 * Two cases: 826 * a variable: point arg1 at it. 827 * a constant: pass it in arg2. 828 */ 829 830int 831sysctl_handle_int(SYSCTL_HANDLER_ARGS) 832{ 833 int tmpout, error = 0; 834 835 /* 836 * Attempt to get a coherent snapshot by making a copy of the data. 837 */ 838 if (arg1) 839 tmpout = *(int *)arg1; 840 else 841 tmpout = arg2; 842 error = SYSCTL_OUT(req, &tmpout, sizeof(int)); 843 844 if (error || !req->newptr) 845 return (error); 846 847 if (!arg1) 848 error = EPERM; 849 else 850 error = SYSCTL_IN(req, arg1, sizeof(int)); 851 return (error); 852} 853 854 855/* 856 * Based on on sysctl_handle_int() convert milliseconds into ticks. 857 */ 858 859int 860sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS) 861{ 862 int error, s, tt; 863 864 tt = *(int *)oidp->oid_arg1; 865 s = (int)((int64_t)tt * 1000 / hz); 866 867 error = sysctl_handle_int(oidp, &s, 0, req); 868 if (error || !req->newptr) 869 return (error); 870 871 tt = (int)((int64_t)s * hz / 1000); 872 if (tt < 1) 873 return (EINVAL); 874 875 *(int *)oidp->oid_arg1 = tt; 876 return (0); 877} 878 879 880/* 881 * Handle a long, signed or unsigned. arg1 points to it. 882 */ 883 884int 885sysctl_handle_long(SYSCTL_HANDLER_ARGS) 886{ 887 int error = 0; 888 long tmplong; 889#ifdef SCTL_MASK32 890 int tmpint; 891#endif 892 893 /* 894 * Attempt to get a coherent snapshot by making a copy of the data. 895 */ 896 if (!arg1) 897 return (EINVAL); 898 tmplong = *(long *)arg1; 899#ifdef SCTL_MASK32 900 if (req->flags & SCTL_MASK32) { 901 tmpint = tmplong; 902 error = SYSCTL_OUT(req, &tmpint, sizeof(int)); 903 } else 904#endif 905 error = SYSCTL_OUT(req, &tmplong, sizeof(long)); 906 907 if (error || !req->newptr) 908 return (error); 909 910#ifdef SCTL_MASK32 911 if (req->flags & SCTL_MASK32) { 912 error = SYSCTL_IN(req, &tmpint, sizeof(int)); 913 *(long *)arg1 = (long)tmpint; 914 } else 915#endif 916 error = SYSCTL_IN(req, arg1, sizeof(long)); 917 return (error); 918} 919 920/* 921 * Handle a 64 bit int, signed or unsigned. arg1 points to it. 922 */ 923 924int 925sysctl_handle_quad(SYSCTL_HANDLER_ARGS) 926{ 927 int error = 0; 928 uint64_t tmpout; 929 930 /* 931 * Attempt to get a coherent snapshot by making a copy of the data. 932 */ 933 if (!arg1) 934 return (EINVAL); 935 tmpout = *(uint64_t *)arg1; 936 error = SYSCTL_OUT(req, &tmpout, sizeof(uint64_t)); 937 938 if (error || !req->newptr) 939 return (error); 940 941 error = SYSCTL_IN(req, arg1, sizeof(uint64_t)); 942 return (error); 943} 944 945/* 946 * Handle our generic '\0' terminated 'C' string. 947 * Two cases: 948 * a variable string: point arg1 at it, arg2 is max length. 949 * a constant string: point arg1 at it, arg2 is zero. 950 */ 951 952int 953sysctl_handle_string(SYSCTL_HANDLER_ARGS) 954{ 955 int error=0; 956 char *tmparg; 957 size_t outlen; 958 959 /* 960 * Attempt to get a coherent snapshot by copying to a 961 * temporary kernel buffer. 962 */ 963retry: 964 outlen = strlen((char *)arg1)+1; 965 tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK); 966 967 if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) { 968 free(tmparg, M_SYSCTLTMP); 969 goto retry; 970 } 971 972 error = SYSCTL_OUT(req, tmparg, outlen); 973 free(tmparg, M_SYSCTLTMP); 974 975 if (error || !req->newptr) 976 return (error); 977 978 if ((req->newlen - req->newidx) >= arg2) { 979 error = EINVAL; 980 } else { 981 arg2 = (req->newlen - req->newidx); 982 error = SYSCTL_IN(req, arg1, arg2); 983 ((char *)arg1)[arg2] = '\0'; 984 } 985 986 return (error); 987} 988 989/* 990 * Handle any kind of opaque data. 991 * arg1 points to it, arg2 is the size. 992 */ 993 994int 995sysctl_handle_opaque(SYSCTL_HANDLER_ARGS) 996{ 997 int error, tries; 998 u_int generation; 999 struct sysctl_req req2; 1000 1001 /* 1002 * Attempt to get a coherent snapshot, by using the thread 1003 * pre-emption counter updated from within mi_switch() to 1004 * determine if we were pre-empted during a bcopy() or 1005 * copyout(). Make 3 attempts at doing this before giving up. 1006 * If we encounter an error, stop immediately. 1007 */ 1008 tries = 0; 1009 req2 = *req; 1010retry: 1011 generation = curthread->td_generation; 1012 error = SYSCTL_OUT(req, arg1, arg2); 1013 if (error) 1014 return (error); 1015 tries++; 1016 if (generation != curthread->td_generation && tries < 3) { 1017 *req = req2; 1018 goto retry; 1019 } 1020 1021 error = SYSCTL_IN(req, arg1, arg2); 1022 1023 return (error); 1024} 1025 1026/* 1027 * Transfer functions to/from kernel space. 1028 * XXX: rather untested at this point 1029 */ 1030static int 1031sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) 1032{ 1033 size_t i = 0; 1034 1035 if (req->oldptr) { 1036 i = l; 1037 if (req->oldlen <= req->oldidx) 1038 i = 0; 1039 else 1040 if (i > req->oldlen - req->oldidx) 1041 i = req->oldlen - req->oldidx; 1042 if (i > 0) 1043 bcopy(p, (char *)req->oldptr + req->oldidx, i); 1044 } 1045 req->oldidx += l; 1046 if (req->oldptr && i != l) 1047 return (ENOMEM); 1048 return (0); 1049} 1050 1051static int 1052sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) 1053{ 1054 if (!req->newptr) 1055 return (0); 1056 if (req->newlen - req->newidx < l) 1057 return (EINVAL); 1058 bcopy((char *)req->newptr + req->newidx, p, l); 1059 req->newidx += l; 1060 return (0); 1061} 1062 1063int 1064kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old, 1065 size_t *oldlenp, void *new, size_t newlen, size_t *retval, int flags) 1066{ 1067 int error = 0; 1068 struct sysctl_req req; 1069 1070 bzero(&req, sizeof req); 1071 1072 req.td = td; 1073 req.flags = flags; 1074 1075 if (oldlenp) { 1076 req.oldlen = *oldlenp; 1077 } 1078 req.validlen = req.oldlen; 1079 1080 if (old) { 1081 req.oldptr= old; 1082 } 1083 1084 if (new != NULL) { 1085 req.newlen = newlen; 1086 req.newptr = new; 1087 } 1088 1089 req.oldfunc = sysctl_old_kernel; 1090 req.newfunc = sysctl_new_kernel; 1091 req.lock = REQ_LOCKED; 1092 1093 SYSCTL_LOCK(); 1094 error = sysctl_root(0, name, namelen, &req); 1095 SYSCTL_UNLOCK(); 1096 1097 if (req.lock == REQ_WIRED && req.validlen > 0) 1098 vsunlock(req.oldptr, req.validlen); 1099 1100 if (error && error != ENOMEM) 1101 return (error); 1102 1103 if (retval) { 1104 if (req.oldptr && req.oldidx > req.validlen) 1105 *retval = req.validlen; 1106 else 1107 *retval = req.oldidx; 1108 } 1109 return (error); 1110} 1111 1112int 1113kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp, 1114 void *new, size_t newlen, size_t *retval, int flags) 1115{ 1116 int oid[CTL_MAXNAME]; 1117 size_t oidlen, plen; 1118 int error; 1119 1120 oid[0] = 0; /* sysctl internal magic */ 1121 oid[1] = 3; /* name2oid */ 1122 oidlen = sizeof(oid); 1123 1124 /* 1125 * XXX: Prone to a possible race condition between lookup and 1126 * execution? Maybe put locking around it? 1127 */ 1128 1129 error = kernel_sysctl(td, oid, 2, oid, &oidlen, 1130 (void *)name, strlen(name), &plen, flags); 1131 if (error) 1132 return (error); 1133 1134 error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp, 1135 new, newlen, retval, flags); 1136 return (error); 1137} 1138 1139/* 1140 * Transfer function to/from user space. 1141 */ 1142static int 1143sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) 1144{ 1145 int error = 0; 1146 size_t i, len, origidx; 1147 1148 origidx = req->oldidx; 1149 req->oldidx += l; 1150 if (req->oldptr == NULL) 1151 return (0); 1152 /* 1153 * If we have not wired the user supplied buffer and we are currently 1154 * holding locks, drop a witness warning, as it's possible that 1155 * write operations to the user page can sleep. 1156 */ 1157 if (req->lock != REQ_WIRED) 1158 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 1159 "sysctl_old_user()"); 1160 i = l; 1161 len = req->validlen; 1162 if (len <= origidx) 1163 i = 0; 1164 else { 1165 if (i > len - origidx) 1166 i = len - origidx; 1167 error = copyout(p, (char *)req->oldptr + origidx, i); 1168 } 1169 if (error) 1170 return (error); 1171 if (i < l) 1172 return (ENOMEM); 1173 return (0); 1174} 1175 1176static int 1177sysctl_new_user(struct sysctl_req *req, void *p, size_t l) 1178{ 1179 int error; 1180 1181 if (!req->newptr) 1182 return (0); 1183 if (req->newlen - req->newidx < l) 1184 return (EINVAL); 1185 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 1186 "sysctl_new_user()"); 1187 error = copyin((char *)req->newptr + req->newidx, p, l); 1188 req->newidx += l; 1189 return (error); 1190} 1191 1192/* 1193 * Wire the user space destination buffer. If set to a value greater than 1194 * zero, the len parameter limits the maximum amount of wired memory. 1195 */ 1196int 1197sysctl_wire_old_buffer(struct sysctl_req *req, size_t len) 1198{ 1199 int ret; 1200 size_t i, wiredlen; 1201 char *cp, dummy; 1202 1203 wiredlen = (len > 0 && len < req->oldlen) ? len : req->oldlen; 1204 ret = 0; 1205 if (req->lock == REQ_LOCKED && req->oldptr && 1206 req->oldfunc == sysctl_old_user) { 1207 if (wiredlen != 0) { 1208 ret = vslock(req->oldptr, wiredlen); 1209 if (ret != 0) { 1210 if (ret != ENOMEM) 1211 return (ret); 1212 wiredlen = 0; 1213 } 1214 /* 1215 * Touch all the wired pages to avoid PTE modified 1216 * bit emulation traps on Alpha while holding locks 1217 * in the sysctl handler. 1218 */ 1219 for (i = (wiredlen + PAGE_SIZE - 1) / PAGE_SIZE, 1220 cp = req->oldptr; i > 0; i--, cp += PAGE_SIZE) { 1221 copyin(cp, &dummy, 1); 1222 copyout(&dummy, cp, 1); 1223 } 1224 } 1225 req->lock = REQ_WIRED; 1226 req->validlen = wiredlen; 1227 } 1228 return (0); 1229} 1230 1231int 1232sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid, 1233 int *nindx, struct sysctl_req *req) 1234{ 1235 struct sysctl_oid *oid; 1236 int indx; 1237 1238 oid = SLIST_FIRST(&sysctl__children); 1239 indx = 0; 1240 while (oid && indx < CTL_MAXNAME) { 1241 if (oid->oid_number == name[indx]) { 1242 indx++; 1243 if (oid->oid_kind & CTLFLAG_NOLOCK) 1244 req->lock = REQ_UNLOCKED; 1245 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1246 if (oid->oid_handler != NULL || 1247 indx == namelen) { 1248 *noid = oid; 1249 if (nindx != NULL) 1250 *nindx = indx; 1251 return (0); 1252 } 1253 oid = SLIST_FIRST( 1254 (struct sysctl_oid_list *)oid->oid_arg1); 1255 } else if (indx == namelen) { 1256 *noid = oid; 1257 if (nindx != NULL) 1258 *nindx = indx; 1259 return (0); 1260 } else { 1261 return (ENOTDIR); 1262 } 1263 } else { 1264 oid = SLIST_NEXT(oid, oid_link); 1265 } 1266 } 1267 return (ENOENT); 1268} 1269 1270/* 1271 * Traverse our tree, and find the right node, execute whatever it points 1272 * to, and return the resulting error code. 1273 */ 1274 1275static int 1276sysctl_root(SYSCTL_HANDLER_ARGS) 1277{ 1278 struct sysctl_oid *oid; 1279 int error, indx, lvl; 1280 1281 SYSCTL_LOCK_ASSERT(); 1282 1283 error = sysctl_find_oid(arg1, arg2, &oid, &indx, req); 1284 if (error) 1285 return (error); 1286 1287 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1288 /* 1289 * You can't call a sysctl when it's a node, but has 1290 * no handler. Inform the user that it's a node. 1291 * The indx may or may not be the same as namelen. 1292 */ 1293 if (oid->oid_handler == NULL) 1294 return (EISDIR); 1295 } 1296 1297 /* Is this sysctl writable? */ 1298 if (req->newptr && !(oid->oid_kind & CTLFLAG_WR)) 1299 return (EPERM); 1300 1301 KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL")); 1302 1303 /* Is this sysctl sensitive to securelevels? */ 1304 if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) { 1305 lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE; 1306 error = securelevel_gt(req->td->td_ucred, lvl); 1307 if (error) 1308 return (error); 1309 } 1310 1311 /* Is this sysctl writable by only privileged users? */ 1312 if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) { 1313 if (oid->oid_kind & CTLFLAG_PRISON) 1314 error = priv_check(req->td, PRIV_SYSCTL_WRITEJAIL); 1315 else 1316 error = priv_check(req->td, PRIV_SYSCTL_WRITE); 1317 if (error) 1318 return (error); 1319 } 1320 1321 if (!oid->oid_handler) 1322 return (EINVAL); 1323 1324 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1325 arg1 = (int *)arg1 + indx; 1326 arg2 -= indx; 1327 } else { 1328 arg1 = oid->oid_arg1; 1329 arg2 = oid->oid_arg2; 1330 } 1331#ifdef MAC 1332 error = mac_system_check_sysctl(req->td->td_ucred, oid, arg1, arg2, 1333 req); 1334 if (error != 0) 1335 return (error); 1336#endif 1337 1338 /* XXX: Handlers are not guaranteed to be Giant safe! */ 1339 mtx_lock(&Giant); 1340 error = oid->oid_handler(oid, arg1, arg2, req); 1341 mtx_unlock(&Giant); 1342 1343 return (error); 1344} 1345 1346#ifndef _SYS_SYSPROTO_H_ 1347struct sysctl_args { 1348 int *name; 1349 u_int namelen; 1350 void *old; 1351 size_t *oldlenp; 1352 void *new; 1353 size_t newlen; 1354}; 1355#endif 1356int 1357__sysctl(struct thread *td, struct sysctl_args *uap) 1358{ 1359 int error, name[CTL_MAXNAME]; 1360 size_t j; 1361 1362 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 1363 return (EINVAL); 1364 1365 error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 1366 if (error) 1367 return (error); 1368 1369 error = userland_sysctl(td, name, uap->namelen, 1370 uap->old, uap->oldlenp, 0, 1371 uap->new, uap->newlen, &j, 0); 1372 if (error && error != ENOMEM) 1373 return (error); 1374 if (uap->oldlenp) { 1375 int i = copyout(&j, uap->oldlenp, sizeof(j)); 1376 if (i) 1377 return (i); 1378 } 1379 return (error); 1380} 1381 1382/* 1383 * This is used from various compatibility syscalls too. That's why name 1384 * must be in kernel space. 1385 */ 1386int 1387userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, 1388 size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval, 1389 int flags) 1390{ 1391 int error = 0; 1392 struct sysctl_req req; 1393 1394 bzero(&req, sizeof req); 1395 1396 req.td = td; 1397 req.flags = flags; 1398 1399 if (oldlenp) { 1400 if (inkernel) { 1401 req.oldlen = *oldlenp; 1402 } else { 1403 error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); 1404 if (error) 1405 return (error); 1406 } 1407 } 1408 req.validlen = req.oldlen; 1409 1410 if (old) { 1411 if (!useracc(old, req.oldlen, VM_PROT_WRITE)) 1412 return (EFAULT); 1413 req.oldptr= old; 1414 } 1415 1416 if (new != NULL) { 1417 if (!useracc(new, newlen, VM_PROT_READ)) 1418 return (EFAULT); 1419 req.newlen = newlen; 1420 req.newptr = new; 1421 } 1422 1423 req.oldfunc = sysctl_old_user; 1424 req.newfunc = sysctl_new_user; 1425 req.lock = REQ_LOCKED; 1426 1427 SYSCTL_LOCK(); 1428 CURVNET_SET(TD_TO_VNET(curthread)); 1429 1430 for (;;) { 1431 req.oldidx = 0; 1432 req.newidx = 0; 1433 error = sysctl_root(0, name, namelen, &req); 1434 if (error != EAGAIN) 1435 break; 1436 uio_yield(); 1437 } 1438 1439 CURVNET_RESTORE(); 1440 SYSCTL_UNLOCK(); 1441 1442 if (req.lock == REQ_WIRED && req.validlen > 0) 1443 vsunlock(req.oldptr, req.validlen); 1444 1445 if (error && error != ENOMEM) 1446 return (error); 1447 1448 if (retval) { 1449 if (req.oldptr && req.oldidx > req.validlen) 1450 *retval = req.validlen; 1451 else 1452 *retval = req.oldidx; 1453 } 1454 return (error); 1455} 1456