2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1982, 1986, 1989, 1993
30 * The Regents of the University of California. All rights reserved.
32 * This code is derived from software contributed to Berkeley by
33 * Mike Karels at Berkeley Software Design, Inc.
35 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
36 * project, to make these variables more userfriendly.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
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.
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
66 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
70 #include <sys/param.h>
72 #include <sys/kernel.h>
73 #include <sys/sysctl.h>
74 #include <sys/malloc.h>
75 #include <sys/proc_internal.h>
76 #include <sys/kauth.h>
77 #include <sys/systm.h>
78 #include <sys/sysproto.h>
80 #include <security/audit/audit.h>
81 #include <pexpert/pexpert.h>
84 #include <security/mac_framework.h>
87 #if defined(HAS_APPLE_PAC)
89 #endif /* defined(HAS_APPLE_PAC) */
91 lck_grp_t
* sysctl_lock_group
= NULL
;
92 lck_rw_t
* sysctl_geometry_lock
= NULL
;
93 lck_mtx_t
* sysctl_unlocked_node_lock
= NULL
;
96 * Conditionally allow dtrace to see these functions for debugging purposes.
104 #define STATIC static
107 /* forward declarations of static functions */
108 STATIC
void sysctl_sysctl_debug_dump_node(struct sysctl_oid_list
*l
, int i
);
109 STATIC
int sysctl_sysctl_debug(struct sysctl_oid
*oidp
, void *arg1
,
110 int arg2
, struct sysctl_req
*req
);
111 STATIC
int sysctl_sysctl_name(struct sysctl_oid
*oidp
, void *arg1
,
112 int arg2
, struct sysctl_req
*req
);
113 STATIC
int sysctl_sysctl_next_ls(struct sysctl_oid_list
*lsp
,
114 int *name
, u_int namelen
, int *next
, int *len
, int level
,
115 struct sysctl_oid
**oidpp
);
116 STATIC
int sysctl_old_kernel(struct sysctl_req
*req
, const void *p
, size_t l
);
117 STATIC
int sysctl_new_kernel(struct sysctl_req
*req
, void *p
, size_t l
);
118 STATIC
int name2oid(char *name
, int *oid
, u_int
*len
);
119 STATIC
int sysctl_sysctl_name2oid(struct sysctl_oid
*oidp
, void *arg1
, int arg2
, struct sysctl_req
*req
);
120 STATIC
int sysctl_sysctl_next(struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
121 struct sysctl_req
*req
);
122 STATIC
int sysctl_sysctl_oidfmt(struct sysctl_oid
*oidp
, void *arg1
, int arg2
, struct sysctl_req
*req
);
123 STATIC
int sysctl_old_user(struct sysctl_req
*req
, const void *p
, size_t l
);
124 STATIC
int sysctl_new_user(struct sysctl_req
*req
, void *p
, size_t l
);
126 STATIC
void sysctl_create_user_req(struct sysctl_req
*req
, struct proc
*p
, user_addr_t oldp
,
127 size_t oldlen
, user_addr_t newp
, size_t newlen
);
128 STATIC
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
);
130 int kernel_sysctl(struct proc
*p
, int *name
, u_int namelen
, void *old
, size_t *oldlenp
, void *new, size_t newlen
);
131 int kernel_sysctlbyname(const char *name
, void *oldp
, size_t *oldlenp
, void *newp
, size_t newlen
);
132 int userland_sysctl(boolean_t string_is_canonical
,
133 char *namestring
, size_t namestringlen
,
134 int *name
, u_int namelen
, struct sysctl_req
*req
,
137 struct sysctl_oid_list sysctl__children
; /* root list */
140 * Initialization of the MIB tree.
142 * Order by number in each list.
146 sysctl_register_oid(struct sysctl_oid
*new_oidp
)
148 struct sysctl_oid
*oidp
= NULL
;
149 struct sysctl_oid_list
*parent
= new_oidp
->oid_parent
;
150 struct sysctl_oid
*p
;
151 struct sysctl_oid
*q
;
155 * The OID can be old-style (needs copy), new style without an earlier
156 * version (also needs copy), or new style with a matching version (no
157 * copy needed). Later versions are rejected (presumably, the OID
158 * structure was changed for a necessary reason).
160 if (!(new_oidp
->oid_kind
& CTLFLAG_OID2
)) {
162 * XXX: M_TEMP is perhaps not the most apropriate zone, as it
163 * XXX: will subject us to use-after-free by other consumers.
165 MALLOC(oidp
, struct sysctl_oid
*, sizeof(*oidp
), M_TEMP
, M_WAITOK
| M_ZERO
);
167 return; /* reject: no memory */
170 * Copy the structure only through the oid_fmt field, which
171 * is the last field in a non-OID2 OID structure.
173 * Note: We may want to set the oid_descr to the
174 * oid_name (or "") at some future date.
176 memcpy(oidp
, new_oidp
, offsetof(struct sysctl_oid
, oid_descr
));
178 /* It's a later version; handle the versions we know about */
179 switch (new_oidp
->oid_version
) {
180 case SYSCTL_OID_VERSION
:
181 /* current version */
185 return; /* rejects unknown version */
189 /* Get the write lock to modify the geometry */
190 lck_rw_lock_exclusive(sysctl_geometry_lock
);
193 * If this oid has a number OID_AUTO, give it a number which
194 * is greater than any current oid. Make sure it is at least
195 * OID_AUTO_START to leave space for pre-assigned oid numbers.
197 if (oidp
->oid_number
== OID_AUTO
) {
198 /* First, find the highest oid in the parent list >OID_AUTO_START-1 */
200 SLIST_FOREACH(p
, parent
, oid_link
) {
201 if (p
->oid_number
> n
) {
205 oidp
->oid_number
= n
+ 1;
207 * Reflect the number in an llocated OID into the template
208 * of the caller for sysctl_unregister_oid() compares.
210 if (oidp
!= new_oidp
) {
211 new_oidp
->oid_number
= oidp
->oid_number
;
215 #if defined(HAS_APPLE_PAC)
216 if (oidp
->oid_handler
) {
218 * Dereference function-pointer-signed oid_handler to prevent an
219 * attacker with the ability to observe the result of the
220 * auth_and_resign below from trying all possible inputs until an auth
223 if (__builtin_expect(!*(uintptr_t*)ptrauth_auth_data((void*)
224 oidp
->oid_handler
, ptrauth_key_function_pointer
, 0), 0)) {
226 * This is necessary to force the dereference but will never
227 * actually be reached, dereferencing an invalidly signed pointer
228 * will trap before getting here (and the codegen is nicer than
234 * Sign oid_handler address-discriminated upon installation to make it
235 * harder to replace with an arbitrary function pointer.
237 oidp
->oid_handler
= ptrauth_auth_and_resign(oidp
->oid_handler
,
238 ptrauth_key_function_pointer
, 0, ptrauth_key_function_pointer
,
239 ptrauth_blend_discriminator(&oidp
->oid_handler
,
240 ptrauth_string_discriminator("oid_handler")));
242 #endif /* defined(HAS_APPLE_PAC) */
245 * Insert the oid into the parent's list in order.
248 SLIST_FOREACH(p
, parent
, oid_link
) {
249 if (oidp
->oid_number
== p
->oid_number
) {
250 panic("attempting to register a sysctl at previously registered slot : %d", oidp
->oid_number
);
251 } else if (oidp
->oid_number
< p
->oid_number
) {
257 SLIST_INSERT_AFTER(q
, oidp
, oid_link
);
259 SLIST_INSERT_HEAD(parent
, oidp
, oid_link
);
262 /* Release the write lock */
263 lck_rw_unlock_exclusive(sysctl_geometry_lock
);
267 sysctl_unregister_oid(struct sysctl_oid
*oidp
)
269 struct sysctl_oid
*removed_oidp
= NULL
; /* OID removed from tree */
270 struct sysctl_oid
*old_oidp
= NULL
; /* OID compatibility copy */
272 /* Get the write lock to modify the geometry */
273 lck_rw_lock_exclusive(sysctl_geometry_lock
);
275 if (!(oidp
->oid_kind
& CTLFLAG_OID2
)) {
277 * We're using a copy so we can get the new fields in an
278 * old structure, so we have to iterate to compare the
279 * partial structure; when we find a match, we remove it
280 * normally and free the memory.
282 SLIST_FOREACH(old_oidp
, oidp
->oid_parent
, oid_link
) {
283 if (!memcmp(&oidp
->oid_number
, &old_oidp
->oid_number
, (offsetof(struct sysctl_oid
, oid_descr
) - offsetof(struct sysctl_oid
, oid_number
)))) {
287 if (old_oidp
!= NULL
) {
288 SLIST_REMOVE(old_oidp
->oid_parent
, old_oidp
, sysctl_oid
, oid_link
);
289 removed_oidp
= old_oidp
;
292 /* It's a later version; handle the versions we know about */
293 switch (oidp
->oid_version
) {
294 case SYSCTL_OID_VERSION
:
295 /* We can just remove the OID directly... */
296 SLIST_REMOVE(oidp
->oid_parent
, oidp
, sysctl_oid
, oid_link
);
300 /* XXX: Can't happen; probably tree coruption.*/
301 break; /* rejects unknown version */
305 #if defined(HAS_APPLE_PAC)
306 if (removed_oidp
&& removed_oidp
->oid_handler
&& old_oidp
== NULL
) {
308 * Revert address-discriminated signing performed by
309 * sysctl_register_oid() (in case this oid is registered again).
311 removed_oidp
->oid_handler
= ptrauth_auth_function(removed_oidp
->oid_handler
,
312 ptrauth_key_function_pointer
,
313 ptrauth_blend_discriminator(&removed_oidp
->oid_handler
,
314 ptrauth_string_discriminator("oid_handler")));
316 * Dereference the function-pointer-signed result to prevent an
317 * attacker with the ability to observe the result of the
318 * auth_and_resign above from trying all possible inputs until an auth
321 if (__builtin_expect(!*(uintptr_t*)ptrauth_auth_data((void*)
322 removed_oidp
->oid_handler
, ptrauth_key_function_pointer
, 0), 0)) {
324 * This is necessary to force the dereference but will never
325 * actually be reached, dereferencing an invalidly signed pointer
326 * will trap before getting here (and the codegen is nicer than
332 #endif /* defined(HAS_APPLE_PAC) */
335 * We've removed it from the list at this point, but we don't want
336 * to return to the caller until all handler references have drained
337 * out. Doing things in this order prevent other people coming in
338 * and starting new operations against the OID node we want removed.
340 * Note: oidp could be NULL if it wasn't found.
342 while (removed_oidp
&& removed_oidp
->oid_refcnt
) {
343 lck_rw_sleep(sysctl_geometry_lock
, LCK_SLEEP_EXCLUSIVE
, &removed_oidp
->oid_refcnt
, THREAD_UNINT
);
346 /* Release the write lock */
347 lck_rw_unlock_exclusive(sysctl_geometry_lock
);
349 /* If it was allocated, free it after dropping the lock */
350 if (old_oidp
!= NULL
) {
351 FREE(old_oidp
, M_TEMP
);
356 * Bulk-register all the oids in a linker_set.
359 sysctl_register_set(const char *set
)
361 struct sysctl_oid
**oidpp
, *oidp
;
363 LINKER_SET_FOREACH(oidpp
, struct sysctl_oid
**, set
) {
365 if (!(oidp
->oid_kind
& CTLFLAG_NOAUTO
)) {
366 sysctl_register_oid(oidp
);
372 sysctl_unregister_set(const char *set
)
374 struct sysctl_oid
**oidpp
, *oidp
;
376 LINKER_SET_FOREACH(oidpp
, struct sysctl_oid
**, set
) {
378 if (!(oidp
->oid_kind
& CTLFLAG_NOAUTO
)) {
379 sysctl_unregister_oid(oidp
);
385 * Exported in BSDKernel.exports, kept for binary compatibility
387 #if defined(__x86_64__)
389 sysctl_register_fixed(void)
395 * Register the kernel's oids on startup.
399 sysctl_early_init(void)
402 * Initialize the geometry lock for reading/modifying the
403 * sysctl tree. This is done here because IOKit registers
404 * some sysctl's before bsd_init() would otherwise perform
405 * subsystem initialization.
408 sysctl_lock_group
= lck_grp_alloc_init("sysctl", NULL
);
409 sysctl_geometry_lock
= lck_rw_alloc_init(sysctl_lock_group
, NULL
);
410 sysctl_unlocked_node_lock
= lck_mtx_alloc_init(sysctl_lock_group
, NULL
);
412 sysctl_register_set("__sysctl_set");
413 sysctl_load_devicetree_entries();
417 * New handler interface
418 * If the sysctl caller (user mode or kernel mode) is interested in the
419 * value (req->oldptr != NULL), we copy the data (bigValue etc.) out,
420 * if the caller wants to set the value (req->newptr), we copy
421 * the data in (*pValue etc.).
425 sysctl_io_number(struct sysctl_req
*req
, long long bigValue
, size_t valueSize
, void *pValue
, int *changed
)
435 * Handle the various combinations of caller buffer size and
436 * data value size. We are generous in the case where the
437 * caller has specified a 32-bit buffer but the value is 64-bit
441 /* 32 bit value expected or 32 bit buffer offered */
442 if (((valueSize
== sizeof(int)) ||
443 ((req
->oldlen
== sizeof(int)) && (valueSize
== sizeof(long long))))
445 smallValue
= (int)bigValue
;
446 if ((long long)smallValue
!= bigValue
) {
449 error
= SYSCTL_OUT(req
, &smallValue
, sizeof(smallValue
));
451 /* any other case is either size-equal or a bug */
452 error
= SYSCTL_OUT(req
, &bigValue
, valueSize
);
454 /* error or nothing to set */
455 if (error
|| !req
->newptr
) {
459 /* set request for constant */
460 if (pValue
== NULL
) {
464 /* set request needs to convert? */
465 if ((req
->newlen
== sizeof(int)) && (valueSize
== sizeof(long long))) {
466 /* new value is 32 bits, upconvert to 64 bits */
467 error
= SYSCTL_IN(req
, &smallValue
, sizeof(smallValue
));
469 *(long long *)pValue
= (long long)smallValue
;
471 } else if ((req
->newlen
== sizeof(long long)) && (valueSize
== sizeof(int))) {
472 /* new value is 64 bits, downconvert to 32 bits and range check */
473 error
= SYSCTL_IN(req
, &bigValue
, sizeof(bigValue
));
475 smallValue
= (int)bigValue
;
476 if ((long long)smallValue
!= bigValue
) {
479 *(int *)pValue
= smallValue
;
482 /* sizes match, just copy in */
483 error
= SYSCTL_IN(req
, pValue
, valueSize
);
485 if (!error
&& changed
) {
492 sysctl_io_string(struct sysctl_req
*req
, char *pValue
, size_t valueSize
, int trunc
, int *changed
)
500 if (trunc
&& req
->oldptr
&& req
->oldlen
&& (req
->oldlen
< strlen(pValue
) + 1)) {
501 /* If trunc != 0, if you give it a too small (but larger than
502 * 0 bytes) buffer, instead of returning ENOMEM, it truncates the
503 * returned string to the buffer size. This preserves the semantics
504 * of some library routines implemented via sysctl, which truncate
505 * their returned data, rather than simply returning an error. The
506 * returned string is always nul (ascii '\0') terminated. */
507 error
= SYSCTL_OUT(req
, pValue
, req
->oldlen
- 1);
510 error
= SYSCTL_OUT(req
, &c
, 1);
513 /* Copy string out */
514 error
= SYSCTL_OUT(req
, pValue
, strlen(pValue
) + 1);
517 /* error or no new value */
518 if (error
|| !req
->newptr
) {
522 /* attempt to set read-only value */
523 if (valueSize
== 0) {
527 /* make sure there's room for the new string */
528 if (req
->newlen
>= valueSize
) {
532 /* copy the string in and force nul termination */
533 error
= SYSCTL_IN(req
, pValue
, req
->newlen
);
534 pValue
[req
->newlen
] = '\0';
536 if (!error
&& changed
) {
543 sysctl_io_opaque(struct sysctl_req
*req
, void *pValue
, size_t valueSize
, int *changed
)
552 error
= SYSCTL_OUT(req
, pValue
, valueSize
);
554 /* error or nothing to set */
555 if (error
|| !req
->newptr
) {
559 error
= SYSCTL_IN(req
, pValue
, valueSize
);
561 if (!error
&& changed
) {
570 * These functions implement a presently undocumented interface
571 * used by the sysctl program to walk the tree, and get the type
572 * so it can print the value.
573 * This interface is under work and consideration, and should probably
574 * be killed with a big axe by the first person who can find the time.
575 * (be aware though, that the proper interface isn't as obvious as it
576 * may seem, there are various conflicting requirements.
578 * {0,0} printf the entire MIB-tree.
579 * {0,1,...} return the name of the "..." OID.
580 * {0,2,...} return the next OID.
581 * {0,3} return the OID of the name in "new"
582 * {0,4,...} return the kind & format info for the "..." OID.
586 * sysctl_sysctl_debug_dump_node
588 * Description: Dump debug information for a given sysctl_oid_list at the
589 * given oid depth out to the kernel log, via printf
591 * Parameters: l sysctl_oid_list pointer
592 * i current node depth
596 * Implicit: kernel log, modified
598 * Locks: Assumes sysctl_geometry_lock is held prior to calling
600 * Notes: This function may call itself recursively to resolve Node
601 * values, which potentially have an inferioer sysctl_oid_list
603 * This function is only callable indirectly via the function
604 * sysctl_sysctl_debug()
606 * Bugs: The node depth indentation does not work; this may be an
607 * artifact of leading space removal by the log daemon itself
608 * or some intermediate routine.
611 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list
*l
, int i
)
614 struct sysctl_oid
*oidp
;
616 SLIST_FOREACH(oidp
, l
, oid_link
) {
617 for (k
= 0; k
< i
; k
++) {
621 printf("%d %s ", oidp
->oid_number
, oidp
->oid_name
);
624 oidp
->oid_kind
& CTLFLAG_LOCKED
? 'L':' ',
625 oidp
->oid_kind
& CTLFLAG_RD
? 'R':' ',
626 oidp
->oid_kind
& CTLFLAG_WR
? 'W':' ');
628 if (oidp
->oid_handler
) {
632 switch (oidp
->oid_kind
& CTLTYPE
) {
635 if (!oidp
->oid_handler
) {
636 sysctl_sysctl_debug_dump_node(
637 oidp
->oid_arg1
, i
+ 2);
640 case CTLTYPE_INT
: printf(" Int\n"); break;
641 case CTLTYPE_STRING
: printf(" String\n"); break;
642 case CTLTYPE_QUAD
: printf(" Quad\n"); break;
643 case CTLTYPE_OPAQUE
: printf(" Opaque/struct\n"); break;
644 default: printf("\n");
650 * sysctl_sysctl_debug
652 * Description: This function implements the "sysctl.debug" portion of the
653 * OID space for sysctl.
657 * Parameters: __unused
661 * Implicit: kernel log, modified
663 * Locks: Acquires and then releases a read lock on the
664 * sysctl_geometry_lock
667 sysctl_sysctl_debug(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
,
668 __unused
int arg2
, __unused
struct sysctl_req
*req
)
670 lck_rw_lock_shared(sysctl_geometry_lock
);
671 sysctl_sysctl_debug_dump_node(&sysctl__children
, 0);
672 lck_rw_done(sysctl_geometry_lock
);
676 SYSCTL_PROC(_sysctl
, 0, debug
, CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_LOCKED
,
677 0, 0, sysctl_sysctl_debug
, "-", "");
682 * Description: Convert an OID into a string name; this is used by the user
683 * space sysctl() command line utility; this is done in a purely
684 * advisory capacity (e.g. to provide node names for "sysctl -A"
689 * Parameters: oidp __unused
690 * arg1 A pointer to the OID name list
691 * integer array, beginning at
692 * adjusted option base 2
693 * arg2 The number of elements which
694 * remain in the name array
697 * SYSCTL_OUT:EPERM Permission denied
698 * SYSCTL_OUT:EFAULT Bad user supplied buffer
699 * SYSCTL_OUT:??? Return value from user function
700 * for SYSCTL_PROC leaf node
702 * Implict: Contents of user request buffer, modified
704 * Locks: Acquires and then releases a read lock on the
705 * sysctl_geometry_lock
707 * Notes: SPI (System Programming Interface); this is subject to change
708 * and may not be relied upon by third party applications; use
709 * a subprocess to communicate with the "sysctl" command line
710 * command instead, if you believe you need this functionality.
711 * Preferrably, use sysctlbyname() instead.
713 * Setting of the NULL termination of the output string is
714 * delayed until after the geometry lock is dropped. If there
715 * are no Entries remaining in the OID name list when this
716 * function is called, it will still write out the termination
719 * This function differs from other sysctl functions in that
720 * it can not take an output buffer length of 0 to determine the
721 * space which will be required. It is suggested that the buffer
722 * length be PATH_MAX, and that authors of new sysctl's refrain
723 * from exceeding this string length.
726 sysctl_sysctl_name(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
727 struct sysctl_req
*req
)
729 int *name
= (int *) arg1
;
730 u_int namelen
= arg2
;
732 struct sysctl_oid
*oid
;
733 struct sysctl_oid_list
*lsp
= &sysctl__children
, *lsp2
;
734 char tempbuf
[10] = {};
736 lck_rw_lock_shared(sysctl_geometry_lock
);
739 snprintf(tempbuf
, sizeof(tempbuf
), "%d", *name
);
741 error
= SYSCTL_OUT(req
, ".", 1);
744 error
= SYSCTL_OUT(req
, tempbuf
, strlen(tempbuf
));
747 lck_rw_done(sysctl_geometry_lock
);
755 SLIST_FOREACH(oid
, lsp
, oid_link
) {
756 if (oid
->oid_number
!= *name
) {
761 error
= SYSCTL_OUT(req
, ".", 1);
764 error
= SYSCTL_OUT(req
, oid
->oid_name
,
765 strlen(oid
->oid_name
));
768 lck_rw_done(sysctl_geometry_lock
);
775 if ((oid
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
779 if (oid
->oid_handler
) {
783 lsp2
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
788 lck_rw_done(sysctl_geometry_lock
);
789 return SYSCTL_OUT(req
, "", 1);
792 SYSCTL_NODE(_sysctl
, 1, name
, CTLFLAG_RD
| CTLFLAG_LOCKED
, sysctl_sysctl_name
, "");
795 * sysctl_sysctl_next_ls
797 * Description: For a given OID name value, return the next consecutive OID
798 * name value within the geometry tree
800 * Parameters: lsp The OID list to look in
801 * name The OID name to start from
802 * namelen The length of the OID name
803 * next Pointer to new oid storage to
805 * len Pointer to receive new OID
806 * length value of storage written
807 * level OID tree depth (used to compute
809 * oidpp Pointer to OID list entry
810 * pointer; used to walk the list
811 * forward across recursion
813 * Returns: 0 Returning a new entry
814 * 1 End of geometry list reached
816 * Implicit: *next Modified to contain the new OID
817 * *len Modified to contain new length
819 * Locks: Assumes sysctl_geometry_lock is held prior to calling
821 * Notes: This function will not return OID values that have special
822 * handlers, since we can not tell wheter these handlers consume
823 * elements from the OID space as parameters. For this reason,
824 * we STRONGLY discourage these types of handlers
827 sysctl_sysctl_next_ls(struct sysctl_oid_list
*lsp
, int *name
, u_int namelen
,
828 int *next
, int *len
, int level
, struct sysctl_oid
**oidpp
)
830 struct sysctl_oid
*oidp
;
833 SLIST_FOREACH(oidp
, lsp
, oid_link
) {
834 *next
= oidp
->oid_number
;
838 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
841 if (oidp
->oid_handler
) {
842 /* We really should call the handler here...*/
845 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
847 if (!SLIST_FIRST(lsp
)) {
848 /* This node had no children - skip it! */
852 if (!sysctl_sysctl_next_ls(lsp
, 0, 0, next
+ 1,
853 len
, level
+ 1, oidpp
)) {
859 if (oidp
->oid_number
< *name
) {
863 if (oidp
->oid_number
> *name
) {
864 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
867 if (oidp
->oid_handler
) {
870 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
871 if (!sysctl_sysctl_next_ls(lsp
, name
+ 1, namelen
- 1,
872 next
+ 1, len
, level
+ 1, oidpp
)) {
877 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
881 if (oidp
->oid_handler
) {
885 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
886 if (!sysctl_sysctl_next_ls(lsp
, name
+ 1, namelen
- 1, next
+ 1,
887 len
, level
+ 1, oidpp
)) {
900 * Description: This is an iterator function designed to iterate the oid tree
901 * and provide a list of OIDs for use by the user space "sysctl"
906 * Parameters: oidp __unused
907 * arg1 Pointer to start OID name
908 * arg2 Start OID name length
909 * req Pointer to user request buffer
912 * ENOENT Reached end of OID space
913 * SYSCTL_OUT:EPERM Permission denied
914 * SYSCTL_OUT:EFAULT Bad user supplied buffer
915 * SYSCTL_OUT:??? Return value from user function
916 * for SYSCTL_PROC leaf node
918 * Implict: Contents of user request buffer, modified
920 * Locks: Acquires and then releases a read lock on the
921 * sysctl_geometry_lock
923 * Notes: SPI (System Programming Interface); this is subject to change
924 * and may not be relied upon by third party applications; use
925 * a subprocess to communicate with the "sysctl" command line
926 * command instead, if you believe you need this functionality.
927 * Preferrably, use sysctlbyname() instead.
929 * This function differs from other sysctl functions in that
930 * it can not take an output buffer length of 0 to determine the
931 * space which will be required. It is suggested that the buffer
932 * length be PATH_MAX, and that authors of new sysctl's refrain
933 * from exceeding this string length.
936 sysctl_sysctl_next(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
937 struct sysctl_req
*req
)
939 int *name
= (int *) arg1
;
940 u_int namelen
= arg2
;
942 struct sysctl_oid
*oid
;
943 struct sysctl_oid_list
*lsp
= &sysctl__children
;
944 int newoid
[CTL_MAXNAME
] = {};
946 lck_rw_lock_shared(sysctl_geometry_lock
);
947 i
= sysctl_sysctl_next_ls(lsp
, name
, namelen
, newoid
, &j
, 1, &oid
);
948 lck_rw_done(sysctl_geometry_lock
);
952 error
= SYSCTL_OUT(req
, newoid
, j
* sizeof(int));
956 SYSCTL_NODE(_sysctl
, 2, next
, CTLFLAG_RD
| CTLFLAG_LOCKED
, sysctl_sysctl_next
, "");
961 * Description: Support function for use by sysctl_sysctl_name2oid(); looks
962 * up an OID name given a string name.
964 * Parameters: name NULL terminated string name
965 * oid Pointer to receive OID name
966 * len Pointer to receive OID length
967 * pointer value (see "Notes")
970 * ENOENT Entry not found
972 * Implicit: *oid Modified to contain OID value
973 * *len Modified to contain OID length
975 * Locks: Assumes sysctl_geometry_lock is held prior to calling
978 name2oid(char *name
, int *oid
, u_int
*len
)
981 struct sysctl_oid
*oidp
;
982 struct sysctl_oid_list
*lsp
= &sysctl__children
;
989 p
= name
+ strlen(name
) - 1;
996 for (p
= name
; *p
&& *p
!= '.'; p
++) {
1004 oidp
= SLIST_FIRST(lsp
);
1006 while (oidp
&& *len
< CTL_MAXNAME
) {
1007 if (strcmp(name
, oidp
->oid_name
)) {
1008 oidp
= SLIST_NEXT(oidp
, oid_link
);
1011 *oid
++ = oidp
->oid_number
;
1018 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
1022 if (oidp
->oid_handler
) {
1026 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
1027 oidp
= SLIST_FIRST(lsp
);
1028 *p
= i
; /* restore */
1030 for (p
= name
; *p
&& *p
!= '.'; p
++) {
1042 * sysctl_sysctl_name2oid
1044 * Description: Translate a string name to an OID name value; this is used by
1045 * the sysctlbyname() function as well as by the "sysctl" command
1050 * Parameters: oidp __unused
1053 * req Request structure
1055 * Returns: ENOENT Input length too short
1056 * ENAMETOOLONG Input length too long
1057 * ENOMEM Could not allocate work area
1058 * SYSCTL_IN/OUT:EPERM Permission denied
1059 * SYSCTL_IN/OUT:EFAULT Bad user supplied buffer
1060 * SYSCTL_IN/OUT:??? Return value from user function
1061 * name2oid:ENOENT Not found
1063 * Implicit: *req Contents of request, modified
1065 * Locks: Acquires and then releases a read lock on the
1066 * sysctl_geometry_lock
1068 * Notes: SPI (System Programming Interface); this is subject to change
1069 * and may not be relied upon by third party applications; use
1070 * a subprocess to communicate with the "sysctl" command line
1071 * command instead, if you believe you need this functionality.
1072 * Preferrably, use sysctlbyname() instead.
1074 * This function differs from other sysctl functions in that
1075 * it can not take an output buffer length of 0 to determine the
1076 * space which will be required. It is suggested that the buffer
1077 * length be PATH_MAX, and that authors of new sysctl's refrain
1078 * from exceeding this string length.
1081 sysctl_sysctl_name2oid(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
,
1082 __unused
int arg2
, struct sysctl_req
*req
)
1085 int error
, oid
[CTL_MAXNAME
] = {};
1086 u_int len
= 0; /* set by name2oid() */
1088 if (req
->newlen
< 1) {
1091 if (req
->newlen
>= MAXPATHLEN
) { /* XXX arbitrary, undocumented */
1092 return ENAMETOOLONG
;
1095 MALLOC(p
, char *, req
->newlen
+ 1, M_TEMP
, M_WAITOK
);
1100 error
= SYSCTL_IN(req
, p
, req
->newlen
);
1106 p
[req
->newlen
] = '\0';
1109 * Note: We acquire and release the geometry lock here to
1110 * avoid making name2oid needlessly complex.
1112 lck_rw_lock_shared(sysctl_geometry_lock
);
1113 error
= name2oid(p
, oid
, &len
);
1114 lck_rw_done(sysctl_geometry_lock
);
1122 error
= SYSCTL_OUT(req
, oid
, len
* sizeof *oid
);
1126 SYSCTL_PROC(_sysctl
, 3, name2oid
, CTLFLAG_RW
| CTLFLAG_ANYBODY
| CTLFLAG_KERN
| CTLFLAG_LOCKED
, 0, 0,
1127 sysctl_sysctl_name2oid
, "I", "");
1130 * sysctl_sysctl_oidfmt
1132 * Description: For a given OID name, determine the format of the data which
1133 * is associated with it. This is used by the "sysctl" command
1138 * Parameters: oidp __unused
1139 * arg1 The OID name to look up
1140 * arg2 The length of the OID name
1141 * req Pointer to user request buffer
1143 * Returns: 0 Success
1144 * EISDIR Malformed request
1145 * ENOENT No such OID name
1146 * SYSCTL_OUT:EPERM Permission denied
1147 * SYSCTL_OUT:EFAULT Bad user supplied buffer
1148 * SYSCTL_OUT:??? Return value from user function
1150 * Implict: Contents of user request buffer, modified
1152 * Locks: Acquires and then releases a read lock on the
1153 * sysctl_geometry_lock
1155 * Notes: SPI (System Programming Interface); this is subject to change
1156 * and may not be relied upon by third party applications; use
1157 * a subprocess to communicate with the "sysctl" command line
1158 * command instead, if you believe you need this functionality.
1160 * This function differs from other sysctl functions in that
1161 * it can not take an output buffer length of 0 to determine the
1162 * space which will be required. It is suggested that the buffer
1163 * length be PATH_MAX, and that authors of new sysctl's refrain
1164 * from exceeding this string length.
1167 sysctl_sysctl_oidfmt(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
1168 struct sysctl_req
*req
)
1170 int *name
= (int *) arg1
;
1171 int error
= ENOENT
; /* default error: not found */
1172 u_int namelen
= arg2
;
1174 struct sysctl_oid
*oid
;
1175 struct sysctl_oid_list
*lsp
= &sysctl__children
;
1177 lck_rw_lock_shared(sysctl_geometry_lock
);
1178 oid
= SLIST_FIRST(lsp
);
1181 while (oid
&& indx
< CTL_MAXNAME
) {
1182 if (oid
->oid_number
== name
[indx
]) {
1184 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
1185 if (oid
->oid_handler
) {
1188 if (indx
== namelen
) {
1191 lsp
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
1192 oid
= SLIST_FIRST(lsp
);
1194 if (indx
!= namelen
) {
1201 oid
= SLIST_NEXT(oid
, oid_link
);
1208 if (!oid
->oid_fmt
) {
1211 error
= SYSCTL_OUT(req
,
1212 &oid
->oid_kind
, sizeof(oid
->oid_kind
));
1214 error
= SYSCTL_OUT(req
, oid
->oid_fmt
,
1215 strlen(oid
->oid_fmt
) + 1);
1218 lck_rw_done(sysctl_geometry_lock
);
1222 SYSCTL_NODE(_sysctl
, 4, oidfmt
, CTLFLAG_RD
| CTLFLAG_LOCKED
, sysctl_sysctl_oidfmt
, "");
1226 * Default "handler" functions.
1230 * Handle an int, signed or unsigned.
1232 * a variable: point arg1 at it.
1233 * a constant: pass it in arg2.
1237 sysctl_handle_int(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
1238 struct sysctl_req
*req
)
1240 return sysctl_io_number(req
, arg1
? *(int*)arg1
: arg2
, sizeof(int), arg1
, NULL
);
1244 * Handle a long, signed or unsigned. arg1 points to it.
1248 sysctl_handle_long(__unused
struct sysctl_oid
*oidp
, void *arg1
,
1249 __unused
int arg2
, struct sysctl_req
*req
)
1254 return sysctl_io_number(req
, *(long*)arg1
, sizeof(long), arg1
, NULL
);
1258 * Handle a quad, signed or unsigned. arg1 points to it.
1262 sysctl_handle_quad(__unused
struct sysctl_oid
*oidp
, void *arg1
,
1263 __unused
int arg2
, struct sysctl_req
*req
)
1268 return sysctl_io_number(req
, *(long long*)arg1
, sizeof(long long), arg1
, NULL
);
1272 * Expose an int value as a quad.
1274 * This interface allows us to support interfaces defined
1275 * as using quad values while the implementation is still
1279 sysctl_handle_int2quad(__unused
struct sysctl_oid
*oidp
, void *arg1
,
1280 __unused
int arg2
, struct sysctl_req
*req
)
1289 val
= (long long)*(int *)arg1
;
1290 error
= SYSCTL_OUT(req
, &val
, sizeof(long long));
1292 if (error
|| !req
->newptr
) {
1296 error
= SYSCTL_IN(req
, &val
, sizeof(long long));
1299 * Value must be representable; check by
1300 * casting and then casting back.
1303 if ((long long)newval
!= val
) {
1306 *(int *)arg1
= newval
;
1313 * Handle our generic '\0' terminated 'C' string.
1315 * a variable string: point arg1 at it, arg2 is max length.
1316 * a constant string: point arg1 at it, arg2 is zero.
1320 sysctl_handle_string( __unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
1321 struct sysctl_req
*req
)
1323 return sysctl_io_string(req
, arg1
, arg2
, 0, NULL
);
1327 * Handle any kind of opaque data.
1328 * arg1 points to it, arg2 is the size.
1332 sysctl_handle_opaque(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
1333 struct sysctl_req
*req
)
1335 return sysctl_io_opaque(req
, arg1
, arg2
, NULL
);
1339 * Transfer functions to/from kernel space.
1342 sysctl_old_kernel(struct sysctl_req
*req
, const void *p
, size_t l
)
1348 if (i
> req
->oldlen
- req
->oldidx
) {
1349 i
= req
->oldlen
- req
->oldidx
;
1352 bcopy((const void*)p
, CAST_DOWN(char *, (req
->oldptr
+ req
->oldidx
)), i
);
1356 if (req
->oldptr
&& i
!= l
) {
1363 sysctl_new_kernel(struct sysctl_req
*req
, void *p
, size_t l
)
1368 if (req
->newlen
- req
->newidx
< l
) {
1371 bcopy(CAST_DOWN(char *, (req
->newptr
+ req
->newidx
)), p
, l
);
1377 kernel_sysctl(struct proc
*p
, int *name
, u_int namelen
, void *old
, size_t *oldlenp
, void *new, size_t newlen
)
1380 struct sysctl_req req
;
1383 * Construct request.
1385 bzero(&req
, sizeof req
);
1388 req
.oldlen
= *oldlenp
;
1391 req
.oldptr
= CAST_USER_ADDR_T(old
);
1394 req
.newlen
= newlen
;
1395 req
.newptr
= CAST_USER_ADDR_T(new);
1397 req
.oldfunc
= sysctl_old_kernel
;
1398 req
.newfunc
= sysctl_new_kernel
;
1401 /* make the request */
1402 error
= sysctl_root(TRUE
, FALSE
, NULL
, 0, name
, namelen
, &req
);
1404 if (error
&& error
!= ENOMEM
) {
1409 *oldlenp
= req
.oldidx
;
1416 * Transfer function to/from user space.
1419 sysctl_old_user(struct sysctl_req
*req
, const void *p
, size_t l
)
1425 if (req
->oldlen
- req
->oldidx
< l
) {
1429 if (i
> req
->oldlen
- req
->oldidx
) {
1430 i
= req
->oldlen
- req
->oldidx
;
1433 error
= copyout((const void*)p
, (req
->oldptr
+ req
->oldidx
), i
);
1440 if (req
->oldptr
&& i
< l
) {
1447 sysctl_new_user(struct sysctl_req
*req
, void *p
, size_t l
)
1454 if (req
->newlen
- req
->newidx
< l
) {
1457 error
= copyin((req
->newptr
+ req
->newidx
), p
, l
);
1463 * Traverse our tree, and find the right node, execute whatever it points
1464 * at, and return the resulting error code.
1468 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
)
1472 struct sysctl_oid
*oid
;
1473 struct sysctl_oid_list
*lsp
= &sysctl__children
;
1474 sysctl_handler_t oid_handler
= NULL
;
1476 boolean_t unlocked_node_found
= FALSE
;
1477 boolean_t namestring_started
= FALSE
;
1479 /* Get the read lock on the geometry */
1480 lck_rw_lock_shared(sysctl_geometry_lock
);
1482 if (string_is_canonical
) {
1483 /* namestring is actually canonical, name/namelen needs to be populated */
1484 error
= name2oid(namestring
, name
, &namelen
);
1490 oid
= SLIST_FIRST(lsp
);
1493 while (oid
&& indx
< CTL_MAXNAME
) {
1494 if (oid
->oid_number
== name
[indx
]) {
1495 if (!from_kernel
&& !string_is_canonical
) {
1496 if (namestring_started
) {
1497 if (strlcat(namestring
, ".", namestringlen
) >= namestringlen
) {
1498 error
= ENAMETOOLONG
;
1503 if (strlcat(namestring
, oid
->oid_name
, namestringlen
) >= namestringlen
) {
1504 error
= ENAMETOOLONG
;
1507 namestring_started
= TRUE
;
1511 if (!(oid
->oid_kind
& CTLFLAG_LOCKED
)) {
1512 unlocked_node_found
= TRUE
;
1514 if (oid
->oid_kind
& CTLFLAG_NOLOCK
) {
1518 * For SYSCTL_PROC() functions which are for sysctl's
1519 * which have parameters at the end of their OID
1520 * space, you need to OR CTLTYPE_NODE into their
1523 * NOTE: For binary backward compatibility ONLY! Do
1524 * NOT add new sysctl's that do this! Existing
1525 * sysctl's which do this will eventually have
1526 * compatibility code in user space, and this method
1527 * will become unsupported.
1529 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
1530 if (oid
->oid_handler
) {
1533 if (indx
== namelen
) {
1538 lsp
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
1539 oid
= SLIST_FIRST(lsp
);
1541 if (indx
!= namelen
) {
1548 oid
= SLIST_NEXT(oid
, oid_link
);
1556 * indx is the index of the first remaining OID name,
1557 * for sysctls that take them as arguments
1559 if (!from_kernel
&& !string_is_canonical
&& (indx
< namelen
)) {
1563 for (indx2
= indx
; indx2
< namelen
; indx2
++) {
1564 snprintf(tempbuf
, sizeof(tempbuf
), "%d", name
[indx2
]);
1566 if (namestring_started
) {
1567 if (strlcat(namestring
, ".", namestringlen
) >= namestringlen
) {
1568 error
= ENAMETOOLONG
;
1573 if (strlcat(namestring
, tempbuf
, namestringlen
) >= namestringlen
) {
1574 error
= ENAMETOOLONG
;
1577 namestring_started
= TRUE
;
1581 /* If writing isn't allowed */
1582 if (req
->newptr
&& (!(oid
->oid_kind
& CTLFLAG_WR
) ||
1583 ((oid
->oid_kind
& CTLFLAG_SECURE
) && securelevel
> 0))) {
1589 * If we're inside the kernel, the OID must be marked as kernel-valid.
1591 if (from_kernel
&& !(oid
->oid_kind
& CTLFLAG_KERN
)) {
1597 * This is where legacy enforcement of permissions occurs. If the
1598 * flag does not say CTLFLAG_ANYBODY, then we prohibit anyone but
1599 * root from writing new values down. If local enforcement happens
1600 * at the leaf node, then it needs to be set as CTLFLAG_ANYBODY. In
1601 * addition, if the leaf node is set this way, then in order to do
1602 * specific enforcement, it has to be of type SYSCTL_PROC.
1604 if (!(oid
->oid_kind
& CTLFLAG_ANYBODY
) &&
1605 req
->newptr
&& req
->p
&&
1606 (error
= proc_suser(req
->p
))) {
1611 * sysctl_unregister_oid() may change the handler value, so grab it
1614 oid_handler
= oid
->oid_handler
;
1621 * Reference the OID and drop the geometry lock; this prevents the
1622 * OID from being deleted out from under the handler call, but does
1623 * not prevent other calls into handlers or calls to manage the
1624 * geometry elsewhere from blocking...
1626 OSAddAtomic(1, &oid
->oid_refcnt
);
1628 lck_rw_done(sysctl_geometry_lock
);
1632 error
= mac_system_check_sysctlbyname(kauth_cred_get(),
1647 * ...however, we still have to grab the mutex for those calls which
1648 * may be into code whose reentrancy is protected by it.
1650 if (unlocked_node_found
) {
1651 lck_mtx_lock(sysctl_unlocked_node_lock
);
1654 #if defined(HAS_APPLE_PAC)
1656 * oid_handler is signed address-discriminated by sysctl_register_oid().
1658 oid_handler
= ptrauth_auth_function(oid_handler
,
1659 ptrauth_key_function_pointer
,
1660 ptrauth_blend_discriminator(&oid
->oid_handler
,
1661 ptrauth_string_discriminator("oid_handler")));
1662 #endif /* defined(HAS_APPLE_PAC) */
1664 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
1665 i
= oid_handler(oid
, name
+ indx
, namelen
- indx
, req
);
1667 i
= oid_handler(oid
, oid
->oid_arg1
, oid
->oid_arg2
, req
);
1671 if (unlocked_node_found
) {
1672 lck_mtx_unlock(sysctl_unlocked_node_lock
);
1676 /* only used from another CONFIG_MACF block */
1681 * This is tricky... we re-grab the geometry lock in order to drop
1682 * the reference and wake on the address; since the geometry
1683 * lock is a reader/writer lock rather than a mutex, we have to
1684 * wake on all apparent 1->0 transitions. This abuses the drop
1685 * after the reference decrement in order to wake any lck_rw_sleep()
1686 * in progress in sysctl_unregister_oid() that slept because of a
1687 * non-zero reference count.
1689 * Note: OSAddAtomic() is defined to return the previous value;
1690 * we use this and the fact that the lock itself is a
1691 * barrier to avoid waking every time through on "hot"
1694 lck_rw_lock_shared(sysctl_geometry_lock
);
1695 if (OSAddAtomic(-1, &oid
->oid_refcnt
) == 1) {
1696 wakeup(&oid
->oid_refcnt
);
1700 lck_rw_done(sysctl_geometry_lock
);
1705 sysctl_create_user_req(struct sysctl_req
*req
, struct proc
*p
, user_addr_t oldp
,
1706 size_t oldlen
, user_addr_t newp
, size_t newlen
)
1708 bzero(req
, sizeof(*req
));
1712 req
->oldlen
= oldlen
;
1716 req
->newlen
= newlen
;
1720 req
->oldfunc
= sysctl_old_user
;
1721 req
->newfunc
= sysctl_new_user
;
1728 sysctl(proc_t p
, struct sysctl_args
*uap
, __unused
int32_t *retval
)
1730 int error
, new_error
;
1731 size_t oldlen
= 0, newlen
;
1732 int name
[CTL_MAXNAME
];
1733 struct sysctl_req req
;
1735 size_t namestringlen
= MAXPATHLEN
;
1738 * all top-level sysctl names are non-terminal
1740 if (uap
->namelen
> CTL_MAXNAME
|| uap
->namelen
< 2) {
1743 error
= copyin(uap
->name
, &name
[0], uap
->namelen
* sizeof(int));
1748 AUDIT_ARG(ctlname
, name
, uap
->namelen
);
1750 if (uap
->newlen
> SIZE_T_MAX
) {
1753 newlen
= (size_t)uap
->newlen
;
1755 if (uap
->oldlenp
!= USER_ADDR_NULL
) {
1756 uint64_t oldlen64
= fuulong(uap
->oldlenp
);
1759 * If more than 4G, clamp to 4G
1761 if (oldlen64
> SIZE_T_MAX
) {
1762 oldlen
= SIZE_T_MAX
;
1764 oldlen
= (size_t)oldlen64
;
1768 sysctl_create_user_req(&req
, p
, uap
->old
, oldlen
, uap
->new, newlen
);
1770 /* Guess that longest length for the passed-in MIB, if we can be more aggressive than MAXPATHLEN */
1771 if (uap
->namelen
== 2) {
1772 if (name
[0] == CTL_KERN
&& name
[1] < KERN_MAXID
) {
1773 namestringlen
= 32; /* "kern.speculative_reads_disabled" */
1774 } else if (name
[0] == CTL_HW
&& name
[1] < HW_MAXID
) {
1775 namestringlen
= 32; /* "hw.cachelinesize_compat" */
1779 MALLOC(namestring
, char *, namestringlen
, M_TEMP
, M_WAITOK
);
1785 error
= userland_sysctl(FALSE
, namestring
, namestringlen
, name
, uap
->namelen
, &req
, &oldlen
);
1787 FREE(namestring
, M_TEMP
);
1789 if ((error
) && (error
!= ENOMEM
)) {
1794 if (uap
->oldlenp
!= USER_ADDR_NULL
) {
1796 * Only overwrite the old error value on a new error
1798 new_error
= suulong(uap
->oldlenp
, oldlen
);
1808 // sysctlbyname is also exported as KPI to kexts
1809 // and the syscall name cannot conflict with it
1811 sys_sysctlbyname(proc_t p
, struct sysctlbyname_args
*uap
, __unused
int32_t *retval
)
1813 int error
, new_error
;
1814 size_t oldlen
= 0, newlen
;
1817 struct sysctl_req req
;
1818 int oid
[CTL_MAXNAME
];
1820 if (uap
->namelen
>= MAXPATHLEN
) { /* XXX arbitrary, undocumented */
1821 return ENAMETOOLONG
;
1823 namelen
= (size_t)uap
->namelen
;
1825 MALLOC(name
, char *, namelen
+ 1, M_TEMP
, M_WAITOK
);
1830 error
= copyin(uap
->name
, name
, namelen
);
1835 name
[namelen
] = '\0';
1838 * AUDIT_ARG(ctlname, name, uap->namelen);
1841 if (uap
->newlen
> SIZE_T_MAX
) {
1845 newlen
= (size_t)uap
->newlen
;
1847 if (uap
->oldlenp
!= USER_ADDR_NULL
) {
1848 uint64_t oldlen64
= fuulong(uap
->oldlenp
);
1851 * If more than 4G, clamp to 4G
1853 if (oldlen64
> SIZE_T_MAX
) {
1854 oldlen
= SIZE_T_MAX
;
1856 oldlen
= (size_t)oldlen64
;
1860 sysctl_create_user_req(&req
, p
, uap
->old
, oldlen
, uap
->new, newlen
);
1862 error
= userland_sysctl(TRUE
, name
, namelen
+ 1, oid
, CTL_MAXNAME
, &req
, &oldlen
);
1866 if ((error
) && (error
!= ENOMEM
)) {
1870 if (uap
->oldlenp
!= USER_ADDR_NULL
) {
1872 * Only overwrite the old error value on a new error
1874 new_error
= suulong(uap
->oldlenp
, oldlen
);
1885 * This is used from various compatibility syscalls too. That's why name
1886 * must be in kernel space.
1889 userland_sysctl(boolean_t string_is_canonical
,
1890 char *namestring
, size_t namestringlen
,
1891 int *name
, u_int namelen
, struct sysctl_req
*req
,
1895 struct sysctl_req req2
;
1898 /* if EAGAIN, reset output cursor */
1900 if (!string_is_canonical
) {
1901 namestring
[0] = '\0';
1904 error
= sysctl_root(FALSE
, string_is_canonical
, namestring
, namestringlen
, name
, namelen
, &req2
);
1905 } while (error
== EAGAIN
);
1907 if (error
&& error
!= ENOMEM
) {
1912 if (req2
.oldptr
&& req2
.oldidx
> req2
.oldlen
) {
1913 *retval
= req2
.oldlen
;
1915 *retval
= req2
.oldidx
;
1922 * Kernel versions of the userland sysctl helper functions.
1924 * These allow sysctl to be used in the same fashion in both
1925 * userland and the kernel.
1927 * Note that some sysctl handlers use copyin/copyout, which
1928 * may not work correctly.
1930 * The "sysctlbyname" KPI for use by kexts is aliased to this function.
1934 kernel_sysctlbyname(const char *name
, void *oldp
, size_t *oldlenp
, void *newp
, size_t newlen
)
1936 int oid
[CTL_MAXNAME
];
1937 int name2mib_oid
[2];
1941 /* look up the OID with magic service node */
1942 name2mib_oid
[0] = 0;
1943 name2mib_oid
[1] = 3;
1945 oidlen
= sizeof(oid
);
1946 error
= kernel_sysctl(current_proc(), name2mib_oid
, 2, oid
, &oidlen
, __DECONST(void *, name
), strlen(name
));
1947 oidlen
/= sizeof(int);
1949 /* now use the OID */
1951 error
= kernel_sysctl(current_proc(), oid
, oidlen
, oldp
, oldlenp
, newp
, newlen
);