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)
90 #endif /* defined(HAS_APPLE_PAC) */
92 lck_grp_t
* sysctl_lock_group
= NULL
;
93 lck_rw_t
* sysctl_geometry_lock
= NULL
;
94 lck_mtx_t
* sysctl_unlocked_node_lock
= NULL
;
97 * Conditionally allow dtrace to see these functions for debugging purposes.
105 #define STATIC static
108 /* forward declarations of static functions */
109 STATIC
void sysctl_sysctl_debug_dump_node(struct sysctl_oid_list
*l
, int i
);
110 STATIC
int sysctl_sysctl_debug(struct sysctl_oid
*oidp
, void *arg1
,
111 int arg2
, struct sysctl_req
*req
);
112 STATIC
int sysctl_sysctl_name(struct sysctl_oid
*oidp
, void *arg1
,
113 int arg2
, struct sysctl_req
*req
);
114 STATIC
int sysctl_sysctl_next_ls(struct sysctl_oid_list
*lsp
,
115 int *name
, u_int namelen
, int *next
, int *len
, int level
,
116 struct sysctl_oid
**oidpp
);
117 STATIC
int sysctl_old_kernel(struct sysctl_req
*req
, const void *p
, size_t l
);
118 STATIC
int sysctl_new_kernel(struct sysctl_req
*req
, void *p
, size_t l
);
119 STATIC
int name2oid(char *name
, int *oid
, size_t *len
);
120 STATIC
int sysctl_sysctl_name2oid(struct sysctl_oid
*oidp
, void *arg1
, int arg2
, struct sysctl_req
*req
);
121 STATIC
int sysctl_sysctl_next(struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
122 struct sysctl_req
*req
);
123 STATIC
int sysctl_sysctl_oidfmt(struct sysctl_oid
*oidp
, void *arg1
, int arg2
, struct sysctl_req
*req
);
124 STATIC
int sysctl_old_user(struct sysctl_req
*req
, const void *p
, size_t l
);
125 STATIC
int sysctl_new_user(struct sysctl_req
*req
, void *p
, size_t l
);
127 STATIC
void sysctl_create_user_req(struct sysctl_req
*req
, struct proc
*p
, user_addr_t oldp
,
128 size_t oldlen
, user_addr_t newp
, size_t newlen
);
129 STATIC
int sysctl_root(boolean_t from_kernel
, boolean_t string_is_canonical
, char *namestring
, size_t namestringlen
, int *name
, size_t namelen
, struct sysctl_req
*req
);
131 int kernel_sysctl(struct proc
*p
, int *name
, size_t namelen
, void *old
, size_t *oldlenp
, void *new, size_t newlen
);
132 int kernel_sysctlbyname(const char *name
, void *oldp
, size_t *oldlenp
, void *newp
, size_t newlen
);
133 int userland_sysctl(boolean_t string_is_canonical
,
134 char *namestring
, size_t namestringlen
,
135 int *name
, u_int namelen
, struct sysctl_req
*req
,
138 struct sysctl_oid_list sysctl__children
; /* root list */
141 * Initialization of the MIB tree.
143 * Order by number in each list.
147 sysctl_register_oid(struct sysctl_oid
*new_oidp
)
149 struct sysctl_oid
*oidp
= NULL
;
150 struct sysctl_oid_list
*parent
= new_oidp
->oid_parent
;
151 struct sysctl_oid
*p
;
152 struct sysctl_oid
*q
;
156 * The OID can be old-style (needs copy), new style without an earlier
157 * version (also needs copy), or new style with a matching version (no
158 * copy needed). Later versions are rejected (presumably, the OID
159 * structure was changed for a necessary reason).
161 if (!(new_oidp
->oid_kind
& CTLFLAG_OID2
)) {
164 * XXX: M_TEMP is perhaps not the most apropriate zone, as it
165 * XXX: will subject us to use-after-free by other consumers.
167 MALLOC(oidp
, struct sysctl_oid
*, sizeof(*oidp
), M_TEMP
, M_WAITOK
| M_ZERO
);
169 return; /* reject: no memory */
172 * Copy the structure only through the oid_fmt field, which
173 * is the last field in a non-OID2 OID structure.
175 * Note: We may want to set the oid_descr to the
176 * oid_name (or "") at some future date.
180 panic("Old style sysctl without a version number isn't supported");
183 /* It's a later version; handle the versions we know about */
184 switch (new_oidp
->oid_version
) {
185 case SYSCTL_OID_VERSION
:
186 /* current version */
190 return; /* rejects unknown version */
194 /* Get the write lock to modify the geometry */
195 lck_rw_lock_exclusive(sysctl_geometry_lock
);
198 * If this oid has a number OID_AUTO, give it a number which
199 * is greater than any current oid. Make sure it is at least
200 * OID_AUTO_START to leave space for pre-assigned oid numbers.
202 if (oidp
->oid_number
== OID_AUTO
) {
203 /* First, find the highest oid in the parent list >OID_AUTO_START-1 */
205 SLIST_FOREACH(p
, parent
, oid_link
) {
206 if (p
->oid_number
> n
) {
210 oidp
->oid_number
= n
+ 1;
212 * Reflect the number in an llocated OID into the template
213 * of the caller for sysctl_unregister_oid() compares.
215 if (oidp
!= new_oidp
) {
216 new_oidp
->oid_number
= oidp
->oid_number
;
220 #if defined(HAS_APPLE_PAC)
221 if (oidp
->oid_handler
) {
223 * Sign oid_handler address-discriminated upon installation to make it
224 * harder to replace with an arbitrary function pointer. Blend with
225 * a hash of oid_arg1 for robustness against memory corruption.
227 oidp
->oid_handler
= ptrauth_auth_and_resign(oidp
->oid_handler
,
228 ptrauth_key_function_pointer
,
229 ptrauth_function_pointer_type_discriminator(typeof(oidp
->oid_handler
)),
230 ptrauth_key_function_pointer
,
231 ptrauth_blend_discriminator(&oidp
->oid_handler
,
232 os_hash_kernel_pointer(oidp
->oid_arg1
)));
234 #endif /* defined(HAS_APPLE_PAC) */
237 * Insert the oid into the parent's list in order.
240 SLIST_FOREACH(p
, parent
, oid_link
) {
241 if (oidp
->oid_number
== p
->oid_number
) {
242 panic("attempting to register a sysctl at previously registered slot : %d", oidp
->oid_number
);
243 } else if (oidp
->oid_number
< p
->oid_number
) {
249 SLIST_INSERT_AFTER(q
, oidp
, oid_link
);
251 SLIST_INSERT_HEAD(parent
, oidp
, oid_link
);
254 /* Release the write lock */
255 lck_rw_unlock_exclusive(sysctl_geometry_lock
);
259 sysctl_unregister_oid(struct sysctl_oid
*oidp
)
261 struct sysctl_oid
*removed_oidp
= NULL
; /* OID removed from tree */
263 struct sysctl_oid
*old_oidp
= NULL
; /* OID compatibility copy */
265 struct sysctl_oid
*const old_oidp
= NULL
;
268 /* Get the write lock to modify the geometry */
269 lck_rw_lock_exclusive(sysctl_geometry_lock
);
271 if (!(oidp
->oid_kind
& CTLFLAG_OID2
)) {
274 * We're using a copy so we can get the new fields in an
275 * old structure, so we have to iterate to compare the
276 * partial structure; when we find a match, we remove it
277 * normally and free the memory.
279 SLIST_FOREACH(old_oidp
, oidp
->oid_parent
, oid_link
) {
280 if (!memcmp(&oidp
->oid_number
, &old_oidp
->oid_number
, (offsetof(struct sysctl_oid
, oid_descr
) - offsetof(struct sysctl_oid
, oid_number
)))) {
284 if (old_oidp
!= NULL
) {
285 SLIST_REMOVE(old_oidp
->oid_parent
, old_oidp
, sysctl_oid
, oid_link
);
286 removed_oidp
= old_oidp
;
289 panic("Old style sysctl without a version number isn't supported");
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_and_resign(removed_oidp
->oid_handler
,
312 ptrauth_key_function_pointer
,
313 ptrauth_blend_discriminator(&removed_oidp
->oid_handler
,
314 os_hash_kernel_pointer(removed_oidp
->oid_arg1
)),
315 ptrauth_key_function_pointer
,
316 ptrauth_function_pointer_type_discriminator(typeof(removed_oidp
->oid_handler
)));
318 #endif /* defined(HAS_APPLE_PAC) */
321 * We've removed it from the list at this point, but we don't want
322 * to return to the caller until all handler references have drained
323 * out. Doing things in this order prevent other people coming in
324 * and starting new operations against the OID node we want removed.
326 * Note: oidp could be NULL if it wasn't found.
328 while (removed_oidp
&& removed_oidp
->oid_refcnt
) {
329 lck_rw_sleep(sysctl_geometry_lock
, LCK_SLEEP_EXCLUSIVE
, &removed_oidp
->oid_refcnt
, THREAD_UNINT
);
332 /* Release the write lock */
333 lck_rw_unlock_exclusive(sysctl_geometry_lock
);
335 if (old_oidp
!= NULL
) {
337 /* If it was allocated, free it after dropping the lock */
338 FREE(old_oidp
, M_TEMP
);
344 * Bulk-register all the oids in a linker_set.
347 sysctl_register_set(const char *set
)
349 struct sysctl_oid
**oidpp
, *oidp
;
351 LINKER_SET_FOREACH(oidpp
, struct sysctl_oid
**, set
) {
353 if (!(oidp
->oid_kind
& CTLFLAG_NOAUTO
)) {
354 sysctl_register_oid(oidp
);
360 sysctl_unregister_set(const char *set
)
362 struct sysctl_oid
**oidpp
, *oidp
;
364 LINKER_SET_FOREACH(oidpp
, struct sysctl_oid
**, set
) {
366 if (!(oidp
->oid_kind
& CTLFLAG_NOAUTO
)) {
367 sysctl_unregister_oid(oidp
);
373 * Exported in BSDKernel.exports, kept for binary compatibility
375 #if defined(__x86_64__)
377 sysctl_register_fixed(void)
383 * Register the kernel's oids on startup.
387 sysctl_early_init(void)
390 * Initialize the geometry lock for reading/modifying the
391 * sysctl tree. This is done here because IOKit registers
392 * some sysctl's before bsd_init() would otherwise perform
393 * subsystem initialization.
396 sysctl_lock_group
= lck_grp_alloc_init("sysctl", NULL
);
397 sysctl_geometry_lock
= lck_rw_alloc_init(sysctl_lock_group
, NULL
);
398 sysctl_unlocked_node_lock
= lck_mtx_alloc_init(sysctl_lock_group
, NULL
);
400 sysctl_register_set("__sysctl_set");
401 sysctl_load_devicetree_entries();
405 * New handler interface
406 * If the sysctl caller (user mode or kernel mode) is interested in the
407 * value (req->oldptr != NULL), we copy the data (bigValue etc.) out,
408 * if the caller wants to set the value (req->newptr), we copy
409 * the data in (*pValue etc.).
413 sysctl_io_number(struct sysctl_req
*req
, long long bigValue
, size_t valueSize
, void *pValue
, int *changed
)
423 * Handle the various combinations of caller buffer size and
424 * data value size. We are generous in the case where the
425 * caller has specified a 32-bit buffer but the value is 64-bit
429 /* 32 bit value expected or 32 bit buffer offered */
430 if (((valueSize
== sizeof(int)) ||
431 ((req
->oldlen
== sizeof(int)) && (valueSize
== sizeof(long long))))
433 smallValue
= (int)bigValue
;
434 if ((long long)smallValue
!= bigValue
) {
437 error
= SYSCTL_OUT(req
, &smallValue
, sizeof(smallValue
));
439 /* any other case is either size-equal or a bug */
440 error
= SYSCTL_OUT(req
, &bigValue
, valueSize
);
442 /* error or nothing to set */
443 if (error
|| !req
->newptr
) {
447 /* set request for constant */
448 if (pValue
== NULL
) {
452 /* set request needs to convert? */
453 if ((req
->newlen
== sizeof(int)) && (valueSize
== sizeof(long long))) {
454 /* new value is 32 bits, upconvert to 64 bits */
455 error
= SYSCTL_IN(req
, &smallValue
, sizeof(smallValue
));
457 *(long long *)pValue
= (long long)smallValue
;
459 } else if ((req
->newlen
== sizeof(long long)) && (valueSize
== sizeof(int))) {
460 /* new value is 64 bits, downconvert to 32 bits and range check */
461 error
= SYSCTL_IN(req
, &bigValue
, sizeof(bigValue
));
463 smallValue
= (int)bigValue
;
464 if ((long long)smallValue
!= bigValue
) {
467 *(int *)pValue
= smallValue
;
470 /* sizes match, just copy in */
471 error
= SYSCTL_IN(req
, pValue
, valueSize
);
473 if (!error
&& changed
) {
480 sysctl_io_string(struct sysctl_req
*req
, char *pValue
, size_t valueSize
, int trunc
, int *changed
)
483 size_t len
= strlen(pValue
) + 1;
489 if (trunc
&& req
->oldptr
&& req
->oldlen
&& (req
->oldlen
< len
)) {
490 /* If trunc != 0, if you give it a too small (but larger than
491 * 0 bytes) buffer, instead of returning ENOMEM, it truncates the
492 * returned string to the buffer size. This preserves the semantics
493 * of some library routines implemented via sysctl, which truncate
494 * their returned data, rather than simply returning an error. The
495 * returned string is always nul (ascii '\0') terminated. */
496 error
= SYSCTL_OUT(req
, pValue
, req
->oldlen
- 1);
499 error
= SYSCTL_OUT(req
, &c
, 1);
502 /* Copy string out */
503 error
= SYSCTL_OUT(req
, pValue
, len
);
506 /* error or no new value */
507 if (error
|| !req
->newptr
) {
511 /* attempt to set read-only value */
512 if (valueSize
== 0) {
516 /* make sure there's room for the new string */
517 if (req
->newlen
>= valueSize
) {
521 /* copy the string in and force nul termination */
522 error
= SYSCTL_IN(req
, pValue
, req
->newlen
);
523 pValue
[req
->newlen
] = '\0';
525 if (!error
&& changed
) {
532 sysctl_io_opaque(struct sysctl_req
*req
, void *pValue
, size_t valueSize
, int *changed
)
541 error
= SYSCTL_OUT(req
, pValue
, valueSize
);
543 /* error or nothing to set */
544 if (error
|| !req
->newptr
) {
548 error
= SYSCTL_IN(req
, pValue
, valueSize
);
550 if (!error
&& changed
) {
559 * These functions implement a presently undocumented interface
560 * used by the sysctl program to walk the tree, and get the type
561 * so it can print the value.
562 * This interface is under work and consideration, and should probably
563 * be killed with a big axe by the first person who can find the time.
564 * (be aware though, that the proper interface isn't as obvious as it
565 * may seem, there are various conflicting requirements.
567 * {0,0} printf the entire MIB-tree.
568 * {0,1,...} return the name of the "..." OID.
569 * {0,2,...} return the next OID.
570 * {0,3} return the OID of the name in "new"
571 * {0,4,...} return the kind & format info for the "..." OID.
575 * sysctl_sysctl_debug_dump_node
577 * Description: Dump debug information for a given sysctl_oid_list at the
578 * given oid depth out to the kernel log, via printf
580 * Parameters: l sysctl_oid_list pointer
581 * i current node depth
585 * Implicit: kernel log, modified
587 * Locks: Assumes sysctl_geometry_lock is held prior to calling
589 * Notes: This function may call itself recursively to resolve Node
590 * values, which potentially have an inferioer sysctl_oid_list
592 * This function is only callable indirectly via the function
593 * sysctl_sysctl_debug()
595 * Bugs: The node depth indentation does not work; this may be an
596 * artifact of leading space removal by the log daemon itself
597 * or some intermediate routine.
600 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list
*l
, int i
)
603 struct sysctl_oid
*oidp
;
605 SLIST_FOREACH(oidp
, l
, oid_link
) {
606 for (k
= 0; k
< i
; k
++) {
610 printf("%d %s ", oidp
->oid_number
, oidp
->oid_name
);
613 oidp
->oid_kind
& CTLFLAG_LOCKED
? 'L':' ',
614 oidp
->oid_kind
& CTLFLAG_RD
? 'R':' ',
615 oidp
->oid_kind
& CTLFLAG_WR
? 'W':' ');
617 if (oidp
->oid_handler
) {
621 switch (oidp
->oid_kind
& CTLTYPE
) {
624 if (!oidp
->oid_handler
) {
625 sysctl_sysctl_debug_dump_node(
626 oidp
->oid_arg1
, i
+ 2);
629 case CTLTYPE_INT
: printf(" Int\n"); break;
630 case CTLTYPE_STRING
: printf(" String\n"); break;
631 case CTLTYPE_QUAD
: printf(" Quad\n"); break;
632 case CTLTYPE_OPAQUE
: printf(" Opaque/struct\n"); break;
633 default: printf("\n");
639 * sysctl_sysctl_debug
641 * Description: This function implements the "sysctl.debug" portion of the
642 * OID space for sysctl.
646 * Parameters: __unused
650 * Implicit: kernel log, modified
652 * Locks: Acquires and then releases a read lock on the
653 * sysctl_geometry_lock
656 sysctl_sysctl_debug(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
,
657 __unused
int arg2
, __unused
struct sysctl_req
*req
)
659 lck_rw_lock_shared(sysctl_geometry_lock
);
660 sysctl_sysctl_debug_dump_node(&sysctl__children
, 0);
661 lck_rw_done(sysctl_geometry_lock
);
665 SYSCTL_PROC(_sysctl
, 0, debug
, CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_LOCKED
,
666 0, 0, sysctl_sysctl_debug
, "-", "");
671 * Description: Convert an OID into a string name; this is used by the user
672 * space sysctl() command line utility; this is done in a purely
673 * advisory capacity (e.g. to provide node names for "sysctl -A"
678 * Parameters: oidp __unused
679 * arg1 A pointer to the OID name list
680 * integer array, beginning at
681 * adjusted option base 2
682 * arg2 The number of elements which
683 * remain in the name array
686 * SYSCTL_OUT:EPERM Permission denied
687 * SYSCTL_OUT:EFAULT Bad user supplied buffer
688 * SYSCTL_OUT:??? Return value from user function
689 * for SYSCTL_PROC leaf node
691 * Implict: Contents of user request buffer, modified
693 * Locks: Acquires and then releases a read lock on the
694 * sysctl_geometry_lock
696 * Notes: SPI (System Programming Interface); this is subject to change
697 * and may not be relied upon by third party applications; use
698 * a subprocess to communicate with the "sysctl" command line
699 * command instead, if you believe you need this functionality.
700 * Preferrably, use sysctlbyname() instead.
702 * Setting of the NULL termination of the output string is
703 * delayed until after the geometry lock is dropped. If there
704 * are no Entries remaining in the OID name list when this
705 * function is called, it will still write out the termination
708 * This function differs from other sysctl functions in that
709 * it can not take an output buffer length of 0 to determine the
710 * space which will be required. It is suggested that the buffer
711 * length be PATH_MAX, and that authors of new sysctl's refrain
712 * from exceeding this string length.
715 sysctl_sysctl_name(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
716 struct sysctl_req
*req
)
718 int *name
= (int *) arg1
;
719 u_int namelen
= arg2
;
721 struct sysctl_oid
*oid
;
722 struct sysctl_oid_list
*lsp
= &sysctl__children
, *lsp2
;
723 char tempbuf
[10] = {};
725 lck_rw_lock_shared(sysctl_geometry_lock
);
728 snprintf(tempbuf
, sizeof(tempbuf
), "%d", *name
);
730 error
= SYSCTL_OUT(req
, ".", 1);
733 error
= SYSCTL_OUT(req
, tempbuf
, strlen(tempbuf
));
736 lck_rw_done(sysctl_geometry_lock
);
744 SLIST_FOREACH(oid
, lsp
, oid_link
) {
745 if (oid
->oid_number
!= *name
) {
750 error
= SYSCTL_OUT(req
, ".", 1);
753 error
= SYSCTL_OUT(req
, oid
->oid_name
,
754 strlen(oid
->oid_name
));
757 lck_rw_done(sysctl_geometry_lock
);
764 if ((oid
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
768 if (oid
->oid_handler
) {
772 lsp2
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
777 lck_rw_done(sysctl_geometry_lock
);
778 return SYSCTL_OUT(req
, "", 1);
781 SYSCTL_NODE(_sysctl
, 1, name
, CTLFLAG_RD
| CTLFLAG_LOCKED
, sysctl_sysctl_name
, "");
784 * sysctl_sysctl_next_ls
786 * Description: For a given OID name value, return the next consecutive OID
787 * name value within the geometry tree
789 * Parameters: lsp The OID list to look in
790 * name The OID name to start from
791 * namelen The length of the OID name
792 * next Pointer to new oid storage to
794 * len Pointer to receive new OID
795 * length value of storage written
796 * level OID tree depth (used to compute
798 * oidpp Pointer to OID list entry
799 * pointer; used to walk the list
800 * forward across recursion
802 * Returns: 0 Returning a new entry
803 * 1 End of geometry list reached
805 * Implicit: *next Modified to contain the new OID
806 * *len Modified to contain new length
808 * Locks: Assumes sysctl_geometry_lock is held prior to calling
810 * Notes: This function will not return OID values that have special
811 * handlers, since we can not tell wheter these handlers consume
812 * elements from the OID space as parameters. For this reason,
813 * we STRONGLY discourage these types of handlers
816 sysctl_sysctl_next_ls(struct sysctl_oid_list
*lsp
, int *name
, u_int namelen
,
817 int *next
, int *len
, int level
, struct sysctl_oid
**oidpp
)
819 struct sysctl_oid
*oidp
;
822 SLIST_FOREACH(oidp
, lsp
, oid_link
) {
823 *next
= oidp
->oid_number
;
827 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
830 if (oidp
->oid_handler
) {
831 /* We really should call the handler here...*/
834 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
836 if (!SLIST_FIRST(lsp
)) {
837 /* This node had no children - skip it! */
841 if (!sysctl_sysctl_next_ls(lsp
, 0, 0, next
+ 1,
842 len
, level
+ 1, oidpp
)) {
848 if (oidp
->oid_number
< *name
) {
852 if (oidp
->oid_number
> *name
) {
853 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
856 if (oidp
->oid_handler
) {
859 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
860 if (!sysctl_sysctl_next_ls(lsp
, name
+ 1, namelen
- 1,
861 next
+ 1, len
, level
+ 1, oidpp
)) {
866 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
870 if (oidp
->oid_handler
) {
874 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
875 if (!sysctl_sysctl_next_ls(lsp
, name
+ 1, namelen
- 1, next
+ 1,
876 len
, level
+ 1, oidpp
)) {
889 * Description: This is an iterator function designed to iterate the oid tree
890 * and provide a list of OIDs for use by the user space "sysctl"
895 * Parameters: oidp __unused
896 * arg1 Pointer to start OID name
897 * arg2 Start OID name length
898 * req Pointer to user request buffer
901 * ENOENT Reached end of OID space
902 * SYSCTL_OUT:EPERM Permission denied
903 * SYSCTL_OUT:EFAULT Bad user supplied buffer
904 * SYSCTL_OUT:??? Return value from user function
905 * for SYSCTL_PROC leaf node
907 * Implict: Contents of user request buffer, modified
909 * Locks: Acquires and then releases a read lock on the
910 * sysctl_geometry_lock
912 * Notes: SPI (System Programming Interface); this is subject to change
913 * and may not be relied upon by third party applications; use
914 * a subprocess to communicate with the "sysctl" command line
915 * command instead, if you believe you need this functionality.
916 * Preferrably, use sysctlbyname() instead.
918 * This function differs from other sysctl functions in that
919 * it can not take an output buffer length of 0 to determine the
920 * space which will be required. It is suggested that the buffer
921 * length be PATH_MAX, and that authors of new sysctl's refrain
922 * from exceeding this string length.
925 sysctl_sysctl_next(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
926 struct sysctl_req
*req
)
928 int *name
= (int *) arg1
;
929 u_int namelen
= arg2
;
931 struct sysctl_oid
*oid
;
932 struct sysctl_oid_list
*lsp
= &sysctl__children
;
933 int newoid
[CTL_MAXNAME
] = {};
935 lck_rw_lock_shared(sysctl_geometry_lock
);
936 i
= sysctl_sysctl_next_ls(lsp
, name
, namelen
, newoid
, &j
, 1, &oid
);
937 lck_rw_done(sysctl_geometry_lock
);
941 error
= SYSCTL_OUT(req
, newoid
, j
* sizeof(int));
945 SYSCTL_NODE(_sysctl
, 2, next
, CTLFLAG_RD
| CTLFLAG_LOCKED
, sysctl_sysctl_next
, "");
950 * Description: Support function for use by sysctl_sysctl_name2oid(); looks
951 * up an OID name given a string name.
953 * Parameters: name NULL terminated string name
954 * oid Pointer to receive OID name
955 * len Pointer to receive OID length
956 * pointer value (see "Notes")
959 * ENOENT Entry not found
961 * Implicit: *oid Modified to contain OID value
962 * *len Modified to contain OID length
964 * Locks: Assumes sysctl_geometry_lock is held prior to calling
967 name2oid(char *name
, int *oid
, size_t *len
)
970 struct sysctl_oid
*oidp
;
971 struct sysctl_oid_list
*lsp
= &sysctl__children
;
978 p
= name
+ strlen(name
) - 1;
985 for (p
= name
; *p
&& *p
!= '.'; p
++) {
993 oidp
= SLIST_FIRST(lsp
);
995 while (oidp
&& *len
< CTL_MAXNAME
) {
996 if (strcmp(name
, oidp
->oid_name
)) {
997 oidp
= SLIST_NEXT(oidp
, oid_link
);
1000 *oid
++ = oidp
->oid_number
;
1007 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
) {
1011 if (oidp
->oid_handler
) {
1015 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
1016 oidp
= SLIST_FIRST(lsp
);
1017 *p
= i
; /* restore */
1019 for (p
= name
; *p
&& *p
!= '.'; p
++) {
1031 * sysctl_sysctl_name2oid
1033 * Description: Translate a string name to an OID name value; this is used by
1034 * the sysctlbyname() function as well as by the "sysctl" command
1039 * Parameters: oidp __unused
1042 * req Request structure
1044 * Returns: ENOENT Input length too short
1045 * ENAMETOOLONG Input length too long
1046 * ENOMEM Could not allocate work area
1047 * SYSCTL_IN/OUT:EPERM Permission denied
1048 * SYSCTL_IN/OUT:EFAULT Bad user supplied buffer
1049 * SYSCTL_IN/OUT:??? Return value from user function
1050 * name2oid:ENOENT Not found
1052 * Implicit: *req Contents of request, modified
1054 * Locks: Acquires and then releases a read lock on the
1055 * sysctl_geometry_lock
1057 * Notes: SPI (System Programming Interface); this is subject to change
1058 * and may not be relied upon by third party applications; use
1059 * a subprocess to communicate with the "sysctl" command line
1060 * command instead, if you believe you need this functionality.
1061 * Preferrably, use sysctlbyname() instead.
1063 * This function differs from other sysctl functions in that
1064 * it can not take an output buffer length of 0 to determine the
1065 * space which will be required. It is suggested that the buffer
1066 * length be PATH_MAX, and that authors of new sysctl's refrain
1067 * from exceeding this string length.
1070 sysctl_sysctl_name2oid(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
,
1071 __unused
int arg2
, struct sysctl_req
*req
)
1074 int error
, oid
[CTL_MAXNAME
] = {};
1075 size_t len
= 0; /* set by name2oid() */
1077 if (req
->newlen
< 1) {
1080 if (req
->newlen
>= MAXPATHLEN
) { /* XXX arbitrary, undocumented */
1081 return ENAMETOOLONG
;
1084 MALLOC(p
, char *, req
->newlen
+ 1, M_TEMP
, M_WAITOK
);
1089 error
= SYSCTL_IN(req
, p
, req
->newlen
);
1095 p
[req
->newlen
] = '\0';
1098 * Note: We acquire and release the geometry lock here to
1099 * avoid making name2oid needlessly complex.
1101 lck_rw_lock_shared(sysctl_geometry_lock
);
1102 error
= name2oid(p
, oid
, &len
);
1103 lck_rw_done(sysctl_geometry_lock
);
1111 error
= SYSCTL_OUT(req
, oid
, len
* sizeof *oid
);
1115 SYSCTL_PROC(_sysctl
, 3, name2oid
, CTLFLAG_RW
| CTLFLAG_ANYBODY
| CTLFLAG_KERN
| CTLFLAG_LOCKED
, 0, 0,
1116 sysctl_sysctl_name2oid
, "I", "");
1119 * sysctl_sysctl_oidfmt
1121 * Description: For a given OID name, determine the format of the data which
1122 * is associated with it. This is used by the "sysctl" command
1127 * Parameters: oidp __unused
1128 * arg1 The OID name to look up
1129 * arg2 The length of the OID name
1130 * req Pointer to user request buffer
1132 * Returns: 0 Success
1133 * EISDIR Malformed request
1134 * ENOENT No such OID name
1135 * SYSCTL_OUT:EPERM Permission denied
1136 * SYSCTL_OUT:EFAULT Bad user supplied buffer
1137 * SYSCTL_OUT:??? Return value from user function
1139 * Implict: Contents of user request buffer, modified
1141 * Locks: Acquires and then releases a read lock on the
1142 * sysctl_geometry_lock
1144 * Notes: SPI (System Programming Interface); this is subject to change
1145 * and may not be relied upon by third party applications; use
1146 * a subprocess to communicate with the "sysctl" command line
1147 * command instead, if you believe you need this functionality.
1149 * This function differs from other sysctl functions in that
1150 * it can not take an output buffer length of 0 to determine the
1151 * space which will be required. It is suggested that the buffer
1152 * length be PATH_MAX, and that authors of new sysctl's refrain
1153 * from exceeding this string length.
1156 sysctl_sysctl_oidfmt(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
1157 struct sysctl_req
*req
)
1159 int *name
= (int *) arg1
;
1160 int error
= ENOENT
; /* default error: not found */
1161 u_int namelen
= arg2
;
1163 struct sysctl_oid
*oid
;
1164 struct sysctl_oid_list
*lsp
= &sysctl__children
;
1166 lck_rw_lock_shared(sysctl_geometry_lock
);
1167 oid
= SLIST_FIRST(lsp
);
1170 while (oid
&& indx
< CTL_MAXNAME
) {
1171 if (oid
->oid_number
== name
[indx
]) {
1173 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
1174 if (oid
->oid_handler
) {
1177 if (indx
== namelen
) {
1180 lsp
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
1181 oid
= SLIST_FIRST(lsp
);
1183 if (indx
!= namelen
) {
1190 oid
= SLIST_NEXT(oid
, oid_link
);
1197 if (!oid
->oid_fmt
) {
1200 error
= SYSCTL_OUT(req
,
1201 &oid
->oid_kind
, sizeof(oid
->oid_kind
));
1203 error
= SYSCTL_OUT(req
, oid
->oid_fmt
,
1204 strlen(oid
->oid_fmt
) + 1);
1207 lck_rw_done(sysctl_geometry_lock
);
1211 SYSCTL_NODE(_sysctl
, 4, oidfmt
, CTLFLAG_RD
| CTLFLAG_LOCKED
, sysctl_sysctl_oidfmt
, "");
1215 * Default "handler" functions.
1219 * Handle an int, signed or unsigned.
1221 * a variable: point arg1 at it.
1222 * a constant: pass it in arg2.
1226 sysctl_handle_int(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
1227 struct sysctl_req
*req
)
1229 return sysctl_io_number(req
, arg1
? *(int*)arg1
: arg2
, sizeof(int), arg1
, NULL
);
1233 * Handle a long, signed or unsigned. arg1 points to it.
1237 sysctl_handle_long(__unused
struct sysctl_oid
*oidp
, void *arg1
,
1238 __unused
int arg2
, struct sysctl_req
*req
)
1243 return sysctl_io_number(req
, *(long*)arg1
, sizeof(long), arg1
, NULL
);
1247 * Handle a quad, signed or unsigned. arg1 points to it.
1251 sysctl_handle_quad(__unused
struct sysctl_oid
*oidp
, void *arg1
,
1252 __unused
int arg2
, struct sysctl_req
*req
)
1257 return sysctl_io_number(req
, *(long long*)arg1
, sizeof(long long), arg1
, NULL
);
1261 * Expose an int value as a quad.
1263 * This interface allows us to support interfaces defined
1264 * as using quad values while the implementation is still
1268 sysctl_handle_int2quad(__unused
struct sysctl_oid
*oidp
, void *arg1
,
1269 __unused
int arg2
, struct sysctl_req
*req
)
1278 val
= (long long)*(int *)arg1
;
1279 error
= SYSCTL_OUT(req
, &val
, sizeof(long long));
1281 if (error
|| !req
->newptr
) {
1285 error
= SYSCTL_IN(req
, &val
, sizeof(long long));
1288 * Value must be representable; check by
1289 * casting and then casting back.
1292 if ((long long)newval
!= val
) {
1295 *(int *)arg1
= newval
;
1302 * Handle our generic '\0' terminated 'C' string.
1304 * a variable string: point arg1 at it, arg2 is max length.
1305 * a constant string: point arg1 at it, arg2 is zero.
1309 sysctl_handle_string( __unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
1310 struct sysctl_req
*req
)
1312 return sysctl_io_string(req
, arg1
, arg2
, 0, NULL
);
1316 * Handle any kind of opaque data.
1317 * arg1 points to it, arg2 is the size.
1321 sysctl_handle_opaque(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
1322 struct sysctl_req
*req
)
1324 return sysctl_io_opaque(req
, arg1
, arg2
, NULL
);
1328 * Transfer functions to/from kernel space.
1331 sysctl_old_kernel(struct sysctl_req
*req
, const void *p
, size_t l
)
1337 if (i
> req
->oldlen
- req
->oldidx
) {
1338 i
= req
->oldlen
- req
->oldidx
;
1341 bcopy((const void*)p
, CAST_DOWN(char *, (req
->oldptr
+ req
->oldidx
)), i
);
1345 if (req
->oldptr
&& i
!= l
) {
1352 sysctl_new_kernel(struct sysctl_req
*req
, void *p
, size_t l
)
1357 if (req
->newlen
- req
->newidx
< l
) {
1360 bcopy(CAST_DOWN(char *, (req
->newptr
+ req
->newidx
)), p
, l
);
1366 kernel_sysctl(struct proc
*p
, int *name
, size_t namelen
, void *old
, size_t *oldlenp
, void *new, size_t newlen
)
1369 struct sysctl_req req
;
1372 * Construct request.
1374 bzero(&req
, sizeof req
);
1377 req
.oldlen
= *oldlenp
;
1380 req
.oldptr
= CAST_USER_ADDR_T(old
);
1383 req
.newlen
= newlen
;
1384 req
.newptr
= CAST_USER_ADDR_T(new);
1386 req
.oldfunc
= sysctl_old_kernel
;
1387 req
.newfunc
= sysctl_new_kernel
;
1390 /* make the request */
1391 error
= sysctl_root(TRUE
, FALSE
, NULL
, 0, name
, namelen
, &req
);
1393 if (error
&& error
!= ENOMEM
) {
1398 *oldlenp
= req
.oldidx
;
1405 * Transfer function to/from user space.
1408 sysctl_old_user(struct sysctl_req
*req
, const void *p
, size_t l
)
1414 if (req
->oldlen
- req
->oldidx
< l
) {
1418 if (i
> req
->oldlen
- req
->oldidx
) {
1419 i
= req
->oldlen
- req
->oldidx
;
1422 error
= copyout((const void*)p
, (req
->oldptr
+ req
->oldidx
), i
);
1429 if (req
->oldptr
&& i
< l
) {
1436 sysctl_new_user(struct sysctl_req
*req
, void *p
, size_t l
)
1443 if (req
->newlen
- req
->newidx
< l
) {
1446 error
= copyin((req
->newptr
+ req
->newidx
), p
, l
);
1452 * Traverse our tree, and find the right node, execute whatever it points
1453 * at, and return the resulting error code.
1457 sysctl_root(boolean_t from_kernel
, boolean_t string_is_canonical
, char *namestring
, size_t namestringlen
, int *name
, size_t namelen
, struct sysctl_req
*req
)
1461 struct sysctl_oid
*oid
;
1462 struct sysctl_oid_list
*lsp
= &sysctl__children
;
1463 sysctl_handler_t oid_handler
= NULL
;
1465 boolean_t unlocked_node_found
= FALSE
;
1466 boolean_t namestring_started
= FALSE
;
1468 /* Get the read lock on the geometry */
1469 lck_rw_lock_shared(sysctl_geometry_lock
);
1471 if (string_is_canonical
) {
1472 /* namestring is actually canonical, name/namelen needs to be populated */
1473 error
= name2oid(namestring
, name
, &namelen
);
1479 oid
= SLIST_FIRST(lsp
);
1482 while (oid
&& indx
< CTL_MAXNAME
) {
1483 if (oid
->oid_number
== name
[indx
]) {
1484 if (!from_kernel
&& !string_is_canonical
) {
1485 if (namestring_started
) {
1486 if (strlcat(namestring
, ".", namestringlen
) >= namestringlen
) {
1487 error
= ENAMETOOLONG
;
1492 if (strlcat(namestring
, oid
->oid_name
, namestringlen
) >= namestringlen
) {
1493 error
= ENAMETOOLONG
;
1496 namestring_started
= TRUE
;
1500 if (!(oid
->oid_kind
& CTLFLAG_LOCKED
)) {
1501 unlocked_node_found
= TRUE
;
1503 if (oid
->oid_kind
& CTLFLAG_NOLOCK
) {
1507 * For SYSCTL_PROC() functions which are for sysctl's
1508 * which have parameters at the end of their OID
1509 * space, you need to OR CTLTYPE_NODE into their
1512 * NOTE: For binary backward compatibility ONLY! Do
1513 * NOT add new sysctl's that do this! Existing
1514 * sysctl's which do this will eventually have
1515 * compatibility code in user space, and this method
1516 * will become unsupported.
1518 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
1519 if (oid
->oid_handler
) {
1522 if (indx
== namelen
) {
1527 lsp
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
1528 oid
= SLIST_FIRST(lsp
);
1530 if (indx
!= namelen
) {
1537 oid
= SLIST_NEXT(oid
, oid_link
);
1545 * indx is the index of the first remaining OID name,
1546 * for sysctls that take them as arguments
1548 if (!from_kernel
&& !string_is_canonical
&& (indx
< namelen
)) {
1552 for (indx2
= indx
; indx2
< namelen
; indx2
++) {
1553 snprintf(tempbuf
, sizeof(tempbuf
), "%d", name
[indx2
]);
1555 if (namestring_started
) {
1556 if (strlcat(namestring
, ".", namestringlen
) >= namestringlen
) {
1557 error
= ENAMETOOLONG
;
1562 if (strlcat(namestring
, tempbuf
, namestringlen
) >= namestringlen
) {
1563 error
= ENAMETOOLONG
;
1566 namestring_started
= TRUE
;
1570 /* If writing isn't allowed */
1571 if (req
->newptr
&& (!(oid
->oid_kind
& CTLFLAG_WR
) ||
1572 ((oid
->oid_kind
& CTLFLAG_SECURE
) && securelevel
> 0))) {
1578 * If we're inside the kernel, the OID must be marked as kernel-valid.
1580 if (from_kernel
&& !(oid
->oid_kind
& CTLFLAG_KERN
)) {
1586 * This is where legacy enforcement of permissions occurs. If the
1587 * flag does not say CTLFLAG_ANYBODY, then we prohibit anyone but
1588 * root from writing new values down. If local enforcement happens
1589 * at the leaf node, then it needs to be set as CTLFLAG_ANYBODY. In
1590 * addition, if the leaf node is set this way, then in order to do
1591 * specific enforcement, it has to be of type SYSCTL_PROC.
1593 if (!(oid
->oid_kind
& CTLFLAG_ANYBODY
) &&
1594 req
->newptr
&& req
->p
&&
1595 (error
= proc_suser(req
->p
))) {
1600 * sysctl_unregister_oid() may change the handler value, so grab it
1603 oid_handler
= oid
->oid_handler
;
1610 * Reference the OID and drop the geometry lock; this prevents the
1611 * OID from being deleted out from under the handler call, but does
1612 * not prevent other calls into handlers or calls to manage the
1613 * geometry elsewhere from blocking...
1615 OSAddAtomic(1, &oid
->oid_refcnt
);
1617 lck_rw_done(sysctl_geometry_lock
);
1621 error
= mac_system_check_sysctlbyname(kauth_cred_get(),
1636 * ...however, we still have to grab the mutex for those calls which
1637 * may be into code whose reentrancy is protected by it.
1639 if (unlocked_node_found
) {
1640 lck_mtx_lock(sysctl_unlocked_node_lock
);
1643 #if defined(HAS_APPLE_PAC)
1645 * oid_handler is signed address-discriminated by sysctl_register_oid().
1647 oid_handler
= ptrauth_auth_and_resign(oid_handler
,
1648 ptrauth_key_function_pointer
,
1649 ptrauth_blend_discriminator(&oid
->oid_handler
,
1650 os_hash_kernel_pointer(oid
->oid_arg1
)),
1651 ptrauth_key_function_pointer
,
1652 ptrauth_function_pointer_type_discriminator(typeof(oid_handler
)));
1653 #endif /* defined(HAS_APPLE_PAC) */
1655 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
1656 i
= oid_handler(oid
, name
+ indx
, (int)(namelen
- indx
), req
);
1658 i
= oid_handler(oid
, oid
->oid_arg1
, oid
->oid_arg2
, req
);
1662 if (unlocked_node_found
) {
1663 lck_mtx_unlock(sysctl_unlocked_node_lock
);
1667 /* only used from another CONFIG_MACF block */
1672 * This is tricky... we re-grab the geometry lock in order to drop
1673 * the reference and wake on the address; since the geometry
1674 * lock is a reader/writer lock rather than a mutex, we have to
1675 * wake on all apparent 1->0 transitions. This abuses the drop
1676 * after the reference decrement in order to wake any lck_rw_sleep()
1677 * in progress in sysctl_unregister_oid() that slept because of a
1678 * non-zero reference count.
1680 * Note: OSAddAtomic() is defined to return the previous value;
1681 * we use this and the fact that the lock itself is a
1682 * barrier to avoid waking every time through on "hot"
1685 lck_rw_lock_shared(sysctl_geometry_lock
);
1686 if (OSAddAtomic(-1, &oid
->oid_refcnt
) == 1) {
1687 wakeup(&oid
->oid_refcnt
);
1691 lck_rw_done(sysctl_geometry_lock
);
1696 sysctl_create_user_req(struct sysctl_req
*req
, struct proc
*p
, user_addr_t oldp
,
1697 size_t oldlen
, user_addr_t newp
, size_t newlen
)
1699 bzero(req
, sizeof(*req
));
1703 req
->oldlen
= oldlen
;
1707 req
->newlen
= newlen
;
1711 req
->oldfunc
= sysctl_old_user
;
1712 req
->newfunc
= sysctl_new_user
;
1719 sysctl(proc_t p
, struct sysctl_args
*uap
, __unused
int32_t *retval
)
1721 int error
, new_error
;
1722 size_t oldlen
= 0, newlen
;
1723 int name
[CTL_MAXNAME
];
1724 struct sysctl_req req
;
1726 size_t namestringlen
= MAXPATHLEN
;
1729 * all top-level sysctl names are non-terminal
1731 if (uap
->namelen
> CTL_MAXNAME
|| uap
->namelen
< 2) {
1734 error
= copyin(uap
->name
, &name
[0], uap
->namelen
* sizeof(int));
1739 AUDIT_ARG(ctlname
, name
, uap
->namelen
);
1741 if (uap
->newlen
> SIZE_T_MAX
) {
1744 newlen
= (size_t)uap
->newlen
;
1746 if (uap
->oldlenp
!= USER_ADDR_NULL
) {
1747 uint64_t oldlen64
= fuulong(uap
->oldlenp
);
1750 * If more than 4G, clamp to 4G
1752 if (oldlen64
> SIZE_T_MAX
) {
1753 oldlen
= SIZE_T_MAX
;
1755 oldlen
= (size_t)oldlen64
;
1759 sysctl_create_user_req(&req
, p
, uap
->old
, oldlen
, uap
->new, newlen
);
1761 /* Guess that longest length for the passed-in MIB, if we can be more aggressive than MAXPATHLEN */
1762 if (uap
->namelen
== 2) {
1763 if (name
[0] == CTL_KERN
&& name
[1] < KERN_MAXID
) {
1764 namestringlen
= 32; /* "kern.speculative_reads_disabled" */
1765 } else if (name
[0] == CTL_HW
&& name
[1] < HW_MAXID
) {
1766 namestringlen
= 32; /* "hw.cachelinesize_compat" */
1770 MALLOC(namestring
, char *, namestringlen
, M_TEMP
, M_WAITOK
);
1776 error
= userland_sysctl(FALSE
, namestring
, namestringlen
, name
, uap
->namelen
, &req
, &oldlen
);
1778 FREE(namestring
, M_TEMP
);
1780 if ((error
) && (error
!= ENOMEM
)) {
1785 if (uap
->oldlenp
!= USER_ADDR_NULL
) {
1787 * Only overwrite the old error value on a new error
1789 new_error
= suulong(uap
->oldlenp
, oldlen
);
1799 // sysctlbyname is also exported as KPI to kexts
1800 // and the syscall name cannot conflict with it
1802 sys_sysctlbyname(proc_t p
, struct sysctlbyname_args
*uap
, __unused
int32_t *retval
)
1804 int error
, new_error
;
1805 size_t oldlen
= 0, newlen
;
1808 struct sysctl_req req
;
1809 int oid
[CTL_MAXNAME
];
1811 if (uap
->namelen
>= MAXPATHLEN
) { /* XXX arbitrary, undocumented */
1812 return ENAMETOOLONG
;
1814 namelen
= (size_t)uap
->namelen
;
1816 MALLOC(name
, char *, namelen
+ 1, M_TEMP
, M_WAITOK
);
1821 error
= copyin(uap
->name
, name
, namelen
);
1826 name
[namelen
] = '\0';
1829 * AUDIT_ARG(ctlname, name, uap->namelen);
1832 if (uap
->newlen
> SIZE_T_MAX
) {
1836 newlen
= (size_t)uap
->newlen
;
1838 if (uap
->oldlenp
!= USER_ADDR_NULL
) {
1839 uint64_t oldlen64
= fuulong(uap
->oldlenp
);
1842 * If more than 4G, clamp to 4G
1844 if (oldlen64
> SIZE_T_MAX
) {
1845 oldlen
= SIZE_T_MAX
;
1847 oldlen
= (size_t)oldlen64
;
1851 sysctl_create_user_req(&req
, p
, uap
->old
, oldlen
, uap
->new, newlen
);
1853 error
= userland_sysctl(TRUE
, name
, namelen
+ 1, oid
, CTL_MAXNAME
, &req
, &oldlen
);
1857 if ((error
) && (error
!= ENOMEM
)) {
1861 if (uap
->oldlenp
!= USER_ADDR_NULL
) {
1863 * Only overwrite the old error value on a new error
1865 new_error
= suulong(uap
->oldlenp
, oldlen
);
1876 * This is used from various compatibility syscalls too. That's why name
1877 * must be in kernel space.
1880 userland_sysctl(boolean_t string_is_canonical
,
1881 char *namestring
, size_t namestringlen
,
1882 int *name
, u_int namelen
, struct sysctl_req
*req
,
1886 struct sysctl_req req2
;
1889 /* if EAGAIN, reset output cursor */
1891 if (!string_is_canonical
) {
1892 namestring
[0] = '\0';
1895 error
= sysctl_root(FALSE
, string_is_canonical
, namestring
, namestringlen
, name
, namelen
, &req2
);
1896 } while (error
== EAGAIN
);
1898 if (error
&& error
!= ENOMEM
) {
1903 if (req2
.oldptr
&& req2
.oldidx
> req2
.oldlen
) {
1904 *retval
= req2
.oldlen
;
1906 *retval
= req2
.oldidx
;
1913 * Kernel versions of the userland sysctl helper functions.
1915 * These allow sysctl to be used in the same fashion in both
1916 * userland and the kernel.
1918 * Note that some sysctl handlers use copyin/copyout, which
1919 * may not work correctly.
1921 * The "sysctlbyname" KPI for use by kexts is aliased to this function.
1925 kernel_sysctlbyname(const char *name
, void *oldp
, size_t *oldlenp
, void *newp
, size_t newlen
)
1927 int oid
[CTL_MAXNAME
];
1928 int name2mib_oid
[2];
1932 /* look up the OID with magic service node */
1933 name2mib_oid
[0] = 0;
1934 name2mib_oid
[1] = 3;
1936 oidlen
= sizeof(oid
);
1937 error
= kernel_sysctl(current_proc(), name2mib_oid
, 2, oid
, &oidlen
, __DECONST(void *, name
), strlen(name
));
1938 oidlen
/= sizeof(int);
1939 if (oidlen
> UINT_MAX
) {
1943 /* now use the OID */
1945 error
= kernel_sysctl(current_proc(), oid
, (u_int
)oidlen
, oldp
, oldlenp
, newp
, newlen
);