kern_sysctl.c revision 187864
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 187864 2009-01-28 19:58:05Z 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|CTLFLAG_MPSAFE, 777 0, 0, 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|CTLFLAG_MPSAFE, 800 sysctl_sysctl_oidfmt, ""); 801 802static int 803sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS) 804{ 805 struct sysctl_oid *oid; 806 int error; 807 808 error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); 809 if (error) 810 return (error); 811 812 if (!oid->oid_descr) 813 return (ENOENT); 814 error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1); 815 return (error); 816} 817 818static SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, ""); 819 820/* 821 * Default "handler" functions. 822 */ 823 824/* 825 * Handle an int, signed or unsigned. 826 * Two cases: 827 * a variable: point arg1 at it. 828 * a constant: pass it in arg2. 829 */ 830 831int 832sysctl_handle_int(SYSCTL_HANDLER_ARGS) 833{ 834 int tmpout, error = 0; 835 836 /* 837 * Attempt to get a coherent snapshot by making a copy of the data. 838 */ 839 if (arg1) 840 tmpout = *(int *)arg1; 841 else 842 tmpout = arg2; 843 error = SYSCTL_OUT(req, &tmpout, sizeof(int)); 844 845 if (error || !req->newptr) 846 return (error); 847 848 if (!arg1) 849 error = EPERM; 850 else 851 error = SYSCTL_IN(req, arg1, sizeof(int)); 852 return (error); 853} 854 855 856/* 857 * Based on on sysctl_handle_int() convert milliseconds into ticks. 858 */ 859 860int 861sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS) 862{ 863 int error, s, tt; 864 865 tt = *(int *)oidp->oid_arg1; 866 s = (int)((int64_t)tt * 1000 / hz); 867 868 error = sysctl_handle_int(oidp, &s, 0, req); 869 if (error || !req->newptr) 870 return (error); 871 872 tt = (int)((int64_t)s * hz / 1000); 873 if (tt < 1) 874 return (EINVAL); 875 876 *(int *)oidp->oid_arg1 = tt; 877 return (0); 878} 879 880 881/* 882 * Handle a long, signed or unsigned. arg1 points to it. 883 */ 884 885int 886sysctl_handle_long(SYSCTL_HANDLER_ARGS) 887{ 888 int error = 0; 889 long tmplong; 890#ifdef SCTL_MASK32 891 int tmpint; 892#endif 893 894 /* 895 * Attempt to get a coherent snapshot by making a copy of the data. 896 */ 897 if (!arg1) 898 return (EINVAL); 899 tmplong = *(long *)arg1; 900#ifdef SCTL_MASK32 901 if (req->flags & SCTL_MASK32) { 902 tmpint = tmplong; 903 error = SYSCTL_OUT(req, &tmpint, sizeof(int)); 904 } else 905#endif 906 error = SYSCTL_OUT(req, &tmplong, sizeof(long)); 907 908 if (error || !req->newptr) 909 return (error); 910 911#ifdef SCTL_MASK32 912 if (req->flags & SCTL_MASK32) { 913 error = SYSCTL_IN(req, &tmpint, sizeof(int)); 914 *(long *)arg1 = (long)tmpint; 915 } else 916#endif 917 error = SYSCTL_IN(req, arg1, sizeof(long)); 918 return (error); 919} 920 921/* 922 * Handle a 64 bit int, signed or unsigned. arg1 points to it. 923 */ 924 925int 926sysctl_handle_quad(SYSCTL_HANDLER_ARGS) 927{ 928 int error = 0; 929 uint64_t tmpout; 930 931 /* 932 * Attempt to get a coherent snapshot by making a copy of the data. 933 */ 934 if (!arg1) 935 return (EINVAL); 936 tmpout = *(uint64_t *)arg1; 937 error = SYSCTL_OUT(req, &tmpout, sizeof(uint64_t)); 938 939 if (error || !req->newptr) 940 return (error); 941 942 error = SYSCTL_IN(req, arg1, sizeof(uint64_t)); 943 return (error); 944} 945 946/* 947 * Handle our generic '\0' terminated 'C' string. 948 * Two cases: 949 * a variable string: point arg1 at it, arg2 is max length. 950 * a constant string: point arg1 at it, arg2 is zero. 951 */ 952 953int 954sysctl_handle_string(SYSCTL_HANDLER_ARGS) 955{ 956 int error=0; 957 char *tmparg; 958 size_t outlen; 959 960 /* 961 * Attempt to get a coherent snapshot by copying to a 962 * temporary kernel buffer. 963 */ 964retry: 965 outlen = strlen((char *)arg1)+1; 966 tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK); 967 968 if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) { 969 free(tmparg, M_SYSCTLTMP); 970 goto retry; 971 } 972 973 error = SYSCTL_OUT(req, tmparg, outlen); 974 free(tmparg, M_SYSCTLTMP); 975 976 if (error || !req->newptr) 977 return (error); 978 979 if ((req->newlen - req->newidx) >= arg2) { 980 error = EINVAL; 981 } else { 982 arg2 = (req->newlen - req->newidx); 983 error = SYSCTL_IN(req, arg1, arg2); 984 ((char *)arg1)[arg2] = '\0'; 985 } 986 987 return (error); 988} 989 990/* 991 * Handle any kind of opaque data. 992 * arg1 points to it, arg2 is the size. 993 */ 994 995int 996sysctl_handle_opaque(SYSCTL_HANDLER_ARGS) 997{ 998 int error, tries; 999 u_int generation; 1000 struct sysctl_req req2; 1001 1002 /* 1003 * Attempt to get a coherent snapshot, by using the thread 1004 * pre-emption counter updated from within mi_switch() to 1005 * determine if we were pre-empted during a bcopy() or 1006 * copyout(). Make 3 attempts at doing this before giving up. 1007 * If we encounter an error, stop immediately. 1008 */ 1009 tries = 0; 1010 req2 = *req; 1011retry: 1012 generation = curthread->td_generation; 1013 error = SYSCTL_OUT(req, arg1, arg2); 1014 if (error) 1015 return (error); 1016 tries++; 1017 if (generation != curthread->td_generation && tries < 3) { 1018 *req = req2; 1019 goto retry; 1020 } 1021 1022 error = SYSCTL_IN(req, arg1, arg2); 1023 1024 return (error); 1025} 1026 1027/* 1028 * Transfer functions to/from kernel space. 1029 * XXX: rather untested at this point 1030 */ 1031static int 1032sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) 1033{ 1034 size_t i = 0; 1035 1036 if (req->oldptr) { 1037 i = l; 1038 if (req->oldlen <= req->oldidx) 1039 i = 0; 1040 else 1041 if (i > req->oldlen - req->oldidx) 1042 i = req->oldlen - req->oldidx; 1043 if (i > 0) 1044 bcopy(p, (char *)req->oldptr + req->oldidx, i); 1045 } 1046 req->oldidx += l; 1047 if (req->oldptr && i != l) 1048 return (ENOMEM); 1049 return (0); 1050} 1051 1052static int 1053sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) 1054{ 1055 if (!req->newptr) 1056 return (0); 1057 if (req->newlen - req->newidx < l) 1058 return (EINVAL); 1059 bcopy((char *)req->newptr + req->newidx, p, l); 1060 req->newidx += l; 1061 return (0); 1062} 1063 1064int 1065kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old, 1066 size_t *oldlenp, void *new, size_t newlen, size_t *retval, int flags) 1067{ 1068 int error = 0; 1069 struct sysctl_req req; 1070 1071 bzero(&req, sizeof req); 1072 1073 req.td = td; 1074 req.flags = flags; 1075 1076 if (oldlenp) { 1077 req.oldlen = *oldlenp; 1078 } 1079 req.validlen = req.oldlen; 1080 1081 if (old) { 1082 req.oldptr= old; 1083 } 1084 1085 if (new != NULL) { 1086 req.newlen = newlen; 1087 req.newptr = new; 1088 } 1089 1090 req.oldfunc = sysctl_old_kernel; 1091 req.newfunc = sysctl_new_kernel; 1092 req.lock = REQ_LOCKED; 1093 1094 SYSCTL_LOCK(); 1095 error = sysctl_root(0, name, namelen, &req); 1096 SYSCTL_UNLOCK(); 1097 1098 if (req.lock == REQ_WIRED && req.validlen > 0) 1099 vsunlock(req.oldptr, req.validlen); 1100 1101 if (error && error != ENOMEM) 1102 return (error); 1103 1104 if (retval) { 1105 if (req.oldptr && req.oldidx > req.validlen) 1106 *retval = req.validlen; 1107 else 1108 *retval = req.oldidx; 1109 } 1110 return (error); 1111} 1112 1113int 1114kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp, 1115 void *new, size_t newlen, size_t *retval, int flags) 1116{ 1117 int oid[CTL_MAXNAME]; 1118 size_t oidlen, plen; 1119 int error; 1120 1121 oid[0] = 0; /* sysctl internal magic */ 1122 oid[1] = 3; /* name2oid */ 1123 oidlen = sizeof(oid); 1124 1125 /* 1126 * XXX: Prone to a possible race condition between lookup and 1127 * execution? Maybe put locking around it? 1128 */ 1129 1130 error = kernel_sysctl(td, oid, 2, oid, &oidlen, 1131 (void *)name, strlen(name), &plen, flags); 1132 if (error) 1133 return (error); 1134 1135 error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp, 1136 new, newlen, retval, flags); 1137 return (error); 1138} 1139 1140/* 1141 * Transfer function to/from user space. 1142 */ 1143static int 1144sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) 1145{ 1146 int error = 0; 1147 size_t i, len, origidx; 1148 1149 origidx = req->oldidx; 1150 req->oldidx += l; 1151 if (req->oldptr == NULL) 1152 return (0); 1153 /* 1154 * If we have not wired the user supplied buffer and we are currently 1155 * holding locks, drop a witness warning, as it's possible that 1156 * write operations to the user page can sleep. 1157 */ 1158 if (req->lock != REQ_WIRED) 1159 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 1160 "sysctl_old_user()"); 1161 i = l; 1162 len = req->validlen; 1163 if (len <= origidx) 1164 i = 0; 1165 else { 1166 if (i > len - origidx) 1167 i = len - origidx; 1168 error = copyout(p, (char *)req->oldptr + origidx, i); 1169 } 1170 if (error) 1171 return (error); 1172 if (i < l) 1173 return (ENOMEM); 1174 return (0); 1175} 1176 1177static int 1178sysctl_new_user(struct sysctl_req *req, void *p, size_t l) 1179{ 1180 int error; 1181 1182 if (!req->newptr) 1183 return (0); 1184 if (req->newlen - req->newidx < l) 1185 return (EINVAL); 1186 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 1187 "sysctl_new_user()"); 1188 error = copyin((char *)req->newptr + req->newidx, p, l); 1189 req->newidx += l; 1190 return (error); 1191} 1192 1193/* 1194 * Wire the user space destination buffer. If set to a value greater than 1195 * zero, the len parameter limits the maximum amount of wired memory. 1196 */ 1197int 1198sysctl_wire_old_buffer(struct sysctl_req *req, size_t len) 1199{ 1200 int ret; 1201 size_t i, wiredlen; 1202 char *cp, dummy; 1203 1204 wiredlen = (len > 0 && len < req->oldlen) ? len : req->oldlen; 1205 ret = 0; 1206 if (req->lock == REQ_LOCKED && req->oldptr && 1207 req->oldfunc == sysctl_old_user) { 1208 if (wiredlen != 0) { 1209 ret = vslock(req->oldptr, wiredlen); 1210 if (ret != 0) { 1211 if (ret != ENOMEM) 1212 return (ret); 1213 wiredlen = 0; 1214 } 1215 /* 1216 * Touch all the wired pages to avoid PTE modified 1217 * bit emulation traps on Alpha while holding locks 1218 * in the sysctl handler. 1219 */ 1220 for (i = (wiredlen + PAGE_SIZE - 1) / PAGE_SIZE, 1221 cp = req->oldptr; i > 0; i--, cp += PAGE_SIZE) { 1222 copyin(cp, &dummy, 1); 1223 copyout(&dummy, cp, 1); 1224 } 1225 } 1226 req->lock = REQ_WIRED; 1227 req->validlen = wiredlen; 1228 } 1229 return (0); 1230} 1231 1232int 1233sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid, 1234 int *nindx, struct sysctl_req *req) 1235{ 1236 struct sysctl_oid *oid; 1237 int indx; 1238 1239 oid = SLIST_FIRST(&sysctl__children); 1240 indx = 0; 1241 while (oid && indx < CTL_MAXNAME) { 1242 if (oid->oid_number == name[indx]) { 1243 indx++; 1244 if (oid->oid_kind & CTLFLAG_NOLOCK) 1245 req->lock = REQ_UNLOCKED; 1246 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1247 if (oid->oid_handler != NULL || 1248 indx == namelen) { 1249 *noid = oid; 1250 if (nindx != NULL) 1251 *nindx = indx; 1252 return (0); 1253 } 1254 oid = SLIST_FIRST( 1255 (struct sysctl_oid_list *)oid->oid_arg1); 1256 } else if (indx == namelen) { 1257 *noid = oid; 1258 if (nindx != NULL) 1259 *nindx = indx; 1260 return (0); 1261 } else { 1262 return (ENOTDIR); 1263 } 1264 } else { 1265 oid = SLIST_NEXT(oid, oid_link); 1266 } 1267 } 1268 return (ENOENT); 1269} 1270 1271/* 1272 * Traverse our tree, and find the right node, execute whatever it points 1273 * to, and return the resulting error code. 1274 */ 1275 1276static int 1277sysctl_root(SYSCTL_HANDLER_ARGS) 1278{ 1279 struct sysctl_oid *oid; 1280 int error, indx, lvl; 1281 1282 SYSCTL_LOCK_ASSERT(); 1283 1284 error = sysctl_find_oid(arg1, arg2, &oid, &indx, req); 1285 if (error) 1286 return (error); 1287 1288 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1289 /* 1290 * You can't call a sysctl when it's a node, but has 1291 * no handler. Inform the user that it's a node. 1292 * The indx may or may not be the same as namelen. 1293 */ 1294 if (oid->oid_handler == NULL) 1295 return (EISDIR); 1296 } 1297 1298 /* Is this sysctl writable? */ 1299 if (req->newptr && !(oid->oid_kind & CTLFLAG_WR)) 1300 return (EPERM); 1301 1302 KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL")); 1303 1304 /* Is this sysctl sensitive to securelevels? */ 1305 if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) { 1306 lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE; 1307 error = securelevel_gt(req->td->td_ucred, lvl); 1308 if (error) 1309 return (error); 1310 } 1311 1312 /* Is this sysctl writable by only privileged users? */ 1313 if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) { 1314 if (oid->oid_kind & CTLFLAG_PRISON) 1315 error = priv_check(req->td, PRIV_SYSCTL_WRITEJAIL); 1316 else 1317 error = priv_check(req->td, PRIV_SYSCTL_WRITE); 1318 if (error) 1319 return (error); 1320 } 1321 1322 if (!oid->oid_handler) 1323 return (EINVAL); 1324 1325 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { 1326 arg1 = (int *)arg1 + indx; 1327 arg2 -= indx; 1328 } else { 1329 arg1 = oid->oid_arg1; 1330 arg2 = oid->oid_arg2; 1331 } 1332#ifdef MAC 1333 error = mac_system_check_sysctl(req->td->td_ucred, oid, arg1, arg2, 1334 req); 1335 if (error != 0) 1336 return (error); 1337#endif 1338 if (!(oid->oid_kind & CTLFLAG_MPSAFE)) 1339 mtx_lock(&Giant); 1340 error = oid->oid_handler(oid, arg1, arg2, req); 1341 if (!(oid->oid_kind & CTLFLAG_MPSAFE)) 1342 mtx_unlock(&Giant); 1343 1344 return (error); 1345} 1346 1347#ifndef _SYS_SYSPROTO_H_ 1348struct sysctl_args { 1349 int *name; 1350 u_int namelen; 1351 void *old; 1352 size_t *oldlenp; 1353 void *new; 1354 size_t newlen; 1355}; 1356#endif 1357int 1358__sysctl(struct thread *td, struct sysctl_args *uap) 1359{ 1360 int error, name[CTL_MAXNAME]; 1361 size_t j; 1362 1363 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 1364 return (EINVAL); 1365 1366 error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 1367 if (error) 1368 return (error); 1369 1370 error = userland_sysctl(td, name, uap->namelen, 1371 uap->old, uap->oldlenp, 0, 1372 uap->new, uap->newlen, &j, 0); 1373 if (error && error != ENOMEM) 1374 return (error); 1375 if (uap->oldlenp) { 1376 int i = copyout(&j, uap->oldlenp, sizeof(j)); 1377 if (i) 1378 return (i); 1379 } 1380 return (error); 1381} 1382 1383/* 1384 * This is used from various compatibility syscalls too. That's why name 1385 * must be in kernel space. 1386 */ 1387int 1388userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, 1389 size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval, 1390 int flags) 1391{ 1392 int error = 0; 1393 struct sysctl_req req; 1394 1395 bzero(&req, sizeof req); 1396 1397 req.td = td; 1398 req.flags = flags; 1399 1400 if (oldlenp) { 1401 if (inkernel) { 1402 req.oldlen = *oldlenp; 1403 } else { 1404 error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); 1405 if (error) 1406 return (error); 1407 } 1408 } 1409 req.validlen = req.oldlen; 1410 1411 if (old) { 1412 if (!useracc(old, req.oldlen, VM_PROT_WRITE)) 1413 return (EFAULT); 1414 req.oldptr= old; 1415 } 1416 1417 if (new != NULL) { 1418 if (!useracc(new, newlen, VM_PROT_READ)) 1419 return (EFAULT); 1420 req.newlen = newlen; 1421 req.newptr = new; 1422 } 1423 1424 req.oldfunc = sysctl_old_user; 1425 req.newfunc = sysctl_new_user; 1426 req.lock = REQ_LOCKED; 1427 1428 SYSCTL_LOCK(); 1429 CURVNET_SET(TD_TO_VNET(curthread)); 1430 1431 for (;;) { 1432 req.oldidx = 0; 1433 req.newidx = 0; 1434 error = sysctl_root(0, name, namelen, &req); 1435 if (error != EAGAIN) 1436 break; 1437 uio_yield(); 1438 } 1439 1440 CURVNET_RESTORE(); 1441 SYSCTL_UNLOCK(); 1442 1443 if (req.lock == REQ_WIRED && req.validlen > 0) 1444 vsunlock(req.oldptr, req.validlen); 1445 1446 if (error && error != ENOMEM) 1447 return (error); 1448 1449 if (retval) { 1450 if (req.oldptr && req.oldidx > req.validlen) 1451 *retval = req.validlen; 1452 else 1453 *retval = req.oldidx; 1454 } 1455 return (error); 1456} 1457