]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_newsysctl.c
xnu-6153.81.5.tar.gz
[apple/xnu.git] / bsd / kern / kern_newsysctl.c
CommitLineData
1c79356b 1/*
cb323159 2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
b0d623f7
A
27 *
28 *
1c79356b
A
29 * Copyright (c) 1982, 1986, 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * This code is derived from software contributed to Berkeley by
33 * Mike Karels at Berkeley Software Design, Inc.
34 *
35 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
36 * project, to make these variables more userfriendly.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
67 */
68
69
70#include <sys/param.h>
71#include <sys/buf.h>
72#include <sys/kernel.h>
73#include <sys/sysctl.h>
74#include <sys/malloc.h>
91447636 75#include <sys/proc_internal.h>
fe8ab488 76#include <sys/kauth.h>
1c79356b 77#include <sys/systm.h>
fe8ab488 78#include <sys/sysproto.h>
1c79356b 79
b0d623f7 80#include <security/audit/audit.h>
39037602 81#include <pexpert/pexpert.h>
e5568f75 82
5ba3f43e
A
83#if CONFIG_MACF
84#include <security/mac_framework.h>
85#endif
86
cb323159
A
87#if defined(HAS_APPLE_PAC)
88#include <ptrauth.h>
89#endif /* defined(HAS_APPLE_PAC) */
d9a64523 90
fe8ab488 91lck_grp_t * sysctl_lock_group = NULL;
2d21ac55 92lck_rw_t * sysctl_geometry_lock = NULL;
fe8ab488 93lck_mtx_t * sysctl_unlocked_node_lock = NULL;
1c79356b 94
6d2010ae
A
95/*
96 * Conditionally allow dtrace to see these functions for debugging purposes.
97 */
98#ifdef STATIC
99#undef STATIC
100#endif
101#if 0
0a7de745 102#define STATIC
6d2010ae
A
103#else
104#define STATIC static
105#endif
106
107/* forward declarations of static functions */
6d2010ae
A
108STATIC void sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i);
109STATIC int sysctl_sysctl_debug(struct sysctl_oid *oidp, void *arg1,
0a7de745 110 int arg2, struct sysctl_req *req);
6d2010ae 111STATIC int sysctl_sysctl_name(struct sysctl_oid *oidp, void *arg1,
0a7de745
A
112 int arg2, struct sysctl_req *req);
113STATIC 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);
6d2010ae
A
116STATIC int sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l);
117STATIC int sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l);
0a7de745 118STATIC int name2oid(char *name, int *oid, u_int *len);
6d2010ae
A
119STATIC int sysctl_sysctl_name2oid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
120STATIC int sysctl_sysctl_next(struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 121 struct sysctl_req *req);
6d2010ae 122STATIC int sysctl_sysctl_oidfmt(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
6d2010ae
A
123STATIC int sysctl_old_user(struct sysctl_req *req, const void *p, size_t l);
124STATIC int sysctl_new_user(struct sysctl_req *req, void *p, size_t l);
1c79356b 125
fe8ab488 126STATIC void sysctl_create_user_req(struct sysctl_req *req, struct proc *p, user_addr_t oldp,
0a7de745 127 size_t oldlen, user_addr_t newp, size_t newlen);
fe8ab488 128STATIC int sysctl_root(boolean_t from_kernel, boolean_t string_is_canonical, char *namestring, size_t namestringlen, int *name, u_int namelen, struct sysctl_req *req);
1c79356b 129
0a7de745
A
130int kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen);
131int kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
132int userland_sysctl(boolean_t string_is_canonical,
133 char *namestring, size_t namestringlen,
134 int *name, u_int namelen, struct sysctl_req *req,
135 size_t *retval);
1c79356b
A
136
137struct sysctl_oid_list sysctl__children; /* root list */
138
139/*
140 * Initialization of the MIB tree.
141 *
142 * Order by number in each list.
143 */
144
6d2010ae
A
145void
146sysctl_register_oid(struct sysctl_oid *new_oidp)
1c79356b 147{
6d2010ae
A
148 struct sysctl_oid *oidp = NULL;
149 struct sysctl_oid_list *parent = new_oidp->oid_parent;
1c79356b
A
150 struct sysctl_oid *p;
151 struct sysctl_oid *q;
152 int n;
6d2010ae
A
153
154 /*
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).
159 */
160 if (!(new_oidp->oid_kind & CTLFLAG_OID2)) {
161 /*
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.
164 */
165 MALLOC(oidp, struct sysctl_oid *, sizeof(*oidp), M_TEMP, M_WAITOK | M_ZERO);
0a7de745
A
166 if (oidp == NULL) {
167 return; /* reject: no memory */
168 }
6d2010ae
A
169 /*
170 * Copy the structure only through the oid_fmt field, which
171 * is the last field in a non-OID2 OID structure.
172 *
173 * Note: We may want to set the oid_descr to the
174 * oid_name (or "") at some future date.
175 */
176 memcpy(oidp, new_oidp, offsetof(struct sysctl_oid, oid_descr));
177 } else {
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 */
182 oidp = new_oidp;
183 break;
184 default:
0a7de745 185 return; /* rejects unknown version */
6d2010ae
A
186 }
187 }
43866e37 188
2d21ac55
A
189 /* Get the write lock to modify the geometry */
190 lck_rw_lock_exclusive(sysctl_geometry_lock);
191
1c79356b
A
192 /*
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
2d21ac55 195 * OID_AUTO_START to leave space for pre-assigned oid numbers.
1c79356b 196 */
1c79356b 197 if (oidp->oid_number == OID_AUTO) {
2d21ac55
A
198 /* First, find the highest oid in the parent list >OID_AUTO_START-1 */
199 n = OID_AUTO_START;
1c79356b 200 SLIST_FOREACH(p, parent, oid_link) {
0a7de745 201 if (p->oid_number > n) {
1c79356b 202 n = p->oid_number;
0a7de745 203 }
1c79356b
A
204 }
205 oidp->oid_number = n + 1;
6d2010ae
A
206 /*
207 * Reflect the number in an llocated OID into the template
208 * of the caller for sysctl_unregister_oid() compares.
209 */
0a7de745 210 if (oidp != new_oidp) {
6d2010ae 211 new_oidp->oid_number = oidp->oid_number;
0a7de745 212 }
1c79356b
A
213 }
214
cb323159
A
215#if defined(HAS_APPLE_PAC)
216 if (oidp->oid_handler) {
217 /*
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
221 * succeeds.
222 */
223 if (__builtin_expect(!*(uintptr_t*)ptrauth_auth_data((void*)
224 oidp->oid_handler, ptrauth_key_function_pointer, 0), 0)) {
225 /*
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
229 * with a panic).
230 */
231 __builtin_trap();
232 }
233 /*
234 * Sign oid_handler address-discriminated upon installation to make it
235 * harder to replace with an arbitrary function pointer.
236 */
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")));
241 }
242#endif /* defined(HAS_APPLE_PAC) */
d9a64523 243
1c79356b
A
244 /*
245 * Insert the oid into the parent's list in order.
246 */
247 q = NULL;
248 SLIST_FOREACH(p, parent, oid_link) {
cb323159
A
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) {
1c79356b 252 break;
0a7de745 253 }
1c79356b
A
254 q = p;
255 }
0a7de745 256 if (q) {
1c79356b 257 SLIST_INSERT_AFTER(q, oidp, oid_link);
0a7de745 258 } else {
1c79356b 259 SLIST_INSERT_HEAD(parent, oidp, oid_link);
0a7de745 260 }
43866e37 261
2d21ac55
A
262 /* Release the write lock */
263 lck_rw_unlock_exclusive(sysctl_geometry_lock);
1c79356b
A
264}
265
6d2010ae
A
266void
267sysctl_unregister_oid(struct sysctl_oid *oidp)
1c79356b 268{
0a7de745
A
269 struct sysctl_oid *removed_oidp = NULL; /* OID removed from tree */
270 struct sysctl_oid *old_oidp = NULL; /* OID compatibility copy */
2d21ac55
A
271
272 /* Get the write lock to modify the geometry */
273 lck_rw_lock_exclusive(sysctl_geometry_lock);
274
6d2010ae
A
275 if (!(oidp->oid_kind & CTLFLAG_OID2)) {
276 /*
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.
281 */
282 SLIST_FOREACH(old_oidp, oidp->oid_parent, oid_link) {
0a7de745
A
283 if (!memcmp(&oidp->oid_number, &old_oidp->oid_number, (offsetof(struct sysctl_oid, oid_descr) - offsetof(struct sysctl_oid, oid_number)))) {
284 break;
285 }
6d2010ae
A
286 }
287 if (old_oidp != NULL) {
288 SLIST_REMOVE(old_oidp->oid_parent, old_oidp, sysctl_oid, oid_link);
289 removed_oidp = old_oidp;
290 }
291 } else {
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);
297 removed_oidp = oidp;
298 break;
299 default:
0a7de745
A
300 /* XXX: Can't happen; probably tree coruption.*/
301 break; /* rejects unknown version */
6d2010ae
A
302 }
303 }
304
cb323159
A
305#if defined(HAS_APPLE_PAC)
306 if (removed_oidp && removed_oidp->oid_handler && old_oidp == NULL) {
307 /*
308 * Revert address-discriminated signing performed by
309 * sysctl_register_oid() (in case this oid is registered again).
310 */
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")));
315 /*
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
319 * succeeds.
320 */
321 if (__builtin_expect(!*(uintptr_t*)ptrauth_auth_data((void*)
322 removed_oidp->oid_handler, ptrauth_key_function_pointer, 0), 0)) {
323 /*
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
327 * with a panic).
328 */
329 __builtin_trap();
330 }
331 }
332#endif /* defined(HAS_APPLE_PAC) */
d9a64523 333
6d2010ae
A
334 /*
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.
339 *
340 * Note: oidp could be NULL if it wasn't found.
341 */
0a7de745 342 while (removed_oidp && removed_oidp->oid_refcnt) {
6d2010ae
A
343 lck_rw_sleep(sysctl_geometry_lock, LCK_SLEEP_EXCLUSIVE, &removed_oidp->oid_refcnt, THREAD_UNINT);
344 }
2d21ac55
A
345
346 /* Release the write lock */
347 lck_rw_unlock_exclusive(sysctl_geometry_lock);
348
6d2010ae
A
349 /* If it was allocated, free it after dropping the lock */
350 if (old_oidp != NULL) {
351 FREE(old_oidp, M_TEMP);
352 }
1c79356b
A
353}
354
355/*
356 * Bulk-register all the oids in a linker_set.
357 */
6d2010ae
A
358void
359sysctl_register_set(const char *set)
1c79356b 360{
2d21ac55
A
361 struct sysctl_oid **oidpp, *oidp;
362
b0d623f7 363 LINKER_SET_FOREACH(oidpp, struct sysctl_oid **, set) {
2d21ac55
A
364 oidp = *oidpp;
365 if (!(oidp->oid_kind & CTLFLAG_NOAUTO)) {
0a7de745 366 sysctl_register_oid(oidp);
2d21ac55
A
367 }
368 }
1c79356b
A
369}
370
6d2010ae
A
371void
372sysctl_unregister_set(const char *set)
1c79356b 373{
2d21ac55
A
374 struct sysctl_oid **oidpp, *oidp;
375
b0d623f7 376 LINKER_SET_FOREACH(oidpp, struct sysctl_oid **, set) {
2d21ac55
A
377 oidp = *oidpp;
378 if (!(oidp->oid_kind & CTLFLAG_NOAUTO)) {
0a7de745 379 sysctl_unregister_oid(oidp);
2d21ac55
A
380 }
381 }
1c79356b
A
382}
383
1c79356b 384/*
39037602 385 * Exported in BSDKernel.exports, kept for binary compatibility
1c79356b 386 */
39037602 387#if defined(__x86_64__)
2d21ac55 388void
39037602 389sysctl_register_fixed(void)
2d21ac55 390{
2d21ac55 391}
39037602
A
392#endif
393
394/*
395 * Register the kernel's oids on startup.
396 */
2d21ac55
A
397
398void
39037602 399sysctl_early_init(void)
1c79356b 400{
39037602
A
401 /*
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.
406 */
407
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);
411
412 sysctl_register_set("__sysctl_set");
cb323159 413 sysctl_load_devicetree_entries();
1c79356b
A
414}
415
416/*
2d21ac55
A
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.).
1c79356b 422 */
1c79356b 423
2d21ac55 424int
0a7de745
A
425sysctl_io_number(struct sysctl_req *req, long long bigValue, size_t valueSize, void *pValue, int *changed)
426{
427 int smallValue;
428 int error;
2d21ac55 429
0a7de745
A
430 if (changed) {
431 *changed = 0;
432 }
2d21ac55
A
433
434 /*
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
438 * sized.
439 */
440
441 /* 32 bit value expected or 32 bit buffer offered */
b0d623f7
A
442 if (((valueSize == sizeof(int)) ||
443 ((req->oldlen == sizeof(int)) && (valueSize == sizeof(long long))))
0a7de745 444 && (req->oldptr)) {
2d21ac55 445 smallValue = (int)bigValue;
0a7de745
A
446 if ((long long)smallValue != bigValue) {
447 return ERANGE;
448 }
2d21ac55
A
449 error = SYSCTL_OUT(req, &smallValue, sizeof(smallValue));
450 } else {
451 /* any other case is either size-equal or a bug */
452 error = SYSCTL_OUT(req, &bigValue, valueSize);
453 }
454 /* error or nothing to set */
0a7de745
A
455 if (error || !req->newptr) {
456 return error;
457 }
2d21ac55
A
458
459 /* set request for constant */
0a7de745
A
460 if (pValue == NULL) {
461 return EPERM;
462 }
2d21ac55
A
463
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));
0a7de745 468 if (!error) {
2d21ac55 469 *(long long *)pValue = (long long)smallValue;
0a7de745 470 }
2d21ac55
A
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));
474 if (!error) {
475 smallValue = (int)bigValue;
0a7de745
A
476 if ((long long)smallValue != bigValue) {
477 return ERANGE;
478 }
2d21ac55
A
479 *(int *)pValue = smallValue;
480 }
481 } else {
482 /* sizes match, just copy in */
483 error = SYSCTL_IN(req, pValue, valueSize);
484 }
0a7de745 485 if (!error && changed) {
2d21ac55 486 *changed = 1;
0a7de745
A
487 }
488 return error;
2d21ac55
A
489}
490
491int
492sysctl_io_string(struct sysctl_req *req, char *pValue, size_t valueSize, int trunc, int *changed)
1c79356b 493{
2d21ac55
A
494 int error;
495
0a7de745
A
496 if (changed) {
497 *changed = 0;
498 }
2d21ac55 499
0a7de745 500 if (trunc && req->oldptr && req->oldlen && (req->oldlen < strlen(pValue) + 1)) {
2d21ac55
A
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
cb323159 506 * returned string is always nul (ascii '\0') terminated. */
0a7de745 507 error = SYSCTL_OUT(req, pValue, req->oldlen - 1);
2d21ac55 508 if (!error) {
cb323159 509 char c = '\0';
2d21ac55
A
510 error = SYSCTL_OUT(req, &c, 1);
511 }
512 } else {
513 /* Copy string out */
514 error = SYSCTL_OUT(req, pValue, strlen(pValue) + 1);
515 }
516
517 /* error or no new value */
0a7de745
A
518 if (error || !req->newptr) {
519 return error;
520 }
2d21ac55
A
521
522 /* attempt to set read-only value */
0a7de745
A
523 if (valueSize == 0) {
524 return EPERM;
525 }
2d21ac55
A
526
527 /* make sure there's room for the new string */
0a7de745
A
528 if (req->newlen >= valueSize) {
529 return EINVAL;
530 }
2d21ac55 531
cb323159 532 /* copy the string in and force nul termination */
2d21ac55
A
533 error = SYSCTL_IN(req, pValue, req->newlen);
534 pValue[req->newlen] = '\0';
535
0a7de745 536 if (!error && changed) {
2d21ac55 537 *changed = 1;
0a7de745
A
538 }
539 return error;
1c79356b
A
540}
541
0a7de745
A
542int
543sysctl_io_opaque(struct sysctl_req *req, void *pValue, size_t valueSize, int *changed)
2d21ac55
A
544{
545 int error;
546
0a7de745
A
547 if (changed) {
548 *changed = 0;
549 }
2d21ac55
A
550
551 /* Copy blob out */
552 error = SYSCTL_OUT(req, pValue, valueSize);
553
554 /* error or nothing to set */
0a7de745
A
555 if (error || !req->newptr) {
556 return error;
557 }
2d21ac55
A
558
559 error = SYSCTL_IN(req, pValue, valueSize);
560
0a7de745 561 if (!error && changed) {
2d21ac55 562 *changed = 1;
0a7de745
A
563 }
564 return error;
2d21ac55 565}
1c79356b
A
566
567/*
568 * "Staff-functions"
569 *
0a7de745 570 * These functions implement a presently undocumented interface
1c79356b
A
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.
577 *
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.
583 */
584
6d2010ae
A
585/*
586 * sysctl_sysctl_debug_dump_node
587 *
588 * Description: Dump debug information for a given sysctl_oid_list at the
589 * given oid depth out to the kernel log, via printf
590 *
591 * Parameters: l sysctl_oid_list pointer
592 * i current node depth
593 *
594 * Returns: (void)
595 *
596 * Implicit: kernel log, modified
597 *
598 * Locks: Assumes sysctl_geometry_lock is held prior to calling
599 *
600 * Notes: This function may call itself recursively to resolve Node
601 * values, which potentially have an inferioer sysctl_oid_list
602 *
603 * This function is only callable indirectly via the function
604 * sysctl_sysctl_debug()
605 *
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.
609 */
610STATIC void
1c79356b
A
611sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
612{
613 int k;
614 struct sysctl_oid *oidp;
615
616 SLIST_FOREACH(oidp, l, oid_link) {
0a7de745 617 for (k = 0; k < i; k++) {
1c79356b 618 printf(" ");
0a7de745 619 }
1c79356b
A
620
621 printf("%d %s ", oidp->oid_number, oidp->oid_name);
622
6d2010ae 623 printf("%c%c%c",
0a7de745
A
624 oidp->oid_kind & CTLFLAG_LOCKED ? 'L':' ',
625 oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
626 oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
1c79356b 627
0a7de745 628 if (oidp->oid_handler) {
1c79356b 629 printf(" *Handler");
0a7de745 630 }
1c79356b
A
631
632 switch (oidp->oid_kind & CTLTYPE) {
0a7de745
A
633 case CTLTYPE_NODE:
634 printf(" Node\n");
635 if (!oidp->oid_handler) {
636 sysctl_sysctl_debug_dump_node(
637 oidp->oid_arg1, i + 2);
638 }
639 break;
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");
1c79356b 645 }
1c79356b
A
646 }
647}
648
6d2010ae
A
649/*
650 * sysctl_sysctl_debug
651 *
652 * Description: This function implements the "sysctl.debug" portion of the
653 * OID space for sysctl.
654 *
655 * OID: 0, 0
656 *
657 * Parameters: __unused
658 *
659 * Returns: ENOENT
660 *
661 * Implicit: kernel log, modified
662 *
663 * Locks: Acquires and then releases a read lock on the
664 * sysctl_geometry_lock
665 */
666STATIC int
2d21ac55 667sysctl_sysctl_debug(__unused struct sysctl_oid *oidp, __unused void *arg1,
0a7de745 668 __unused int arg2, __unused struct sysctl_req *req)
1c79356b 669{
6d2010ae 670 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b 671 sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
6d2010ae 672 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
673 return ENOENT;
674}
675
0a7de745
A
676SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
677 0, 0, sysctl_sysctl_debug, "-", "");
1c79356b 678
6d2010ae
A
679/*
680 * sysctl_sysctl_name
681 *
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"
685 * output).
686 *
687 * OID: 0, 1
688 *
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
695 *
696 * Returns: 0 Success
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
701 *
702 * Implict: Contents of user request buffer, modified
703 *
704 * Locks: Acquires and then releases a read lock on the
705 * sysctl_geometry_lock
706 *
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.
712 *
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
717 * byte.
718 *
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.
724 */
725STATIC int
2d21ac55 726sysctl_sysctl_name(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 727 struct sysctl_req *req)
1c79356b
A
728{
729 int *name = (int *) arg1;
730 u_int namelen = arg2;
731 int error = 0;
732 struct sysctl_oid *oid;
733 struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
d9a64523 734 char tempbuf[10] = {};
1c79356b 735
6d2010ae 736 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b
A
737 while (namelen) {
738 if (!lsp) {
0a7de745
A
739 snprintf(tempbuf, sizeof(tempbuf), "%d", *name);
740 if (req->oldidx) {
1c79356b 741 error = SYSCTL_OUT(req, ".", 1);
0a7de745
A
742 }
743 if (!error) {
91447636 744 error = SYSCTL_OUT(req, tempbuf, strlen(tempbuf));
0a7de745 745 }
6d2010ae
A
746 if (error) {
747 lck_rw_done(sysctl_geometry_lock);
0a7de745 748 return error;
6d2010ae 749 }
1c79356b
A
750 namelen--;
751 name++;
752 continue;
753 }
754 lsp2 = 0;
755 SLIST_FOREACH(oid, lsp, oid_link) {
0a7de745 756 if (oid->oid_number != *name) {
1c79356b 757 continue;
0a7de745 758 }
1c79356b 759
0a7de745 760 if (req->oldidx) {
1c79356b 761 error = SYSCTL_OUT(req, ".", 1);
0a7de745
A
762 }
763 if (!error) {
1c79356b 764 error = SYSCTL_OUT(req, oid->oid_name,
0a7de745
A
765 strlen(oid->oid_name));
766 }
6d2010ae
A
767 if (error) {
768 lck_rw_done(sysctl_geometry_lock);
0a7de745 769 return error;
6d2010ae 770 }
1c79356b
A
771
772 namelen--;
773 name++;
774
0a7de745 775 if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 776 break;
0a7de745 777 }
1c79356b 778
0a7de745 779 if (oid->oid_handler) {
1c79356b 780 break;
0a7de745 781 }
1c79356b
A
782
783 lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
784 break;
785 }
786 lsp = lsp2;
787 }
6d2010ae 788 lck_rw_done(sysctl_geometry_lock);
0a7de745 789 return SYSCTL_OUT(req, "", 1);
1c79356b
A
790}
791
6d2010ae 792SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_name, "");
1c79356b 793
6d2010ae
A
794/*
795 * sysctl_sysctl_next_ls
796 *
797 * Description: For a given OID name value, return the next consecutive OID
798 * name value within the geometry tree
799 *
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
804 * fill in
805 * len Pointer to receive new OID
806 * length value of storage written
807 * level OID tree depth (used to compute
808 * len value)
809 * oidpp Pointer to OID list entry
810 * pointer; used to walk the list
811 * forward across recursion
812 *
813 * Returns: 0 Returning a new entry
814 * 1 End of geometry list reached
815 *
816 * Implicit: *next Modified to contain the new OID
817 * *len Modified to contain new length
818 *
819 * Locks: Assumes sysctl_geometry_lock is held prior to calling
820 *
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
825 */
826STATIC int
0a7de745
A
827sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
828 int *next, int *len, int level, struct sysctl_oid **oidpp)
1c79356b
A
829{
830 struct sysctl_oid *oidp;
831
832 *len = level;
833 SLIST_FOREACH(oidp, lsp, oid_link) {
834 *next = oidp->oid_number;
835 *oidpp = oidp;
836
837 if (!namelen) {
0a7de745 838 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 839 return 0;
0a7de745
A
840 }
841 if (oidp->oid_handler) {
1c79356b
A
842 /* We really should call the handler here...*/
843 return 0;
0a7de745 844 }
1c79356b 845 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
2d21ac55 846
0a7de745 847 if (!SLIST_FIRST(lsp)) {
2d21ac55
A
848 /* This node had no children - skip it! */
849 continue;
0a7de745 850 }
2d21ac55 851
0a7de745
A
852 if (!sysctl_sysctl_next_ls(lsp, 0, 0, next + 1,
853 len, level + 1, oidpp)) {
1c79356b 854 return 0;
0a7de745 855 }
1c79356b
A
856 goto next;
857 }
858
0a7de745 859 if (oidp->oid_number < *name) {
1c79356b 860 continue;
0a7de745 861 }
1c79356b
A
862
863 if (oidp->oid_number > *name) {
0a7de745 864 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 865 return 0;
0a7de745
A
866 }
867 if (oidp->oid_handler) {
1c79356b 868 return 0;
0a7de745 869 }
1c79356b 870 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
0a7de745
A
871 if (!sysctl_sysctl_next_ls(lsp, name + 1, namelen - 1,
872 next + 1, len, level + 1, oidpp)) {
873 return 0;
874 }
1c79356b
A
875 goto next;
876 }
0a7de745 877 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 878 continue;
0a7de745 879 }
1c79356b 880
0a7de745 881 if (oidp->oid_handler) {
1c79356b 882 continue;
0a7de745 883 }
1c79356b
A
884
885 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
0a7de745
A
886 if (!sysctl_sysctl_next_ls(lsp, name + 1, namelen - 1, next + 1,
887 len, level + 1, oidpp)) {
888 return 0;
889 }
890next:
1c79356b
A
891 namelen = 1;
892 *len = level;
893 }
894 return 1;
895}
896
6d2010ae
A
897/*
898 * sysctl_sysctl_next
899 *
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"
902 * command line tool
903 *
904 * OID: 0, 2
905 *
906 * Parameters: oidp __unused
907 * arg1 Pointer to start OID name
908 * arg2 Start OID name length
909 * req Pointer to user request buffer
910 *
911 * Returns: 0 Success
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
917 *
918 * Implict: Contents of user request buffer, modified
919 *
920 * Locks: Acquires and then releases a read lock on the
921 * sysctl_geometry_lock
922 *
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.
928 *
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.
934 */
935STATIC int
2d21ac55 936sysctl_sysctl_next(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 937 struct sysctl_req *req)
1c79356b
A
938{
939 int *name = (int *) arg1;
940 u_int namelen = arg2;
941 int i, j, error;
942 struct sysctl_oid *oid;
943 struct sysctl_oid_list *lsp = &sysctl__children;
d9a64523 944 int newoid[CTL_MAXNAME] = {};
1c79356b 945
6d2010ae 946 lck_rw_lock_shared(sysctl_geometry_lock);
0a7de745 947 i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
6d2010ae 948 lck_rw_done(sysctl_geometry_lock);
0a7de745 949 if (i) {
1c79356b 950 return ENOENT;
0a7de745
A
951 }
952 error = SYSCTL_OUT(req, newoid, j * sizeof(int));
953 return error;
1c79356b
A
954}
955
6d2010ae 956SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_next, "");
1c79356b 957
6d2010ae
A
958/*
959 * name2oid
960 *
961 * Description: Support function for use by sysctl_sysctl_name2oid(); looks
962 * up an OID name given a string name.
963 *
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")
968 *
969 * Returns: 0 Success
970 * ENOENT Entry not found
971 *
972 * Implicit: *oid Modified to contain OID value
973 * *len Modified to contain OID length
974 *
975 * Locks: Assumes sysctl_geometry_lock is held prior to calling
976 */
977STATIC int
0a7de745 978name2oid(char *name, int *oid, u_int *len)
1c79356b
A
979{
980 int i;
981 struct sysctl_oid *oidp;
982 struct sysctl_oid_list *lsp = &sysctl__children;
983 char *p;
984
0a7de745 985 if (!*name) {
1c79356b 986 return ENOENT;
0a7de745 987 }
1c79356b 988
0a7de745
A
989 p = name + strlen(name) - 1;
990 if (*p == '.') {
1c79356b 991 *p = '\0';
0a7de745 992 }
1c79356b
A
993
994 *len = 0;
995
0a7de745 996 for (p = name; *p && *p != '.'; p++) {
1c79356b 997 ;
0a7de745 998 }
1c79356b 999 i = *p;
0a7de745 1000 if (i == '.') {
1c79356b 1001 *p = '\0';
0a7de745 1002 }
1c79356b
A
1003
1004 oidp = SLIST_FIRST(lsp);
1005
1006 while (oidp && *len < CTL_MAXNAME) {
1007 if (strcmp(name, oidp->oid_name)) {
1008 oidp = SLIST_NEXT(oidp, oid_link);
1009 continue;
1010 }
1011 *oid++ = oidp->oid_number;
1012 (*len)++;
1013
1014 if (!i) {
0a7de745 1015 return 0;
1c79356b
A
1016 }
1017
0a7de745 1018 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 1019 break;
0a7de745 1020 }
1c79356b 1021
0a7de745 1022 if (oidp->oid_handler) {
1c79356b 1023 break;
0a7de745 1024 }
1c79356b
A
1025
1026 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
1027 oidp = SLIST_FIRST(lsp);
fe8ab488 1028 *p = i; /* restore */
0a7de745
A
1029 name = p + 1;
1030 for (p = name; *p && *p != '.'; p++) {
1031 ;
1032 }
1c79356b 1033 i = *p;
0a7de745 1034 if (i == '.') {
1c79356b 1035 *p = '\0';
0a7de745 1036 }
1c79356b
A
1037 }
1038 return ENOENT;
1039}
1040
6d2010ae
A
1041/*
1042 * sysctl_sysctl_name2oid
1043 *
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
1046 * line command.
1047 *
1048 * OID: 0, 3
1049 *
1050 * Parameters: oidp __unused
1051 * arg1 __unused
1052 * arg2 __unused
1053 * req Request structure
1054 *
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
1062 *
1063 * Implicit: *req Contents of request, modified
1064 *
1065 * Locks: Acquires and then releases a read lock on the
1066 * sysctl_geometry_lock
1067 *
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.
1073 *
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.
1079 */
1080STATIC int
2d21ac55 1081sysctl_sysctl_name2oid(__unused struct sysctl_oid *oidp, __unused void *arg1,
0a7de745 1082 __unused int arg2, struct sysctl_req *req)
1c79356b
A
1083{
1084 char *p;
d9a64523 1085 int error, oid[CTL_MAXNAME] = {};
0a7de745 1086 u_int len = 0; /* set by name2oid() */
1c79356b 1087
0a7de745 1088 if (req->newlen < 1) {
1c79356b 1089 return ENOENT;
0a7de745
A
1090 }
1091 if (req->newlen >= MAXPATHLEN) { /* XXX arbitrary, undocumented */
1092 return ENAMETOOLONG;
1093 }
1c79356b 1094
0a7de745
A
1095 MALLOC(p, char *, req->newlen + 1, M_TEMP, M_WAITOK);
1096 if (!p) {
1097 return ENOMEM;
1098 }
1c79356b
A
1099
1100 error = SYSCTL_IN(req, p, req->newlen);
1101 if (error) {
1102 FREE(p, M_TEMP);
0a7de745 1103 return error;
1c79356b
A
1104 }
1105
0a7de745 1106 p[req->newlen] = '\0';
1c79356b 1107
6d2010ae
A
1108 /*
1109 * Note: We acquire and release the geometry lock here to
1110 * avoid making name2oid needlessly complex.
1111 */
1112 lck_rw_lock_shared(sysctl_geometry_lock);
1113 error = name2oid(p, oid, &len);
1114 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
1115
1116 FREE(p, M_TEMP);
1117
0a7de745
A
1118 if (error) {
1119 return error;
1120 }
1c79356b
A
1121
1122 error = SYSCTL_OUT(req, oid, len * sizeof *oid);
0a7de745 1123 return error;
1c79356b
A
1124}
1125
0a7de745
A
1126SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED, 0, 0,
1127 sysctl_sysctl_name2oid, "I", "");
1c79356b 1128
6d2010ae
A
1129/*
1130 * sysctl_sysctl_oidfmt
1131 *
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
1134 * line command.
1135 *
1136 * OID: 0, 4
1137 *
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
1142 *
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
1149 *
1150 * Implict: Contents of user request buffer, modified
1151 *
1152 * Locks: Acquires and then releases a read lock on the
1153 * sysctl_geometry_lock
1154 *
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.
1159 *
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.
1165 */
1166STATIC int
2d21ac55 1167sysctl_sysctl_oidfmt(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 1168 struct sysctl_req *req)
1c79356b 1169{
6d2010ae 1170 int *name = (int *) arg1;
0a7de745 1171 int error = ENOENT; /* default error: not found */
1c79356b 1172 u_int namelen = arg2;
2d21ac55 1173 u_int indx;
1c79356b
A
1174 struct sysctl_oid *oid;
1175 struct sysctl_oid_list *lsp = &sysctl__children;
1176
6d2010ae 1177 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b
A
1178 oid = SLIST_FIRST(lsp);
1179
1180 indx = 0;
1181 while (oid && indx < CTL_MAXNAME) {
1182 if (oid->oid_number == name[indx]) {
1183 indx++;
1184 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
0a7de745 1185 if (oid->oid_handler) {
1c79356b 1186 goto found;
0a7de745
A
1187 }
1188 if (indx == namelen) {
1c79356b 1189 goto found;
0a7de745 1190 }
1c79356b
A
1191 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
1192 oid = SLIST_FIRST(lsp);
1193 } else {
6d2010ae
A
1194 if (indx != namelen) {
1195 error = EISDIR;
1196 goto err;
1197 }
1c79356b
A
1198 goto found;
1199 }
1200 } else {
1201 oid = SLIST_NEXT(oid, oid_link);
1202 }
1203 }
6d2010ae
A
1204 /* Not found */
1205 goto err;
1206
1c79356b 1207found:
0a7de745 1208 if (!oid->oid_fmt) {
6d2010ae 1209 goto err;
0a7de745
A
1210 }
1211 error = SYSCTL_OUT(req,
1212 &oid->oid_kind, sizeof(oid->oid_kind));
1213 if (!error) {
1214 error = SYSCTL_OUT(req, oid->oid_fmt,
1215 strlen(oid->oid_fmt) + 1);
1216 }
6d2010ae
A
1217err:
1218 lck_rw_done(sysctl_geometry_lock);
0a7de745 1219 return error;
1c79356b
A
1220}
1221
6d2010ae 1222SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_oidfmt, "");
1c79356b 1223
1c79356b
A
1224
1225/*
1226 * Default "handler" functions.
1227 */
1228
1229/*
1230 * Handle an int, signed or unsigned.
1231 * Two cases:
1232 * a variable: point arg1 at it.
1233 * a constant: pass it in arg2.
1234 */
1235
1236int
2d21ac55 1237sysctl_handle_int(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 1238 struct sysctl_req *req)
1c79356b 1239{
2d21ac55 1240 return sysctl_io_number(req, arg1? *(int*)arg1: arg2, sizeof(int), arg1, NULL);
1c79356b
A
1241}
1242
1243/*
1244 * Handle a long, signed or unsigned. arg1 points to it.
1245 */
1246
1247int
2d21ac55 1248sysctl_handle_long(__unused struct sysctl_oid *oidp, void *arg1,
0a7de745 1249 __unused int arg2, struct sysctl_req *req)
1c79356b 1250{
0a7de745
A
1251 if (!arg1) {
1252 return EINVAL;
1253 }
2d21ac55 1254 return sysctl_io_number(req, *(long*)arg1, sizeof(long), arg1, NULL);
1c79356b
A
1255}
1256
43866e37
A
1257/*
1258 * Handle a quad, signed or unsigned. arg1 points to it.
1259 */
1260
1261int
2d21ac55 1262sysctl_handle_quad(__unused struct sysctl_oid *oidp, void *arg1,
0a7de745 1263 __unused int arg2, struct sysctl_req *req)
43866e37 1264{
0a7de745
A
1265 if (!arg1) {
1266 return EINVAL;
1267 }
2d21ac55 1268 return sysctl_io_number(req, *(long long*)arg1, sizeof(long long), arg1, NULL);
43866e37
A
1269}
1270
1271/*
1272 * Expose an int value as a quad.
1273 *
1274 * This interface allows us to support interfaces defined
1275 * as using quad values while the implementation is still
1276 * using ints.
1277 */
1278int
2d21ac55 1279sysctl_handle_int2quad(__unused struct sysctl_oid *oidp, void *arg1,
0a7de745 1280 __unused int arg2, struct sysctl_req *req)
43866e37
A
1281{
1282 int error = 0;
1283 long long val;
1284 int newval;
1285
0a7de745
A
1286 if (!arg1) {
1287 return EINVAL;
1288 }
43866e37
A
1289 val = (long long)*(int *)arg1;
1290 error = SYSCTL_OUT(req, &val, sizeof(long long));
1291
0a7de745
A
1292 if (error || !req->newptr) {
1293 return error;
1294 }
43866e37
A
1295
1296 error = SYSCTL_IN(req, &val, sizeof(long long));
1297 if (!error) {
1298 /*
1299 * Value must be representable; check by
1300 * casting and then casting back.
1301 */
1302 newval = (int)val;
1303 if ((long long)newval != val) {
1304 error = ERANGE;
1305 } else {
1306 *(int *)arg1 = newval;
1307 }
1308 }
0a7de745 1309 return error;
43866e37
A
1310}
1311
1c79356b
A
1312/*
1313 * Handle our generic '\0' terminated 'C' string.
1314 * Two cases:
0a7de745
A
1315 * a variable string: point arg1 at it, arg2 is max length.
1316 * a constant string: point arg1 at it, arg2 is zero.
1c79356b
A
1317 */
1318
1319int
2d21ac55 1320sysctl_handle_string( __unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 1321 struct sysctl_req *req)
1c79356b 1322{
2d21ac55 1323 return sysctl_io_string(req, arg1, arg2, 0, NULL);
1c79356b
A
1324}
1325
1326/*
1327 * Handle any kind of opaque data.
1328 * arg1 points to it, arg2 is the size.
1329 */
1330
1331int
2d21ac55 1332sysctl_handle_opaque(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 1333 struct sysctl_req *req)
1c79356b 1334{
2d21ac55 1335 return sysctl_io_opaque(req, arg1, arg2, NULL);
1c79356b
A
1336}
1337
1338/*
1339 * Transfer functions to/from kernel space.
1c79356b 1340 */
6d2010ae 1341STATIC int
1c79356b
A
1342sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
1343{
1344 size_t i = 0;
1c79356b
A
1345
1346 if (req->oldptr) {
1347 i = l;
0a7de745 1348 if (i > req->oldlen - req->oldidx) {
1c79356b 1349 i = req->oldlen - req->oldidx;
0a7de745
A
1350 }
1351 if (i > 0) {
2d21ac55 1352 bcopy((const void*)p, CAST_DOWN(char *, (req->oldptr + req->oldidx)), i);
0a7de745 1353 }
1c79356b
A
1354 }
1355 req->oldidx += l;
0a7de745
A
1356 if (req->oldptr && i != l) {
1357 return ENOMEM;
1358 }
1359 return 0;
1c79356b
A
1360}
1361
6d2010ae 1362STATIC int
1c79356b
A
1363sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
1364{
0a7de745 1365 if (!req->newptr) {
1c79356b 1366 return 0;
0a7de745
A
1367 }
1368 if (req->newlen - req->newidx < l) {
1369 return EINVAL;
1370 }
91447636 1371 bcopy(CAST_DOWN(char *, (req->newptr + req->newidx)), p, l);
1c79356b 1372 req->newidx += l;
0a7de745 1373 return 0;
1c79356b
A
1374}
1375
1376int
43866e37 1377kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen)
1c79356b
A
1378{
1379 int error = 0;
1380 struct sysctl_req req;
1381
43866e37
A
1382 /*
1383 * Construct request.
1384 */
1c79356b 1385 bzero(&req, sizeof req);
1c79356b 1386 req.p = p;
0a7de745 1387 if (oldlenp) {
1c79356b 1388 req.oldlen = *oldlenp;
0a7de745
A
1389 }
1390 if (old) {
91447636 1391 req.oldptr = CAST_USER_ADDR_T(old);
0a7de745 1392 }
1c79356b
A
1393 if (newlen) {
1394 req.newlen = newlen;
91447636 1395 req.newptr = CAST_USER_ADDR_T(new);
1c79356b 1396 }
1c79356b
A
1397 req.oldfunc = sysctl_old_kernel;
1398 req.newfunc = sysctl_new_kernel;
1399 req.lock = 1;
1400
43866e37 1401 /* make the request */
fe8ab488 1402 error = sysctl_root(TRUE, FALSE, NULL, 0, name, namelen, &req);
1c79356b 1403
0a7de745
A
1404 if (error && error != ENOMEM) {
1405 return error;
1406 }
1c79356b 1407
0a7de745 1408 if (oldlenp) {
43866e37 1409 *oldlenp = req.oldidx;
0a7de745 1410 }
43866e37 1411
0a7de745 1412 return error;
1c79356b
A
1413}
1414
1415/*
1416 * Transfer function to/from user space.
1417 */
6d2010ae 1418STATIC int
1c79356b
A
1419sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1420{
1421 int error = 0;
1422 size_t i = 0;
1423
1424 if (req->oldptr) {
0a7de745
A
1425 if (req->oldlen - req->oldidx < l) {
1426 return ENOMEM;
1427 }
1c79356b 1428 i = l;
0a7de745 1429 if (i > req->oldlen - req->oldidx) {
1c79356b 1430 i = req->oldlen - req->oldidx;
0a7de745
A
1431 }
1432 if (i > 0) {
2d21ac55 1433 error = copyout((const void*)p, (req->oldptr + req->oldidx), i);
0a7de745 1434 }
1c79356b
A
1435 }
1436 req->oldidx += l;
0a7de745
A
1437 if (error) {
1438 return error;
1439 }
1440 if (req->oldptr && i < l) {
1441 return ENOMEM;
1442 }
1443 return 0;
1c79356b
A
1444}
1445
6d2010ae 1446STATIC int
1c79356b
A
1447sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1448{
1449 int error;
1450
0a7de745 1451 if (!req->newptr) {
1c79356b 1452 return 0;
0a7de745
A
1453 }
1454 if (req->newlen - req->newidx < l) {
1455 return EINVAL;
1456 }
91447636 1457 error = copyin((req->newptr + req->newidx), p, l);
1c79356b 1458 req->newidx += l;
0a7de745 1459 return error;
1c79356b
A
1460}
1461
1462/*
1463 * Traverse our tree, and find the right node, execute whatever it points
1464 * at, and return the resulting error code.
1465 */
1466
1467int
fe8ab488 1468sysctl_root(boolean_t from_kernel, boolean_t string_is_canonical, char *namestring, size_t namestringlen, int *name, u_int namelen, struct sysctl_req *req)
1c79356b 1469{
2d21ac55
A
1470 u_int indx;
1471 int i;
1c79356b
A
1472 struct sysctl_oid *oid;
1473 struct sysctl_oid_list *lsp = &sysctl__children;
d9a64523 1474 sysctl_handler_t oid_handler = NULL;
1c79356b 1475 int error;
fe8ab488
A
1476 boolean_t unlocked_node_found = FALSE;
1477 boolean_t namestring_started = FALSE;
2d21ac55
A
1478
1479 /* Get the read lock on the geometry */
1480 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b 1481
fe8ab488
A
1482 if (string_is_canonical) {
1483 /* namestring is actually canonical, name/namelen needs to be populated */
1484 error = name2oid(namestring, name, &namelen);
1485 if (error) {
1486 goto err;
1487 }
1488 }
0a7de745 1489
1c79356b
A
1490 oid = SLIST_FIRST(lsp);
1491
1492 indx = 0;
1493 while (oid && indx < CTL_MAXNAME) {
1494 if (oid->oid_number == name[indx]) {
fe8ab488
A
1495 if (!from_kernel && !string_is_canonical) {
1496 if (namestring_started) {
1497 if (strlcat(namestring, ".", namestringlen) >= namestringlen) {
1498 error = ENAMETOOLONG;
1499 goto err;
1500 }
1501 }
1502
1503 if (strlcat(namestring, oid->oid_name, namestringlen) >= namestringlen) {
1504 error = ENAMETOOLONG;
1505 goto err;
1506 }
1507 namestring_started = TRUE;
1508 }
0a7de745 1509
1c79356b 1510 indx++;
0a7de745 1511 if (!(oid->oid_kind & CTLFLAG_LOCKED)) {
fe8ab488 1512 unlocked_node_found = TRUE;
2d21ac55 1513 }
0a7de745 1514 if (oid->oid_kind & CTLFLAG_NOLOCK) {
1c79356b 1515 req->lock = 0;
0a7de745 1516 }
6d2010ae
A
1517 /*
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
1521 * access value.
1522 *
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.
1528 */
1c79356b 1529 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
0a7de745 1530 if (oid->oid_handler) {
1c79356b 1531 goto found;
0a7de745
A
1532 }
1533 if (indx == namelen) {
2d21ac55
A
1534 error = ENOENT;
1535 goto err;
1536 }
1537
1c79356b
A
1538 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
1539 oid = SLIST_FIRST(lsp);
1540 } else {
0a7de745 1541 if (indx != namelen) {
2d21ac55
A
1542 error = EISDIR;
1543 goto err;
1544 }
1c79356b
A
1545 goto found;
1546 }
1547 } else {
1548 oid = SLIST_NEXT(oid, oid_link);
1549 }
1550 }
2d21ac55
A
1551 error = ENOENT;
1552 goto err;
1c79356b 1553found:
0a7de745 1554
fe8ab488
A
1555 /*
1556 * indx is the index of the first remaining OID name,
1557 * for sysctls that take them as arguments
1558 */
1559 if (!from_kernel && !string_is_canonical && (indx < namelen)) {
1560 char tempbuf[10];
1561 u_int indx2;
0a7de745 1562
fe8ab488 1563 for (indx2 = indx; indx2 < namelen; indx2++) {
0a7de745
A
1564 snprintf(tempbuf, sizeof(tempbuf), "%d", name[indx2]);
1565
fe8ab488
A
1566 if (namestring_started) {
1567 if (strlcat(namestring, ".", namestringlen) >= namestringlen) {
1568 error = ENAMETOOLONG;
1569 goto err;
1570 }
1571 }
0a7de745 1572
fe8ab488
A
1573 if (strlcat(namestring, tempbuf, namestringlen) >= namestringlen) {
1574 error = ENAMETOOLONG;
1575 goto err;
1576 }
1577 namestring_started = TRUE;
1578 }
1579 }
0a7de745 1580
1c79356b
A
1581 /* If writing isn't allowed */
1582 if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
0a7de745 1583 ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) {
2d21ac55
A
1584 error = (EPERM);
1585 goto err;
1c79356b
A
1586 }
1587
43866e37
A
1588 /*
1589 * If we're inside the kernel, the OID must be marked as kernel-valid.
43866e37 1590 */
0a7de745 1591 if (from_kernel && !(oid->oid_kind & CTLFLAG_KERN)) {
2d21ac55
A
1592 error = (EPERM);
1593 goto err;
1594 }
43866e37 1595
6d2010ae
A
1596 /*
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.
1603 */
1c79356b
A
1604 if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
1605 req->newptr && req->p &&
0a7de745 1606 (error = proc_suser(req->p))) {
2d21ac55 1607 goto err;
0a7de745 1608 }
1c79356b 1609
d9a64523
A
1610 /*
1611 * sysctl_unregister_oid() may change the handler value, so grab it
1612 * under the lock.
1613 */
1614 oid_handler = oid->oid_handler;
1615 if (!oid_handler) {
0a7de745 1616 error = EINVAL;
2d21ac55 1617 goto err;
1c79356b
A
1618 }
1619
6d2010ae
A
1620 /*
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...
1625 */
1626 OSAddAtomic(1, &oid->oid_refcnt);
1627
1628 lck_rw_done(sysctl_geometry_lock);
1629
fe8ab488
A
1630#if CONFIG_MACF
1631 if (!from_kernel) {
1632 error = mac_system_check_sysctlbyname(kauth_cred_get(),
0a7de745
A
1633 namestring,
1634 name,
1635 namelen,
1636 req->oldptr,
1637 req->oldlen,
1638 req->newptr,
1639 req->newlen);
1640 if (error) {
fe8ab488 1641 goto dropref;
0a7de745 1642 }
fe8ab488
A
1643 }
1644#endif
0a7de745 1645
6d2010ae 1646 /*
fe8ab488
A
1647 * ...however, we still have to grab the mutex for those calls which
1648 * may be into code whose reentrancy is protected by it.
6d2010ae 1649 */
0a7de745 1650 if (unlocked_node_found) {
fe8ab488 1651 lck_mtx_lock(sysctl_unlocked_node_lock);
2d21ac55 1652 }
1c79356b 1653
cb323159
A
1654#if defined(HAS_APPLE_PAC)
1655 /*
1656 * oid_handler is signed address-discriminated by sysctl_register_oid().
1657 */
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) */
d9a64523 1663
1c79356b 1664 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
d9a64523 1665 i = oid_handler(oid, name + indx, namelen - indx, req);
1c79356b 1666 } else {
d9a64523 1667 i = oid_handler(oid, oid->oid_arg1, oid->oid_arg2, req);
1c79356b 1668 }
2d21ac55
A
1669 error = i;
1670
0a7de745 1671 if (unlocked_node_found) {
fe8ab488 1672 lck_mtx_unlock(sysctl_unlocked_node_lock);
2d21ac55 1673 }
1c79356b 1674
fe8ab488
A
1675#if CONFIG_MACF
1676 /* only used from another CONFIG_MACF block */
1677dropref:
1678#endif
1679
6d2010ae
A
1680 /*
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.
1688 *
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"
1692 * OIDs.
1693 */
1694 lck_rw_lock_shared(sysctl_geometry_lock);
0a7de745 1695 if (OSAddAtomic(-1, &oid->oid_refcnt) == 1) {
6d2010ae 1696 wakeup(&oid->oid_refcnt);
0a7de745 1697 }
6d2010ae 1698
2d21ac55
A
1699err:
1700 lck_rw_done(sysctl_geometry_lock);
0a7de745 1701 return error;
1c79356b
A
1702}
1703
0a7de745
A
1704void
1705sysctl_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)
fe8ab488
A
1707{
1708 bzero(req, sizeof(*req));
0a7de745 1709
fe8ab488 1710 req->p = p;
0a7de745 1711
fe8ab488
A
1712 req->oldlen = oldlen;
1713 req->oldptr = oldp;
0a7de745 1714
fe8ab488
A
1715 if (newlen) {
1716 req->newlen = newlen;
1717 req->newptr = newp;
1718 }
0a7de745 1719
fe8ab488
A
1720 req->oldfunc = sysctl_old_user;
1721 req->newfunc = sysctl_new_user;
1722 req->lock = 1;
1723
1724 return;
1725}
1c79356b
A
1726
1727int
fe8ab488 1728sysctl(proc_t p, struct sysctl_args *uap, __unused int32_t *retval)
1c79356b 1729{
cb323159 1730 int error, new_error;
fe8ab488
A
1731 size_t oldlen = 0, newlen;
1732 int name[CTL_MAXNAME];
1733 struct sysctl_req req;
1734 char *namestring;
1735 size_t namestringlen = MAXPATHLEN;
0a7de745 1736
fe8ab488
A
1737 /*
1738 * all top-level sysctl names are non-terminal
1739 */
0a7de745
A
1740 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) {
1741 return EINVAL;
1742 }
fe8ab488 1743 error = copyin(uap->name, &name[0], uap->namelen * sizeof(int));
0a7de745
A
1744 if (error) {
1745 return error;
1746 }
1747
fe8ab488 1748 AUDIT_ARG(ctlname, name, uap->namelen);
0a7de745
A
1749
1750 if (uap->newlen > SIZE_T_MAX) {
1751 return EINVAL;
1752 }
fe8ab488 1753 newlen = (size_t)uap->newlen;
0a7de745 1754
fe8ab488 1755 if (uap->oldlenp != USER_ADDR_NULL) {
0a7de745 1756 uint64_t oldlen64 = fuulong(uap->oldlenp);
fe8ab488
A
1757
1758 /*
1759 * If more than 4G, clamp to 4G
1760 */
0a7de745 1761 if (oldlen64 > SIZE_T_MAX) {
fe8ab488 1762 oldlen = SIZE_T_MAX;
0a7de745 1763 } else {
fe8ab488 1764 oldlen = (size_t)oldlen64;
0a7de745 1765 }
fe8ab488 1766 }
0a7de745 1767
fe8ab488
A
1768 sysctl_create_user_req(&req, p, uap->old, oldlen, uap->new, newlen);
1769
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" */
1776 }
0a7de745 1777 }
fe8ab488
A
1778
1779 MALLOC(namestring, char *, namestringlen, M_TEMP, M_WAITOK);
1780 if (!namestring) {
0a7de745
A
1781 oldlen = 0;
1782 goto err;
fe8ab488 1783 }
1c79356b 1784
fe8ab488 1785 error = userland_sysctl(FALSE, namestring, namestringlen, name, uap->namelen, &req, &oldlen);
0a7de745 1786
fe8ab488 1787 FREE(namestring, M_TEMP);
0a7de745
A
1788
1789 if ((error) && (error != ENOMEM)) {
1790 return error;
1791 }
1792
fe8ab488 1793err:
0a7de745 1794 if (uap->oldlenp != USER_ADDR_NULL) {
cb323159
A
1795 /*
1796 * Only overwrite the old error value on a new error
1797 */
1798 new_error = suulong(uap->oldlenp, oldlen);
1799
1800 if (new_error) {
1801 error = new_error;
1802 }
0a7de745
A
1803 }
1804
1805 return error;
fe8ab488 1806}
1c79356b 1807
cb323159
A
1808// sysctlbyname is also exported as KPI to kexts
1809// and the syscall name cannot conflict with it
fe8ab488 1810int
cb323159 1811sys_sysctlbyname(proc_t p, struct sysctlbyname_args *uap, __unused int32_t *retval)
fe8ab488 1812{
cb323159 1813 int error, new_error;
fe8ab488
A
1814 size_t oldlen = 0, newlen;
1815 char *name;
1816 size_t namelen = 0;
1817 struct sysctl_req req;
1818 int oid[CTL_MAXNAME];
1819
0a7de745
A
1820 if (uap->namelen >= MAXPATHLEN) { /* XXX arbitrary, undocumented */
1821 return ENAMETOOLONG;
1822 }
fe8ab488 1823 namelen = (size_t)uap->namelen;
0a7de745
A
1824
1825 MALLOC(name, char *, namelen + 1, M_TEMP, M_WAITOK);
1826 if (!name) {
1827 return ENOMEM;
1828 }
fe8ab488
A
1829
1830 error = copyin(uap->name, name, namelen);
1831 if (error) {
1832 FREE(name, M_TEMP);
0a7de745 1833 return error;
1c79356b 1834 }
fe8ab488
A
1835 name[namelen] = '\0';
1836
1837 /* XXX
1838 * AUDIT_ARG(ctlname, name, uap->namelen);
1839 */
0a7de745 1840
fe8ab488
A
1841 if (uap->newlen > SIZE_T_MAX) {
1842 FREE(name, M_TEMP);
0a7de745 1843 return EINVAL;
fe8ab488
A
1844 }
1845 newlen = (size_t)uap->newlen;
0a7de745 1846
fe8ab488 1847 if (uap->oldlenp != USER_ADDR_NULL) {
0a7de745
A
1848 uint64_t oldlen64 = fuulong(uap->oldlenp);
1849
fe8ab488
A
1850 /*
1851 * If more than 4G, clamp to 4G
1852 */
0a7de745 1853 if (oldlen64 > SIZE_T_MAX) {
fe8ab488 1854 oldlen = SIZE_T_MAX;
0a7de745 1855 } else {
fe8ab488 1856 oldlen = (size_t)oldlen64;
0a7de745 1857 }
fe8ab488 1858 }
0a7de745 1859
fe8ab488
A
1860 sysctl_create_user_req(&req, p, uap->old, oldlen, uap->new, newlen);
1861
0a7de745
A
1862 error = userland_sysctl(TRUE, name, namelen + 1, oid, CTL_MAXNAME, &req, &oldlen);
1863
fe8ab488
A
1864 FREE(name, M_TEMP);
1865
0a7de745
A
1866 if ((error) && (error != ENOMEM)) {
1867 return error;
1868 }
1869
1870 if (uap->oldlenp != USER_ADDR_NULL) {
cb323159
A
1871 /*
1872 * Only overwrite the old error value on a new error
1873 */
1874 new_error = suulong(uap->oldlenp, oldlen);
1875
1876 if (new_error) {
1877 error = new_error;
1878 }
0a7de745
A
1879 }
1880
1881 return error;
1c79356b
A
1882}
1883
1884/*
1885 * This is used from various compatibility syscalls too. That's why name
1886 * must be in kernel space.
1887 */
1888int
fe8ab488 1889userland_sysctl(boolean_t string_is_canonical,
0a7de745
A
1890 char *namestring, size_t namestringlen,
1891 int *name, u_int namelen, struct sysctl_req *req,
1892 size_t *retval)
1c79356b
A
1893{
1894 int error = 0;
fe8ab488 1895 struct sysctl_req req2;
1c79356b
A
1896
1897 do {
0a7de745
A
1898 /* if EAGAIN, reset output cursor */
1899 req2 = *req;
1900 if (!string_is_canonical) {
1901 namestring[0] = '\0';
1902 }
1c79356b 1903
0a7de745 1904 error = sysctl_root(FALSE, string_is_canonical, namestring, namestringlen, name, namelen, &req2);
fe8ab488 1905 } while (error == EAGAIN);
1c79356b 1906
0a7de745
A
1907 if (error && error != ENOMEM) {
1908 return error;
1909 }
1c79356b
A
1910
1911 if (retval) {
0a7de745 1912 if (req2.oldptr && req2.oldidx > req2.oldlen) {
fe8ab488 1913 *retval = req2.oldlen;
0a7de745 1914 } else {
fe8ab488 1915 *retval = req2.oldidx;
0a7de745 1916 }
1c79356b 1917 }
0a7de745 1918 return error;
1c79356b 1919}
1c79356b
A
1920
1921/*
43866e37
A
1922 * Kernel versions of the userland sysctl helper functions.
1923 *
1924 * These allow sysctl to be used in the same fashion in both
1925 * userland and the kernel.
1926 *
1927 * Note that some sysctl handlers use copyin/copyout, which
1928 * may not work correctly.
fe8ab488
A
1929 *
1930 * The "sysctlbyname" KPI for use by kexts is aliased to this function.
de355530 1931 */
1c79356b 1932
43866e37 1933int
fe8ab488 1934kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
43866e37 1935{
fe8ab488
A
1936 int oid[CTL_MAXNAME];
1937 int name2mib_oid[2];
43866e37
A
1938 int error;
1939 size_t oidlen;
de355530 1940
fe8ab488
A
1941 /* look up the OID with magic service node */
1942 name2mib_oid[0] = 0;
1943 name2mib_oid[1] = 3;
de355530 1944
fe8ab488 1945 oidlen = sizeof(oid);
3e170ce0 1946 error = kernel_sysctl(current_proc(), name2mib_oid, 2, oid, &oidlen, __DECONST(void *, name), strlen(name));
fe8ab488 1947 oidlen /= sizeof(int);
0a7de745 1948
43866e37 1949 /* now use the OID */
0a7de745 1950 if (error == 0) {
fe8ab488 1951 error = kernel_sysctl(current_proc(), oid, oidlen, oldp, oldlenp, newp, newlen);
0a7de745
A
1952 }
1953 return error;
1c79356b 1954}