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