]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_newsysctl.c
xnu-7195.50.7.100.1.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 87#if defined(HAS_APPLE_PAC)
f427ee49 88#include <os/hash.h>
cb323159
A
89#include <ptrauth.h>
90#endif /* defined(HAS_APPLE_PAC) */
d9a64523 91
fe8ab488 92lck_grp_t * sysctl_lock_group = NULL;
2d21ac55 93lck_rw_t * sysctl_geometry_lock = NULL;
fe8ab488 94lck_mtx_t * sysctl_unlocked_node_lock = NULL;
1c79356b 95
6d2010ae
A
96/*
97 * Conditionally allow dtrace to see these functions for debugging purposes.
98 */
99#ifdef STATIC
100#undef STATIC
101#endif
102#if 0
0a7de745 103#define STATIC
6d2010ae
A
104#else
105#define STATIC static
106#endif
107
108/* forward declarations of static functions */
6d2010ae
A
109STATIC void sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i);
110STATIC int sysctl_sysctl_debug(struct sysctl_oid *oidp, void *arg1,
0a7de745 111 int arg2, struct sysctl_req *req);
6d2010ae 112STATIC int sysctl_sysctl_name(struct sysctl_oid *oidp, void *arg1,
0a7de745
A
113 int arg2, struct sysctl_req *req);
114STATIC 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);
6d2010ae
A
117STATIC int sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l);
118STATIC int sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l);
f427ee49 119STATIC int name2oid(char *name, int *oid, size_t *len);
6d2010ae
A
120STATIC int sysctl_sysctl_name2oid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
121STATIC int sysctl_sysctl_next(struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 122 struct sysctl_req *req);
6d2010ae 123STATIC int sysctl_sysctl_oidfmt(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
6d2010ae
A
124STATIC int sysctl_old_user(struct sysctl_req *req, const void *p, size_t l);
125STATIC int sysctl_new_user(struct sysctl_req *req, void *p, size_t l);
1c79356b 126
fe8ab488 127STATIC void sysctl_create_user_req(struct sysctl_req *req, struct proc *p, user_addr_t oldp,
0a7de745 128 size_t oldlen, user_addr_t newp, size_t newlen);
f427ee49 129STATIC 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);
1c79356b 130
f427ee49 131int kernel_sysctl(struct proc *p, int *name, size_t namelen, void *old, size_t *oldlenp, void *new, size_t newlen);
0a7de745
A
132int kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
133int userland_sysctl(boolean_t string_is_canonical,
134 char *namestring, size_t namestringlen,
135 int *name, u_int namelen, struct sysctl_req *req,
136 size_t *retval);
1c79356b
A
137
138struct sysctl_oid_list sysctl__children; /* root list */
139
140/*
141 * Initialization of the MIB tree.
142 *
143 * Order by number in each list.
144 */
145
6d2010ae
A
146void
147sysctl_register_oid(struct sysctl_oid *new_oidp)
1c79356b 148{
6d2010ae
A
149 struct sysctl_oid *oidp = NULL;
150 struct sysctl_oid_list *parent = new_oidp->oid_parent;
1c79356b
A
151 struct sysctl_oid *p;
152 struct sysctl_oid *q;
153 int n;
6d2010ae
A
154
155 /*
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).
160 */
161 if (!(new_oidp->oid_kind & CTLFLAG_OID2)) {
f427ee49 162#if __x86_64__
6d2010ae
A
163 /*
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.
166 */
167 MALLOC(oidp, struct sysctl_oid *, sizeof(*oidp), M_TEMP, M_WAITOK | M_ZERO);
0a7de745
A
168 if (oidp == NULL) {
169 return; /* reject: no memory */
170 }
6d2010ae
A
171 /*
172 * Copy the structure only through the oid_fmt field, which
173 * is the last field in a non-OID2 OID structure.
174 *
175 * Note: We may want to set the oid_descr to the
176 * oid_name (or "") at some future date.
177 */
f427ee49
A
178 *oidp = *new_oidp;
179#else
180 panic("Old style sysctl without a version number isn't supported");
181#endif
6d2010ae
A
182 } else {
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 */
187 oidp = new_oidp;
188 break;
189 default:
0a7de745 190 return; /* rejects unknown version */
6d2010ae
A
191 }
192 }
43866e37 193
2d21ac55
A
194 /* Get the write lock to modify the geometry */
195 lck_rw_lock_exclusive(sysctl_geometry_lock);
196
1c79356b
A
197 /*
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
2d21ac55 200 * OID_AUTO_START to leave space for pre-assigned oid numbers.
1c79356b 201 */
1c79356b 202 if (oidp->oid_number == OID_AUTO) {
2d21ac55
A
203 /* First, find the highest oid in the parent list >OID_AUTO_START-1 */
204 n = OID_AUTO_START;
1c79356b 205 SLIST_FOREACH(p, parent, oid_link) {
0a7de745 206 if (p->oid_number > n) {
1c79356b 207 n = p->oid_number;
0a7de745 208 }
1c79356b
A
209 }
210 oidp->oid_number = n + 1;
6d2010ae
A
211 /*
212 * Reflect the number in an llocated OID into the template
213 * of the caller for sysctl_unregister_oid() compares.
214 */
0a7de745 215 if (oidp != new_oidp) {
6d2010ae 216 new_oidp->oid_number = oidp->oid_number;
0a7de745 217 }
1c79356b
A
218 }
219
cb323159
A
220#if defined(HAS_APPLE_PAC)
221 if (oidp->oid_handler) {
cb323159
A
222 /*
223 * Sign oid_handler address-discriminated upon installation to make it
f427ee49
A
224 * harder to replace with an arbitrary function pointer. Blend with
225 * a hash of oid_arg1 for robustness against memory corruption.
cb323159
A
226 */
227 oidp->oid_handler = ptrauth_auth_and_resign(oidp->oid_handler,
f427ee49
A
228 ptrauth_key_function_pointer,
229 ptrauth_function_pointer_type_discriminator(typeof(oidp->oid_handler)),
230 ptrauth_key_function_pointer,
cb323159 231 ptrauth_blend_discriminator(&oidp->oid_handler,
f427ee49 232 os_hash_kernel_pointer(oidp->oid_arg1)));
cb323159
A
233 }
234#endif /* defined(HAS_APPLE_PAC) */
d9a64523 235
1c79356b
A
236 /*
237 * Insert the oid into the parent's list in order.
238 */
239 q = NULL;
240 SLIST_FOREACH(p, parent, oid_link) {
cb323159
A
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) {
1c79356b 244 break;
0a7de745 245 }
1c79356b
A
246 q = p;
247 }
0a7de745 248 if (q) {
1c79356b 249 SLIST_INSERT_AFTER(q, oidp, oid_link);
0a7de745 250 } else {
1c79356b 251 SLIST_INSERT_HEAD(parent, oidp, oid_link);
0a7de745 252 }
43866e37 253
2d21ac55
A
254 /* Release the write lock */
255 lck_rw_unlock_exclusive(sysctl_geometry_lock);
1c79356b
A
256}
257
6d2010ae
A
258void
259sysctl_unregister_oid(struct sysctl_oid *oidp)
1c79356b 260{
0a7de745 261 struct sysctl_oid *removed_oidp = NULL; /* OID removed from tree */
f427ee49 262#if __x86_64__
0a7de745 263 struct sysctl_oid *old_oidp = NULL; /* OID compatibility copy */
f427ee49
A
264#else
265 struct sysctl_oid *const old_oidp = NULL;
266#endif
2d21ac55
A
267
268 /* Get the write lock to modify the geometry */
269 lck_rw_lock_exclusive(sysctl_geometry_lock);
270
6d2010ae 271 if (!(oidp->oid_kind & CTLFLAG_OID2)) {
f427ee49 272#if __x86_64__
6d2010ae
A
273 /*
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.
278 */
279 SLIST_FOREACH(old_oidp, oidp->oid_parent, oid_link) {
0a7de745
A
280 if (!memcmp(&oidp->oid_number, &old_oidp->oid_number, (offsetof(struct sysctl_oid, oid_descr) - offsetof(struct sysctl_oid, oid_number)))) {
281 break;
282 }
6d2010ae
A
283 }
284 if (old_oidp != NULL) {
285 SLIST_REMOVE(old_oidp->oid_parent, old_oidp, sysctl_oid, oid_link);
286 removed_oidp = old_oidp;
287 }
f427ee49
A
288#else
289 panic("Old style sysctl without a version number isn't supported");
290#endif
6d2010ae
A
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 */
f427ee49 311 removed_oidp->oid_handler = ptrauth_auth_and_resign(removed_oidp->oid_handler,
cb323159
A
312 ptrauth_key_function_pointer,
313 ptrauth_blend_discriminator(&removed_oidp->oid_handler,
f427ee49
A
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)));
cb323159
A
317 }
318#endif /* defined(HAS_APPLE_PAC) */
d9a64523 319
6d2010ae
A
320 /*
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.
325 *
326 * Note: oidp could be NULL if it wasn't found.
327 */
0a7de745 328 while (removed_oidp && removed_oidp->oid_refcnt) {
6d2010ae
A
329 lck_rw_sleep(sysctl_geometry_lock, LCK_SLEEP_EXCLUSIVE, &removed_oidp->oid_refcnt, THREAD_UNINT);
330 }
2d21ac55
A
331
332 /* Release the write lock */
333 lck_rw_unlock_exclusive(sysctl_geometry_lock);
334
6d2010ae 335 if (old_oidp != NULL) {
f427ee49
A
336#if __x86_64__
337 /* If it was allocated, free it after dropping the lock */
6d2010ae 338 FREE(old_oidp, M_TEMP);
f427ee49 339#endif
6d2010ae 340 }
1c79356b
A
341}
342
343/*
344 * Bulk-register all the oids in a linker_set.
345 */
6d2010ae
A
346void
347sysctl_register_set(const char *set)
1c79356b 348{
2d21ac55
A
349 struct sysctl_oid **oidpp, *oidp;
350
b0d623f7 351 LINKER_SET_FOREACH(oidpp, struct sysctl_oid **, set) {
2d21ac55
A
352 oidp = *oidpp;
353 if (!(oidp->oid_kind & CTLFLAG_NOAUTO)) {
0a7de745 354 sysctl_register_oid(oidp);
2d21ac55
A
355 }
356 }
1c79356b
A
357}
358
6d2010ae
A
359void
360sysctl_unregister_set(const char *set)
1c79356b 361{
2d21ac55
A
362 struct sysctl_oid **oidpp, *oidp;
363
b0d623f7 364 LINKER_SET_FOREACH(oidpp, struct sysctl_oid **, set) {
2d21ac55
A
365 oidp = *oidpp;
366 if (!(oidp->oid_kind & CTLFLAG_NOAUTO)) {
0a7de745 367 sysctl_unregister_oid(oidp);
2d21ac55
A
368 }
369 }
1c79356b
A
370}
371
1c79356b 372/*
39037602 373 * Exported in BSDKernel.exports, kept for binary compatibility
1c79356b 374 */
39037602 375#if defined(__x86_64__)
2d21ac55 376void
39037602 377sysctl_register_fixed(void)
2d21ac55 378{
2d21ac55 379}
39037602
A
380#endif
381
382/*
383 * Register the kernel's oids on startup.
384 */
2d21ac55
A
385
386void
39037602 387sysctl_early_init(void)
1c79356b 388{
39037602
A
389 /*
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.
394 */
395
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);
399
400 sysctl_register_set("__sysctl_set");
cb323159 401 sysctl_load_devicetree_entries();
1c79356b
A
402}
403
404/*
2d21ac55
A
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.).
1c79356b 410 */
1c79356b 411
2d21ac55 412int
0a7de745
A
413sysctl_io_number(struct sysctl_req *req, long long bigValue, size_t valueSize, void *pValue, int *changed)
414{
415 int smallValue;
416 int error;
2d21ac55 417
0a7de745
A
418 if (changed) {
419 *changed = 0;
420 }
2d21ac55
A
421
422 /*
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
426 * sized.
427 */
428
429 /* 32 bit value expected or 32 bit buffer offered */
b0d623f7
A
430 if (((valueSize == sizeof(int)) ||
431 ((req->oldlen == sizeof(int)) && (valueSize == sizeof(long long))))
0a7de745 432 && (req->oldptr)) {
2d21ac55 433 smallValue = (int)bigValue;
0a7de745
A
434 if ((long long)smallValue != bigValue) {
435 return ERANGE;
436 }
2d21ac55
A
437 error = SYSCTL_OUT(req, &smallValue, sizeof(smallValue));
438 } else {
439 /* any other case is either size-equal or a bug */
440 error = SYSCTL_OUT(req, &bigValue, valueSize);
441 }
442 /* error or nothing to set */
0a7de745
A
443 if (error || !req->newptr) {
444 return error;
445 }
2d21ac55
A
446
447 /* set request for constant */
0a7de745
A
448 if (pValue == NULL) {
449 return EPERM;
450 }
2d21ac55
A
451
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));
0a7de745 456 if (!error) {
2d21ac55 457 *(long long *)pValue = (long long)smallValue;
0a7de745 458 }
2d21ac55
A
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));
462 if (!error) {
463 smallValue = (int)bigValue;
0a7de745
A
464 if ((long long)smallValue != bigValue) {
465 return ERANGE;
466 }
2d21ac55
A
467 *(int *)pValue = smallValue;
468 }
469 } else {
470 /* sizes match, just copy in */
471 error = SYSCTL_IN(req, pValue, valueSize);
472 }
0a7de745 473 if (!error && changed) {
2d21ac55 474 *changed = 1;
0a7de745
A
475 }
476 return error;
2d21ac55
A
477}
478
479int
480sysctl_io_string(struct sysctl_req *req, char *pValue, size_t valueSize, int trunc, int *changed)
1c79356b 481{
2d21ac55 482 int error;
f427ee49 483 size_t len = strlen(pValue) + 1;
2d21ac55 484
0a7de745
A
485 if (changed) {
486 *changed = 0;
487 }
2d21ac55 488
f427ee49 489 if (trunc && req->oldptr && req->oldlen && (req->oldlen < len)) {
2d21ac55
A
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
cb323159 495 * returned string is always nul (ascii '\0') terminated. */
0a7de745 496 error = SYSCTL_OUT(req, pValue, req->oldlen - 1);
2d21ac55 497 if (!error) {
cb323159 498 char c = '\0';
2d21ac55
A
499 error = SYSCTL_OUT(req, &c, 1);
500 }
501 } else {
502 /* Copy string out */
f427ee49 503 error = SYSCTL_OUT(req, pValue, len);
2d21ac55
A
504 }
505
506 /* error or no new value */
0a7de745
A
507 if (error || !req->newptr) {
508 return error;
509 }
2d21ac55
A
510
511 /* attempt to set read-only value */
0a7de745
A
512 if (valueSize == 0) {
513 return EPERM;
514 }
2d21ac55
A
515
516 /* make sure there's room for the new string */
0a7de745
A
517 if (req->newlen >= valueSize) {
518 return EINVAL;
519 }
2d21ac55 520
cb323159 521 /* copy the string in and force nul termination */
2d21ac55
A
522 error = SYSCTL_IN(req, pValue, req->newlen);
523 pValue[req->newlen] = '\0';
524
0a7de745 525 if (!error && changed) {
2d21ac55 526 *changed = 1;
0a7de745
A
527 }
528 return error;
1c79356b
A
529}
530
0a7de745
A
531int
532sysctl_io_opaque(struct sysctl_req *req, void *pValue, size_t valueSize, int *changed)
2d21ac55
A
533{
534 int error;
535
0a7de745
A
536 if (changed) {
537 *changed = 0;
538 }
2d21ac55
A
539
540 /* Copy blob out */
541 error = SYSCTL_OUT(req, pValue, valueSize);
542
543 /* error or nothing to set */
0a7de745
A
544 if (error || !req->newptr) {
545 return error;
546 }
2d21ac55
A
547
548 error = SYSCTL_IN(req, pValue, valueSize);
549
0a7de745 550 if (!error && changed) {
2d21ac55 551 *changed = 1;
0a7de745
A
552 }
553 return error;
2d21ac55 554}
1c79356b
A
555
556/*
557 * "Staff-functions"
558 *
0a7de745 559 * These functions implement a presently undocumented interface
1c79356b
A
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.
566 *
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.
572 */
573
6d2010ae
A
574/*
575 * sysctl_sysctl_debug_dump_node
576 *
577 * Description: Dump debug information for a given sysctl_oid_list at the
578 * given oid depth out to the kernel log, via printf
579 *
580 * Parameters: l sysctl_oid_list pointer
581 * i current node depth
582 *
583 * Returns: (void)
584 *
585 * Implicit: kernel log, modified
586 *
587 * Locks: Assumes sysctl_geometry_lock is held prior to calling
588 *
589 * Notes: This function may call itself recursively to resolve Node
590 * values, which potentially have an inferioer sysctl_oid_list
591 *
592 * This function is only callable indirectly via the function
593 * sysctl_sysctl_debug()
594 *
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.
598 */
599STATIC void
1c79356b
A
600sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
601{
602 int k;
603 struct sysctl_oid *oidp;
604
605 SLIST_FOREACH(oidp, l, oid_link) {
0a7de745 606 for (k = 0; k < i; k++) {
1c79356b 607 printf(" ");
0a7de745 608 }
1c79356b
A
609
610 printf("%d %s ", oidp->oid_number, oidp->oid_name);
611
6d2010ae 612 printf("%c%c%c",
0a7de745
A
613 oidp->oid_kind & CTLFLAG_LOCKED ? 'L':' ',
614 oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
615 oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
1c79356b 616
0a7de745 617 if (oidp->oid_handler) {
1c79356b 618 printf(" *Handler");
0a7de745 619 }
1c79356b
A
620
621 switch (oidp->oid_kind & CTLTYPE) {
0a7de745
A
622 case CTLTYPE_NODE:
623 printf(" Node\n");
624 if (!oidp->oid_handler) {
625 sysctl_sysctl_debug_dump_node(
626 oidp->oid_arg1, i + 2);
627 }
628 break;
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");
1c79356b 634 }
1c79356b
A
635 }
636}
637
6d2010ae
A
638/*
639 * sysctl_sysctl_debug
640 *
641 * Description: This function implements the "sysctl.debug" portion of the
642 * OID space for sysctl.
643 *
644 * OID: 0, 0
645 *
646 * Parameters: __unused
647 *
648 * Returns: ENOENT
649 *
650 * Implicit: kernel log, modified
651 *
652 * Locks: Acquires and then releases a read lock on the
653 * sysctl_geometry_lock
654 */
655STATIC int
2d21ac55 656sysctl_sysctl_debug(__unused struct sysctl_oid *oidp, __unused void *arg1,
0a7de745 657 __unused int arg2, __unused struct sysctl_req *req)
1c79356b 658{
6d2010ae 659 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b 660 sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
6d2010ae 661 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
662 return ENOENT;
663}
664
0a7de745
A
665SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
666 0, 0, sysctl_sysctl_debug, "-", "");
1c79356b 667
6d2010ae
A
668/*
669 * sysctl_sysctl_name
670 *
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"
674 * output).
675 *
676 * OID: 0, 1
677 *
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
684 *
685 * Returns: 0 Success
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
690 *
691 * Implict: Contents of user request buffer, modified
692 *
693 * Locks: Acquires and then releases a read lock on the
694 * sysctl_geometry_lock
695 *
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.
701 *
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
706 * byte.
707 *
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.
713 */
714STATIC int
2d21ac55 715sysctl_sysctl_name(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 716 struct sysctl_req *req)
1c79356b
A
717{
718 int *name = (int *) arg1;
719 u_int namelen = arg2;
720 int error = 0;
721 struct sysctl_oid *oid;
722 struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
d9a64523 723 char tempbuf[10] = {};
1c79356b 724
6d2010ae 725 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b
A
726 while (namelen) {
727 if (!lsp) {
0a7de745
A
728 snprintf(tempbuf, sizeof(tempbuf), "%d", *name);
729 if (req->oldidx) {
1c79356b 730 error = SYSCTL_OUT(req, ".", 1);
0a7de745
A
731 }
732 if (!error) {
91447636 733 error = SYSCTL_OUT(req, tempbuf, strlen(tempbuf));
0a7de745 734 }
6d2010ae
A
735 if (error) {
736 lck_rw_done(sysctl_geometry_lock);
0a7de745 737 return error;
6d2010ae 738 }
1c79356b
A
739 namelen--;
740 name++;
741 continue;
742 }
743 lsp2 = 0;
744 SLIST_FOREACH(oid, lsp, oid_link) {
0a7de745 745 if (oid->oid_number != *name) {
1c79356b 746 continue;
0a7de745 747 }
1c79356b 748
0a7de745 749 if (req->oldidx) {
1c79356b 750 error = SYSCTL_OUT(req, ".", 1);
0a7de745
A
751 }
752 if (!error) {
1c79356b 753 error = SYSCTL_OUT(req, oid->oid_name,
0a7de745
A
754 strlen(oid->oid_name));
755 }
6d2010ae
A
756 if (error) {
757 lck_rw_done(sysctl_geometry_lock);
0a7de745 758 return error;
6d2010ae 759 }
1c79356b
A
760
761 namelen--;
762 name++;
763
0a7de745 764 if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 765 break;
0a7de745 766 }
1c79356b 767
0a7de745 768 if (oid->oid_handler) {
1c79356b 769 break;
0a7de745 770 }
1c79356b
A
771
772 lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
773 break;
774 }
775 lsp = lsp2;
776 }
6d2010ae 777 lck_rw_done(sysctl_geometry_lock);
0a7de745 778 return SYSCTL_OUT(req, "", 1);
1c79356b
A
779}
780
6d2010ae 781SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_name, "");
1c79356b 782
6d2010ae
A
783/*
784 * sysctl_sysctl_next_ls
785 *
786 * Description: For a given OID name value, return the next consecutive OID
787 * name value within the geometry tree
788 *
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
793 * fill in
794 * len Pointer to receive new OID
795 * length value of storage written
796 * level OID tree depth (used to compute
797 * len value)
798 * oidpp Pointer to OID list entry
799 * pointer; used to walk the list
800 * forward across recursion
801 *
802 * Returns: 0 Returning a new entry
803 * 1 End of geometry list reached
804 *
805 * Implicit: *next Modified to contain the new OID
806 * *len Modified to contain new length
807 *
808 * Locks: Assumes sysctl_geometry_lock is held prior to calling
809 *
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
814 */
815STATIC int
0a7de745
A
816sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
817 int *next, int *len, int level, struct sysctl_oid **oidpp)
1c79356b
A
818{
819 struct sysctl_oid *oidp;
820
821 *len = level;
822 SLIST_FOREACH(oidp, lsp, oid_link) {
823 *next = oidp->oid_number;
824 *oidpp = oidp;
825
826 if (!namelen) {
0a7de745 827 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 828 return 0;
0a7de745
A
829 }
830 if (oidp->oid_handler) {
1c79356b
A
831 /* We really should call the handler here...*/
832 return 0;
0a7de745 833 }
1c79356b 834 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
2d21ac55 835
0a7de745 836 if (!SLIST_FIRST(lsp)) {
2d21ac55
A
837 /* This node had no children - skip it! */
838 continue;
0a7de745 839 }
2d21ac55 840
0a7de745
A
841 if (!sysctl_sysctl_next_ls(lsp, 0, 0, next + 1,
842 len, level + 1, oidpp)) {
1c79356b 843 return 0;
0a7de745 844 }
1c79356b
A
845 goto next;
846 }
847
0a7de745 848 if (oidp->oid_number < *name) {
1c79356b 849 continue;
0a7de745 850 }
1c79356b
A
851
852 if (oidp->oid_number > *name) {
0a7de745 853 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 854 return 0;
0a7de745
A
855 }
856 if (oidp->oid_handler) {
1c79356b 857 return 0;
0a7de745 858 }
1c79356b 859 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
0a7de745
A
860 if (!sysctl_sysctl_next_ls(lsp, name + 1, namelen - 1,
861 next + 1, len, level + 1, oidpp)) {
862 return 0;
863 }
1c79356b
A
864 goto next;
865 }
0a7de745 866 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 867 continue;
0a7de745 868 }
1c79356b 869
0a7de745 870 if (oidp->oid_handler) {
1c79356b 871 continue;
0a7de745 872 }
1c79356b
A
873
874 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
0a7de745
A
875 if (!sysctl_sysctl_next_ls(lsp, name + 1, namelen - 1, next + 1,
876 len, level + 1, oidpp)) {
877 return 0;
878 }
879next:
1c79356b
A
880 namelen = 1;
881 *len = level;
882 }
883 return 1;
884}
885
6d2010ae
A
886/*
887 * sysctl_sysctl_next
888 *
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"
891 * command line tool
892 *
893 * OID: 0, 2
894 *
895 * Parameters: oidp __unused
896 * arg1 Pointer to start OID name
897 * arg2 Start OID name length
898 * req Pointer to user request buffer
899 *
900 * Returns: 0 Success
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
906 *
907 * Implict: Contents of user request buffer, modified
908 *
909 * Locks: Acquires and then releases a read lock on the
910 * sysctl_geometry_lock
911 *
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.
917 *
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.
923 */
924STATIC int
2d21ac55 925sysctl_sysctl_next(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 926 struct sysctl_req *req)
1c79356b
A
927{
928 int *name = (int *) arg1;
929 u_int namelen = arg2;
930 int i, j, error;
931 struct sysctl_oid *oid;
932 struct sysctl_oid_list *lsp = &sysctl__children;
d9a64523 933 int newoid[CTL_MAXNAME] = {};
1c79356b 934
6d2010ae 935 lck_rw_lock_shared(sysctl_geometry_lock);
0a7de745 936 i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
6d2010ae 937 lck_rw_done(sysctl_geometry_lock);
0a7de745 938 if (i) {
1c79356b 939 return ENOENT;
0a7de745
A
940 }
941 error = SYSCTL_OUT(req, newoid, j * sizeof(int));
942 return error;
1c79356b
A
943}
944
6d2010ae 945SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_next, "");
1c79356b 946
6d2010ae
A
947/*
948 * name2oid
949 *
950 * Description: Support function for use by sysctl_sysctl_name2oid(); looks
951 * up an OID name given a string name.
952 *
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")
957 *
958 * Returns: 0 Success
959 * ENOENT Entry not found
960 *
961 * Implicit: *oid Modified to contain OID value
962 * *len Modified to contain OID length
963 *
964 * Locks: Assumes sysctl_geometry_lock is held prior to calling
965 */
966STATIC int
f427ee49 967name2oid(char *name, int *oid, size_t *len)
1c79356b 968{
f427ee49 969 char i;
1c79356b
A
970 struct sysctl_oid *oidp;
971 struct sysctl_oid_list *lsp = &sysctl__children;
972 char *p;
973
0a7de745 974 if (!*name) {
1c79356b 975 return ENOENT;
0a7de745 976 }
1c79356b 977
0a7de745
A
978 p = name + strlen(name) - 1;
979 if (*p == '.') {
1c79356b 980 *p = '\0';
0a7de745 981 }
1c79356b
A
982
983 *len = 0;
984
0a7de745 985 for (p = name; *p && *p != '.'; p++) {
1c79356b 986 ;
0a7de745 987 }
1c79356b 988 i = *p;
0a7de745 989 if (i == '.') {
1c79356b 990 *p = '\0';
0a7de745 991 }
1c79356b
A
992
993 oidp = SLIST_FIRST(lsp);
994
995 while (oidp && *len < CTL_MAXNAME) {
996 if (strcmp(name, oidp->oid_name)) {
997 oidp = SLIST_NEXT(oidp, oid_link);
998 continue;
999 }
1000 *oid++ = oidp->oid_number;
1001 (*len)++;
1002
f427ee49 1003 if (i == '\0') {
0a7de745 1004 return 0;
1c79356b
A
1005 }
1006
0a7de745 1007 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1c79356b 1008 break;
0a7de745 1009 }
1c79356b 1010
0a7de745 1011 if (oidp->oid_handler) {
1c79356b 1012 break;
0a7de745 1013 }
1c79356b
A
1014
1015 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
1016 oidp = SLIST_FIRST(lsp);
fe8ab488 1017 *p = i; /* restore */
0a7de745
A
1018 name = p + 1;
1019 for (p = name; *p && *p != '.'; p++) {
1020 ;
1021 }
1c79356b 1022 i = *p;
0a7de745 1023 if (i == '.') {
1c79356b 1024 *p = '\0';
0a7de745 1025 }
1c79356b
A
1026 }
1027 return ENOENT;
1028}
1029
6d2010ae
A
1030/*
1031 * sysctl_sysctl_name2oid
1032 *
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
1035 * line command.
1036 *
1037 * OID: 0, 3
1038 *
1039 * Parameters: oidp __unused
1040 * arg1 __unused
1041 * arg2 __unused
1042 * req Request structure
1043 *
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
1051 *
1052 * Implicit: *req Contents of request, modified
1053 *
1054 * Locks: Acquires and then releases a read lock on the
1055 * sysctl_geometry_lock
1056 *
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.
1062 *
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.
1068 */
1069STATIC int
2d21ac55 1070sysctl_sysctl_name2oid(__unused struct sysctl_oid *oidp, __unused void *arg1,
0a7de745 1071 __unused int arg2, struct sysctl_req *req)
1c79356b
A
1072{
1073 char *p;
d9a64523 1074 int error, oid[CTL_MAXNAME] = {};
f427ee49 1075 size_t len = 0; /* set by name2oid() */
1c79356b 1076
0a7de745 1077 if (req->newlen < 1) {
1c79356b 1078 return ENOENT;
0a7de745
A
1079 }
1080 if (req->newlen >= MAXPATHLEN) { /* XXX arbitrary, undocumented */
1081 return ENAMETOOLONG;
1082 }
1c79356b 1083
0a7de745
A
1084 MALLOC(p, char *, req->newlen + 1, M_TEMP, M_WAITOK);
1085 if (!p) {
1086 return ENOMEM;
1087 }
1c79356b
A
1088
1089 error = SYSCTL_IN(req, p, req->newlen);
1090 if (error) {
1091 FREE(p, M_TEMP);
0a7de745 1092 return error;
1c79356b
A
1093 }
1094
0a7de745 1095 p[req->newlen] = '\0';
1c79356b 1096
6d2010ae
A
1097 /*
1098 * Note: We acquire and release the geometry lock here to
1099 * avoid making name2oid needlessly complex.
1100 */
1101 lck_rw_lock_shared(sysctl_geometry_lock);
1102 error = name2oid(p, oid, &len);
1103 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
1104
1105 FREE(p, M_TEMP);
1106
0a7de745
A
1107 if (error) {
1108 return error;
1109 }
1c79356b
A
1110
1111 error = SYSCTL_OUT(req, oid, len * sizeof *oid);
0a7de745 1112 return error;
1c79356b
A
1113}
1114
0a7de745
A
1115SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED, 0, 0,
1116 sysctl_sysctl_name2oid, "I", "");
1c79356b 1117
6d2010ae
A
1118/*
1119 * sysctl_sysctl_oidfmt
1120 *
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
1123 * line command.
1124 *
1125 * OID: 0, 4
1126 *
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
1131 *
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
1138 *
1139 * Implict: Contents of user request buffer, modified
1140 *
1141 * Locks: Acquires and then releases a read lock on the
1142 * sysctl_geometry_lock
1143 *
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.
1148 *
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.
1154 */
1155STATIC int
2d21ac55 1156sysctl_sysctl_oidfmt(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 1157 struct sysctl_req *req)
1c79356b 1158{
6d2010ae 1159 int *name = (int *) arg1;
0a7de745 1160 int error = ENOENT; /* default error: not found */
1c79356b 1161 u_int namelen = arg2;
2d21ac55 1162 u_int indx;
1c79356b
A
1163 struct sysctl_oid *oid;
1164 struct sysctl_oid_list *lsp = &sysctl__children;
1165
6d2010ae 1166 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b
A
1167 oid = SLIST_FIRST(lsp);
1168
1169 indx = 0;
1170 while (oid && indx < CTL_MAXNAME) {
1171 if (oid->oid_number == name[indx]) {
1172 indx++;
1173 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
0a7de745 1174 if (oid->oid_handler) {
1c79356b 1175 goto found;
0a7de745
A
1176 }
1177 if (indx == namelen) {
1c79356b 1178 goto found;
0a7de745 1179 }
1c79356b
A
1180 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
1181 oid = SLIST_FIRST(lsp);
1182 } else {
6d2010ae
A
1183 if (indx != namelen) {
1184 error = EISDIR;
1185 goto err;
1186 }
1c79356b
A
1187 goto found;
1188 }
1189 } else {
1190 oid = SLIST_NEXT(oid, oid_link);
1191 }
1192 }
6d2010ae
A
1193 /* Not found */
1194 goto err;
1195
1c79356b 1196found:
0a7de745 1197 if (!oid->oid_fmt) {
6d2010ae 1198 goto err;
0a7de745
A
1199 }
1200 error = SYSCTL_OUT(req,
1201 &oid->oid_kind, sizeof(oid->oid_kind));
1202 if (!error) {
1203 error = SYSCTL_OUT(req, oid->oid_fmt,
1204 strlen(oid->oid_fmt) + 1);
1205 }
6d2010ae
A
1206err:
1207 lck_rw_done(sysctl_geometry_lock);
0a7de745 1208 return error;
1c79356b
A
1209}
1210
6d2010ae 1211SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_oidfmt, "");
1c79356b 1212
1c79356b
A
1213
1214/*
1215 * Default "handler" functions.
1216 */
1217
1218/*
1219 * Handle an int, signed or unsigned.
1220 * Two cases:
1221 * a variable: point arg1 at it.
1222 * a constant: pass it in arg2.
1223 */
1224
1225int
2d21ac55 1226sysctl_handle_int(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 1227 struct sysctl_req *req)
1c79356b 1228{
2d21ac55 1229 return sysctl_io_number(req, arg1? *(int*)arg1: arg2, sizeof(int), arg1, NULL);
1c79356b
A
1230}
1231
1232/*
1233 * Handle a long, signed or unsigned. arg1 points to it.
1234 */
1235
1236int
2d21ac55 1237sysctl_handle_long(__unused struct sysctl_oid *oidp, void *arg1,
0a7de745 1238 __unused int arg2, struct sysctl_req *req)
1c79356b 1239{
0a7de745
A
1240 if (!arg1) {
1241 return EINVAL;
1242 }
2d21ac55 1243 return sysctl_io_number(req, *(long*)arg1, sizeof(long), arg1, NULL);
1c79356b
A
1244}
1245
43866e37
A
1246/*
1247 * Handle a quad, signed or unsigned. arg1 points to it.
1248 */
1249
1250int
2d21ac55 1251sysctl_handle_quad(__unused struct sysctl_oid *oidp, void *arg1,
0a7de745 1252 __unused int arg2, struct sysctl_req *req)
43866e37 1253{
0a7de745
A
1254 if (!arg1) {
1255 return EINVAL;
1256 }
2d21ac55 1257 return sysctl_io_number(req, *(long long*)arg1, sizeof(long long), arg1, NULL);
43866e37
A
1258}
1259
1260/*
1261 * Expose an int value as a quad.
1262 *
1263 * This interface allows us to support interfaces defined
1264 * as using quad values while the implementation is still
1265 * using ints.
1266 */
1267int
2d21ac55 1268sysctl_handle_int2quad(__unused struct sysctl_oid *oidp, void *arg1,
0a7de745 1269 __unused int arg2, struct sysctl_req *req)
43866e37
A
1270{
1271 int error = 0;
1272 long long val;
1273 int newval;
1274
0a7de745
A
1275 if (!arg1) {
1276 return EINVAL;
1277 }
43866e37
A
1278 val = (long long)*(int *)arg1;
1279 error = SYSCTL_OUT(req, &val, sizeof(long long));
1280
0a7de745
A
1281 if (error || !req->newptr) {
1282 return error;
1283 }
43866e37
A
1284
1285 error = SYSCTL_IN(req, &val, sizeof(long long));
1286 if (!error) {
1287 /*
1288 * Value must be representable; check by
1289 * casting and then casting back.
1290 */
1291 newval = (int)val;
1292 if ((long long)newval != val) {
1293 error = ERANGE;
1294 } else {
1295 *(int *)arg1 = newval;
1296 }
1297 }
0a7de745 1298 return error;
43866e37
A
1299}
1300
1c79356b
A
1301/*
1302 * Handle our generic '\0' terminated 'C' string.
1303 * Two cases:
0a7de745
A
1304 * a variable string: point arg1 at it, arg2 is max length.
1305 * a constant string: point arg1 at it, arg2 is zero.
1c79356b
A
1306 */
1307
1308int
2d21ac55 1309sysctl_handle_string( __unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 1310 struct sysctl_req *req)
1c79356b 1311{
2d21ac55 1312 return sysctl_io_string(req, arg1, arg2, 0, NULL);
1c79356b
A
1313}
1314
1315/*
1316 * Handle any kind of opaque data.
1317 * arg1 points to it, arg2 is the size.
1318 */
1319
1320int
2d21ac55 1321sysctl_handle_opaque(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
0a7de745 1322 struct sysctl_req *req)
1c79356b 1323{
2d21ac55 1324 return sysctl_io_opaque(req, arg1, arg2, NULL);
1c79356b
A
1325}
1326
1327/*
1328 * Transfer functions to/from kernel space.
1c79356b 1329 */
6d2010ae 1330STATIC int
1c79356b
A
1331sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
1332{
1333 size_t i = 0;
1c79356b
A
1334
1335 if (req->oldptr) {
1336 i = l;
0a7de745 1337 if (i > req->oldlen - req->oldidx) {
1c79356b 1338 i = req->oldlen - req->oldidx;
0a7de745
A
1339 }
1340 if (i > 0) {
2d21ac55 1341 bcopy((const void*)p, CAST_DOWN(char *, (req->oldptr + req->oldidx)), i);
0a7de745 1342 }
1c79356b
A
1343 }
1344 req->oldidx += l;
0a7de745
A
1345 if (req->oldptr && i != l) {
1346 return ENOMEM;
1347 }
1348 return 0;
1c79356b
A
1349}
1350
6d2010ae 1351STATIC int
1c79356b
A
1352sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
1353{
0a7de745 1354 if (!req->newptr) {
1c79356b 1355 return 0;
0a7de745
A
1356 }
1357 if (req->newlen - req->newidx < l) {
1358 return EINVAL;
1359 }
91447636 1360 bcopy(CAST_DOWN(char *, (req->newptr + req->newidx)), p, l);
1c79356b 1361 req->newidx += l;
0a7de745 1362 return 0;
1c79356b
A
1363}
1364
1365int
f427ee49 1366kernel_sysctl(struct proc *p, int *name, size_t namelen, void *old, size_t *oldlenp, void *new, size_t newlen)
1c79356b
A
1367{
1368 int error = 0;
1369 struct sysctl_req req;
1370
43866e37
A
1371 /*
1372 * Construct request.
1373 */
1c79356b 1374 bzero(&req, sizeof req);
1c79356b 1375 req.p = p;
0a7de745 1376 if (oldlenp) {
1c79356b 1377 req.oldlen = *oldlenp;
0a7de745
A
1378 }
1379 if (old) {
91447636 1380 req.oldptr = CAST_USER_ADDR_T(old);
0a7de745 1381 }
1c79356b
A
1382 if (newlen) {
1383 req.newlen = newlen;
91447636 1384 req.newptr = CAST_USER_ADDR_T(new);
1c79356b 1385 }
1c79356b
A
1386 req.oldfunc = sysctl_old_kernel;
1387 req.newfunc = sysctl_new_kernel;
1388 req.lock = 1;
1389
43866e37 1390 /* make the request */
fe8ab488 1391 error = sysctl_root(TRUE, FALSE, NULL, 0, name, namelen, &req);
1c79356b 1392
0a7de745
A
1393 if (error && error != ENOMEM) {
1394 return error;
1395 }
1c79356b 1396
0a7de745 1397 if (oldlenp) {
43866e37 1398 *oldlenp = req.oldidx;
0a7de745 1399 }
43866e37 1400
0a7de745 1401 return error;
1c79356b
A
1402}
1403
1404/*
1405 * Transfer function to/from user space.
1406 */
6d2010ae 1407STATIC int
1c79356b
A
1408sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1409{
1410 int error = 0;
1411 size_t i = 0;
1412
1413 if (req->oldptr) {
0a7de745
A
1414 if (req->oldlen - req->oldidx < l) {
1415 return ENOMEM;
1416 }
1c79356b 1417 i = l;
0a7de745 1418 if (i > req->oldlen - req->oldidx) {
1c79356b 1419 i = req->oldlen - req->oldidx;
0a7de745
A
1420 }
1421 if (i > 0) {
2d21ac55 1422 error = copyout((const void*)p, (req->oldptr + req->oldidx), i);
0a7de745 1423 }
1c79356b
A
1424 }
1425 req->oldidx += l;
0a7de745
A
1426 if (error) {
1427 return error;
1428 }
1429 if (req->oldptr && i < l) {
1430 return ENOMEM;
1431 }
1432 return 0;
1c79356b
A
1433}
1434
6d2010ae 1435STATIC int
1c79356b
A
1436sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1437{
1438 int error;
1439
0a7de745 1440 if (!req->newptr) {
1c79356b 1441 return 0;
0a7de745
A
1442 }
1443 if (req->newlen - req->newidx < l) {
1444 return EINVAL;
1445 }
91447636 1446 error = copyin((req->newptr + req->newidx), p, l);
1c79356b 1447 req->newidx += l;
0a7de745 1448 return error;
1c79356b
A
1449}
1450
1451/*
1452 * Traverse our tree, and find the right node, execute whatever it points
1453 * at, and return the resulting error code.
1454 */
1455
1456int
f427ee49 1457sysctl_root(boolean_t from_kernel, boolean_t string_is_canonical, char *namestring, size_t namestringlen, int *name, size_t namelen, struct sysctl_req *req)
1c79356b 1458{
2d21ac55
A
1459 u_int indx;
1460 int i;
1c79356b
A
1461 struct sysctl_oid *oid;
1462 struct sysctl_oid_list *lsp = &sysctl__children;
d9a64523 1463 sysctl_handler_t oid_handler = NULL;
1c79356b 1464 int error;
fe8ab488
A
1465 boolean_t unlocked_node_found = FALSE;
1466 boolean_t namestring_started = FALSE;
2d21ac55
A
1467
1468 /* Get the read lock on the geometry */
1469 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b 1470
fe8ab488
A
1471 if (string_is_canonical) {
1472 /* namestring is actually canonical, name/namelen needs to be populated */
1473 error = name2oid(namestring, name, &namelen);
1474 if (error) {
1475 goto err;
1476 }
1477 }
0a7de745 1478
1c79356b
A
1479 oid = SLIST_FIRST(lsp);
1480
1481 indx = 0;
1482 while (oid && indx < CTL_MAXNAME) {
1483 if (oid->oid_number == name[indx]) {
fe8ab488
A
1484 if (!from_kernel && !string_is_canonical) {
1485 if (namestring_started) {
1486 if (strlcat(namestring, ".", namestringlen) >= namestringlen) {
1487 error = ENAMETOOLONG;
1488 goto err;
1489 }
1490 }
1491
1492 if (strlcat(namestring, oid->oid_name, namestringlen) >= namestringlen) {
1493 error = ENAMETOOLONG;
1494 goto err;
1495 }
1496 namestring_started = TRUE;
1497 }
0a7de745 1498
1c79356b 1499 indx++;
0a7de745 1500 if (!(oid->oid_kind & CTLFLAG_LOCKED)) {
fe8ab488 1501 unlocked_node_found = TRUE;
2d21ac55 1502 }
0a7de745 1503 if (oid->oid_kind & CTLFLAG_NOLOCK) {
1c79356b 1504 req->lock = 0;
0a7de745 1505 }
6d2010ae
A
1506 /*
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
1510 * access value.
1511 *
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.
1517 */
1c79356b 1518 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
0a7de745 1519 if (oid->oid_handler) {
1c79356b 1520 goto found;
0a7de745
A
1521 }
1522 if (indx == namelen) {
2d21ac55
A
1523 error = ENOENT;
1524 goto err;
1525 }
1526
1c79356b
A
1527 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
1528 oid = SLIST_FIRST(lsp);
1529 } else {
0a7de745 1530 if (indx != namelen) {
2d21ac55
A
1531 error = EISDIR;
1532 goto err;
1533 }
1c79356b
A
1534 goto found;
1535 }
1536 } else {
1537 oid = SLIST_NEXT(oid, oid_link);
1538 }
1539 }
2d21ac55
A
1540 error = ENOENT;
1541 goto err;
1c79356b 1542found:
0a7de745 1543
fe8ab488
A
1544 /*
1545 * indx is the index of the first remaining OID name,
1546 * for sysctls that take them as arguments
1547 */
1548 if (!from_kernel && !string_is_canonical && (indx < namelen)) {
1549 char tempbuf[10];
1550 u_int indx2;
0a7de745 1551
fe8ab488 1552 for (indx2 = indx; indx2 < namelen; indx2++) {
0a7de745
A
1553 snprintf(tempbuf, sizeof(tempbuf), "%d", name[indx2]);
1554
fe8ab488
A
1555 if (namestring_started) {
1556 if (strlcat(namestring, ".", namestringlen) >= namestringlen) {
1557 error = ENAMETOOLONG;
1558 goto err;
1559 }
1560 }
0a7de745 1561
fe8ab488
A
1562 if (strlcat(namestring, tempbuf, namestringlen) >= namestringlen) {
1563 error = ENAMETOOLONG;
1564 goto err;
1565 }
1566 namestring_started = TRUE;
1567 }
1568 }
0a7de745 1569
1c79356b
A
1570 /* If writing isn't allowed */
1571 if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
0a7de745 1572 ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) {
2d21ac55
A
1573 error = (EPERM);
1574 goto err;
1c79356b
A
1575 }
1576
43866e37
A
1577 /*
1578 * If we're inside the kernel, the OID must be marked as kernel-valid.
43866e37 1579 */
0a7de745 1580 if (from_kernel && !(oid->oid_kind & CTLFLAG_KERN)) {
2d21ac55
A
1581 error = (EPERM);
1582 goto err;
1583 }
43866e37 1584
6d2010ae
A
1585 /*
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.
1592 */
1c79356b
A
1593 if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
1594 req->newptr && req->p &&
0a7de745 1595 (error = proc_suser(req->p))) {
2d21ac55 1596 goto err;
0a7de745 1597 }
1c79356b 1598
d9a64523
A
1599 /*
1600 * sysctl_unregister_oid() may change the handler value, so grab it
1601 * under the lock.
1602 */
1603 oid_handler = oid->oid_handler;
1604 if (!oid_handler) {
0a7de745 1605 error = EINVAL;
2d21ac55 1606 goto err;
1c79356b
A
1607 }
1608
6d2010ae
A
1609 /*
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...
1614 */
1615 OSAddAtomic(1, &oid->oid_refcnt);
1616
1617 lck_rw_done(sysctl_geometry_lock);
1618
fe8ab488
A
1619#if CONFIG_MACF
1620 if (!from_kernel) {
1621 error = mac_system_check_sysctlbyname(kauth_cred_get(),
0a7de745
A
1622 namestring,
1623 name,
1624 namelen,
1625 req->oldptr,
1626 req->oldlen,
1627 req->newptr,
1628 req->newlen);
1629 if (error) {
fe8ab488 1630 goto dropref;
0a7de745 1631 }
fe8ab488
A
1632 }
1633#endif
0a7de745 1634
6d2010ae 1635 /*
fe8ab488
A
1636 * ...however, we still have to grab the mutex for those calls which
1637 * may be into code whose reentrancy is protected by it.
6d2010ae 1638 */
0a7de745 1639 if (unlocked_node_found) {
fe8ab488 1640 lck_mtx_lock(sysctl_unlocked_node_lock);
2d21ac55 1641 }
1c79356b 1642
cb323159
A
1643#if defined(HAS_APPLE_PAC)
1644 /*
1645 * oid_handler is signed address-discriminated by sysctl_register_oid().
1646 */
f427ee49 1647 oid_handler = ptrauth_auth_and_resign(oid_handler,
cb323159
A
1648 ptrauth_key_function_pointer,
1649 ptrauth_blend_discriminator(&oid->oid_handler,
f427ee49
A
1650 os_hash_kernel_pointer(oid->oid_arg1)),
1651 ptrauth_key_function_pointer,
1652 ptrauth_function_pointer_type_discriminator(typeof(oid_handler)));
cb323159 1653#endif /* defined(HAS_APPLE_PAC) */
d9a64523 1654
1c79356b 1655 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
f427ee49 1656 i = oid_handler(oid, name + indx, (int)(namelen - indx), req);
1c79356b 1657 } else {
d9a64523 1658 i = oid_handler(oid, oid->oid_arg1, oid->oid_arg2, req);
1c79356b 1659 }
2d21ac55
A
1660 error = i;
1661
0a7de745 1662 if (unlocked_node_found) {
fe8ab488 1663 lck_mtx_unlock(sysctl_unlocked_node_lock);
2d21ac55 1664 }
1c79356b 1665
fe8ab488
A
1666#if CONFIG_MACF
1667 /* only used from another CONFIG_MACF block */
1668dropref:
1669#endif
1670
6d2010ae
A
1671 /*
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.
1679 *
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"
1683 * OIDs.
1684 */
1685 lck_rw_lock_shared(sysctl_geometry_lock);
0a7de745 1686 if (OSAddAtomic(-1, &oid->oid_refcnt) == 1) {
6d2010ae 1687 wakeup(&oid->oid_refcnt);
0a7de745 1688 }
6d2010ae 1689
2d21ac55
A
1690err:
1691 lck_rw_done(sysctl_geometry_lock);
0a7de745 1692 return error;
1c79356b
A
1693}
1694
0a7de745
A
1695void
1696sysctl_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)
fe8ab488
A
1698{
1699 bzero(req, sizeof(*req));
0a7de745 1700
fe8ab488 1701 req->p = p;
0a7de745 1702
fe8ab488
A
1703 req->oldlen = oldlen;
1704 req->oldptr = oldp;
0a7de745 1705
fe8ab488
A
1706 if (newlen) {
1707 req->newlen = newlen;
1708 req->newptr = newp;
1709 }
0a7de745 1710
fe8ab488
A
1711 req->oldfunc = sysctl_old_user;
1712 req->newfunc = sysctl_new_user;
1713 req->lock = 1;
1714
1715 return;
1716}
1c79356b
A
1717
1718int
fe8ab488 1719sysctl(proc_t p, struct sysctl_args *uap, __unused int32_t *retval)
1c79356b 1720{
cb323159 1721 int error, new_error;
fe8ab488
A
1722 size_t oldlen = 0, newlen;
1723 int name[CTL_MAXNAME];
1724 struct sysctl_req req;
1725 char *namestring;
1726 size_t namestringlen = MAXPATHLEN;
0a7de745 1727
fe8ab488
A
1728 /*
1729 * all top-level sysctl names are non-terminal
1730 */
0a7de745
A
1731 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) {
1732 return EINVAL;
1733 }
fe8ab488 1734 error = copyin(uap->name, &name[0], uap->namelen * sizeof(int));
0a7de745
A
1735 if (error) {
1736 return error;
1737 }
1738
fe8ab488 1739 AUDIT_ARG(ctlname, name, uap->namelen);
0a7de745
A
1740
1741 if (uap->newlen > SIZE_T_MAX) {
1742 return EINVAL;
1743 }
fe8ab488 1744 newlen = (size_t)uap->newlen;
0a7de745 1745
fe8ab488 1746 if (uap->oldlenp != USER_ADDR_NULL) {
0a7de745 1747 uint64_t oldlen64 = fuulong(uap->oldlenp);
fe8ab488
A
1748
1749 /*
1750 * If more than 4G, clamp to 4G
1751 */
0a7de745 1752 if (oldlen64 > SIZE_T_MAX) {
fe8ab488 1753 oldlen = SIZE_T_MAX;
0a7de745 1754 } else {
fe8ab488 1755 oldlen = (size_t)oldlen64;
0a7de745 1756 }
fe8ab488 1757 }
0a7de745 1758
fe8ab488
A
1759 sysctl_create_user_req(&req, p, uap->old, oldlen, uap->new, newlen);
1760
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" */
1767 }
0a7de745 1768 }
fe8ab488
A
1769
1770 MALLOC(namestring, char *, namestringlen, M_TEMP, M_WAITOK);
1771 if (!namestring) {
0a7de745
A
1772 oldlen = 0;
1773 goto err;
fe8ab488 1774 }
1c79356b 1775
fe8ab488 1776 error = userland_sysctl(FALSE, namestring, namestringlen, name, uap->namelen, &req, &oldlen);
0a7de745 1777
fe8ab488 1778 FREE(namestring, M_TEMP);
0a7de745
A
1779
1780 if ((error) && (error != ENOMEM)) {
1781 return error;
1782 }
1783
fe8ab488 1784err:
0a7de745 1785 if (uap->oldlenp != USER_ADDR_NULL) {
cb323159
A
1786 /*
1787 * Only overwrite the old error value on a new error
1788 */
1789 new_error = suulong(uap->oldlenp, oldlen);
1790
1791 if (new_error) {
1792 error = new_error;
1793 }
0a7de745
A
1794 }
1795
1796 return error;
fe8ab488 1797}
1c79356b 1798
cb323159
A
1799// sysctlbyname is also exported as KPI to kexts
1800// and the syscall name cannot conflict with it
fe8ab488 1801int
cb323159 1802sys_sysctlbyname(proc_t p, struct sysctlbyname_args *uap, __unused int32_t *retval)
fe8ab488 1803{
cb323159 1804 int error, new_error;
fe8ab488
A
1805 size_t oldlen = 0, newlen;
1806 char *name;
1807 size_t namelen = 0;
1808 struct sysctl_req req;
1809 int oid[CTL_MAXNAME];
1810
0a7de745
A
1811 if (uap->namelen >= MAXPATHLEN) { /* XXX arbitrary, undocumented */
1812 return ENAMETOOLONG;
1813 }
fe8ab488 1814 namelen = (size_t)uap->namelen;
0a7de745
A
1815
1816 MALLOC(name, char *, namelen + 1, M_TEMP, M_WAITOK);
1817 if (!name) {
1818 return ENOMEM;
1819 }
fe8ab488
A
1820
1821 error = copyin(uap->name, name, namelen);
1822 if (error) {
1823 FREE(name, M_TEMP);
0a7de745 1824 return error;
1c79356b 1825 }
fe8ab488
A
1826 name[namelen] = '\0';
1827
1828 /* XXX
1829 * AUDIT_ARG(ctlname, name, uap->namelen);
1830 */
0a7de745 1831
fe8ab488
A
1832 if (uap->newlen > SIZE_T_MAX) {
1833 FREE(name, M_TEMP);
0a7de745 1834 return EINVAL;
fe8ab488
A
1835 }
1836 newlen = (size_t)uap->newlen;
0a7de745 1837
fe8ab488 1838 if (uap->oldlenp != USER_ADDR_NULL) {
0a7de745
A
1839 uint64_t oldlen64 = fuulong(uap->oldlenp);
1840
fe8ab488
A
1841 /*
1842 * If more than 4G, clamp to 4G
1843 */
0a7de745 1844 if (oldlen64 > SIZE_T_MAX) {
fe8ab488 1845 oldlen = SIZE_T_MAX;
0a7de745 1846 } else {
fe8ab488 1847 oldlen = (size_t)oldlen64;
0a7de745 1848 }
fe8ab488 1849 }
0a7de745 1850
fe8ab488
A
1851 sysctl_create_user_req(&req, p, uap->old, oldlen, uap->new, newlen);
1852
0a7de745
A
1853 error = userland_sysctl(TRUE, name, namelen + 1, oid, CTL_MAXNAME, &req, &oldlen);
1854
fe8ab488
A
1855 FREE(name, M_TEMP);
1856
0a7de745
A
1857 if ((error) && (error != ENOMEM)) {
1858 return error;
1859 }
1860
1861 if (uap->oldlenp != USER_ADDR_NULL) {
cb323159
A
1862 /*
1863 * Only overwrite the old error value on a new error
1864 */
1865 new_error = suulong(uap->oldlenp, oldlen);
1866
1867 if (new_error) {
1868 error = new_error;
1869 }
0a7de745
A
1870 }
1871
1872 return error;
1c79356b
A
1873}
1874
1875/*
1876 * This is used from various compatibility syscalls too. That's why name
1877 * must be in kernel space.
1878 */
1879int
fe8ab488 1880userland_sysctl(boolean_t string_is_canonical,
0a7de745
A
1881 char *namestring, size_t namestringlen,
1882 int *name, u_int namelen, struct sysctl_req *req,
1883 size_t *retval)
1c79356b
A
1884{
1885 int error = 0;
fe8ab488 1886 struct sysctl_req req2;
1c79356b
A
1887
1888 do {
0a7de745
A
1889 /* if EAGAIN, reset output cursor */
1890 req2 = *req;
1891 if (!string_is_canonical) {
1892 namestring[0] = '\0';
1893 }
1c79356b 1894
0a7de745 1895 error = sysctl_root(FALSE, string_is_canonical, namestring, namestringlen, name, namelen, &req2);
fe8ab488 1896 } while (error == EAGAIN);
1c79356b 1897
0a7de745
A
1898 if (error && error != ENOMEM) {
1899 return error;
1900 }
1c79356b
A
1901
1902 if (retval) {
0a7de745 1903 if (req2.oldptr && req2.oldidx > req2.oldlen) {
fe8ab488 1904 *retval = req2.oldlen;
0a7de745 1905 } else {
fe8ab488 1906 *retval = req2.oldidx;
0a7de745 1907 }
1c79356b 1908 }
0a7de745 1909 return error;
1c79356b 1910}
1c79356b
A
1911
1912/*
43866e37
A
1913 * Kernel versions of the userland sysctl helper functions.
1914 *
1915 * These allow sysctl to be used in the same fashion in both
1916 * userland and the kernel.
1917 *
1918 * Note that some sysctl handlers use copyin/copyout, which
1919 * may not work correctly.
fe8ab488
A
1920 *
1921 * The "sysctlbyname" KPI for use by kexts is aliased to this function.
de355530 1922 */
1c79356b 1923
43866e37 1924int
fe8ab488 1925kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
43866e37 1926{
fe8ab488
A
1927 int oid[CTL_MAXNAME];
1928 int name2mib_oid[2];
43866e37
A
1929 int error;
1930 size_t oidlen;
de355530 1931
fe8ab488
A
1932 /* look up the OID with magic service node */
1933 name2mib_oid[0] = 0;
1934 name2mib_oid[1] = 3;
de355530 1935
fe8ab488 1936 oidlen = sizeof(oid);
3e170ce0 1937 error = kernel_sysctl(current_proc(), name2mib_oid, 2, oid, &oidlen, __DECONST(void *, name), strlen(name));
fe8ab488 1938 oidlen /= sizeof(int);
f427ee49
A
1939 if (oidlen > UINT_MAX) {
1940 error = EDOM;
1941 }
0a7de745 1942
43866e37 1943 /* now use the OID */
0a7de745 1944 if (error == 0) {
f427ee49 1945 error = kernel_sysctl(current_proc(), oid, (u_int)oidlen, oldp, oldlenp, newp, newlen);
0a7de745
A
1946 }
1947 return error;
1c79356b 1948}