1 /*
2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 *
28 *
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 <kern/counter.h>
71 #include <sys/param.h>
72 #include <sys/buf.h>
73 #include <sys/kernel.h>
74 #include <sys/sysctl.h>
75 #include <sys/malloc.h>
76 #include <sys/proc_internal.h>
77 #include <sys/kauth.h>
78 #include <sys/systm.h>
79 #include <sys/sysproto.h>
80
81 #include <vm/vm_pageout_xnu.h>
82
83 #include <os/atomic_private.h>
84
85 #include <security/audit/audit.h>
86 #include <pexpert/pexpert.h>
87
88 #include <IOKit/IOBSD.h>
89
90 #if CONFIG_MACF
91 #include <security/mac_framework.h>
92 #endif
93
94 #if defined(HAS_APPLE_PAC)
95 #include <os/hash.h>
96 #include <ptrauth.h>
97 #endif /* defined(HAS_APPLE_PAC) */
98
99 #include <libkern/coreanalytics/coreanalytics.h>
100
101 #if DEBUG || DEVELOPMENT
102 #include <os/system_event_log.h>
103 #endif /* DEBUG || DEVELOPMENT */
104
105 static LCK_GRP_DECLARE(sysctl_lock_group, "sysctl");
106 static LCK_RW_DECLARE(sysctl_geometry_lock, &sysctl_lock_group);
107 static LCK_MTX_DECLARE(sysctl_unlocked_node_lock, &sysctl_lock_group);
108
109 /*
110 * Conditionally allow dtrace to see these functions for debugging purposes.
111 */
112 #ifdef STATIC
113 #undef STATIC
114 #endif
115 #if 0
116 #define STATIC
117 #else
118 #define STATIC static
119 #endif
120
121 /* forward declarations of static functions */
122 STATIC void sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i);
123 STATIC int sysctl_sysctl_debug(struct sysctl_oid *oidp, void *arg1,
124 int arg2, struct sysctl_req *req);
125 STATIC int sysctl_sysctl_name(struct sysctl_oid *oidp, void *arg1,
126 int arg2, struct sysctl_req *req);
127 STATIC int sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp,
128 int *name, u_int namelen, int *next, int *len, int level,
129 struct sysctl_oid **oidpp);
130 STATIC int sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l);
131 STATIC int sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l);
132 STATIC int name2oid(char *name, int *oid, size_t *len);
133 STATIC int sysctl_sysctl_name2oid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
134 STATIC int sysctl_sysctl_next(struct sysctl_oid *oidp, void *arg1, int arg2,
135 struct sysctl_req *req);
136 STATIC int sysctl_sysctl_oidfmt(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
137 STATIC int sysctl_old_user(struct sysctl_req *req, const void *p, size_t l);
138 STATIC int sysctl_new_user(struct sysctl_req *req, void *p, size_t l);
139
140 STATIC void sysctl_create_user_req(struct sysctl_req *req, struct proc *p, user_addr_t oldp,
141 size_t oldlen, user_addr_t newp, size_t newlen);
142 STATIC int sysctl_root(boolean_t from_kernel, boolean_t string_is_canonical, char *namestring, size_t namestringlen, int *name, size_t namelen, struct sysctl_req *req);
143
144 int kernel_sysctl(struct proc *p, int *name, size_t namelen, void *old, size_t *oldlenp, void *new, size_t newlen);
145 int kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
146 int userland_sysctl(boolean_t string_is_canonical,
147 char *namestring, size_t namestringlen,
148 int *name, u_int namelen, struct sysctl_req *req,
149 size_t *retval);
150
151 SECURITY_READ_ONLY_LATE(struct sysctl_oid_list) sysctl__children; /* root list */
152 __SYSCTL_EXTENSION_NODE();
153
154 /*
155 * Initialization of the MIB tree.
156 *
157 * Order by number in each list.
158 */
159
160 static void
sysctl_register_oid_locked(struct sysctl_oid * new_oidp,struct sysctl_oid * oidp)161 sysctl_register_oid_locked(struct sysctl_oid *new_oidp,
162 struct sysctl_oid *oidp)
163 {
164 struct sysctl_oid_list *parent = new_oidp->oid_parent;
165 struct sysctl_oid_list *parent_rw = NULL;
166 struct sysctl_oid *p, **prevp;
167
168 p = SLIST_FIRST(parent);
169 if (p && p->oid_number == OID_MUTABLE_ANCHOR) {
170 parent_rw = p->oid_arg1;
171 }
172
173 if (oidp->oid_number == OID_AUTO) {
174 int n = OID_AUTO_START;
175
176 /*
177 * If this oid has a number OID_AUTO, give it a number which
178 * is greater than any current oid. Make sure it is at least
179 * OID_AUTO_START to leave space for pre-assigned oid numbers.
180 */
181
182 SLIST_FOREACH_PREVPTR(p, prevp, parent, oid_link) {
183 if (p->oid_number >= n) {
184 n = p->oid_number + 1;
185 }
186 }
187
188 if (parent_rw) {
189 SLIST_FOREACH_PREVPTR(p, prevp, parent_rw, oid_link) {
190 if (p->oid_number >= n) {
191 n = p->oid_number + 1;
192 }
193 }
194 }
195
196 /*
197 * Reflect the number in an allocated OID into the template
198 * of the caller for sysctl_unregister_oid() compares.
199 */
200 oidp->oid_number = new_oidp->oid_number = n;
201 } else {
202 /*
203 * Insert the oid into the parent's list in order.
204 */
205 SLIST_FOREACH_PREVPTR(p, prevp, parent, oid_link) {
206 if (oidp->oid_number == p->oid_number) {
207 panic("attempting to register a sysctl at previously registered slot : %d",
208 oidp->oid_number);
209 } else if (oidp->oid_number < p->oid_number) {
210 break;
211 }
212 }
213
214 if (parent_rw) {
215 SLIST_FOREACH_PREVPTR(p, prevp, parent_rw, oid_link) {
216 if (oidp->oid_number == p->oid_number) {
217 panic("attempting to register a sysctl at previously registered slot : %d",
218 oidp->oid_number);
219 } else if (oidp->oid_number < p->oid_number) {
220 break;
221 }
222 }
223 }
224 }
225
226 #if defined(HAS_APPLE_PAC)
227 if (oidp->oid_handler) {
228 /*
229 * Sign oid_handler address-discriminated upon installation to make it
230 * harder to replace with an arbitrary function pointer. Blend with
231 * a hash of oid_arg1 for robustness against memory corruption.
232 */
233 oidp->oid_handler = ptrauth_auth_and_resign(oidp->oid_handler,
234 ptrauth_key_function_pointer,
235 ptrauth_function_pointer_type_discriminator(typeof(oidp->oid_handler)),
236 ptrauth_key_function_pointer,
237 ptrauth_blend_discriminator(&oidp->oid_handler,
238 os_hash_kernel_pointer(oidp->oid_arg1)));
239 }
240 #endif /* defined(HAS_APPLE_PAC) */
241
242 SLIST_NEXT(oidp, oid_link) = *prevp;
243 *prevp = oidp;
244 }
245
246 void
sysctl_register_oid(struct sysctl_oid * new_oidp)247 sysctl_register_oid(struct sysctl_oid *new_oidp)
248 {
249 struct sysctl_oid *oidp;
250
251 if (new_oidp->oid_number < OID_AUTO) {
252 panic("trying to register a node %p with an invalid oid_number: %d",
253 new_oidp, new_oidp->oid_number);
254 }
255 if (new_oidp->oid_kind & CTLFLAG_PERMANENT) {
256 panic("Use sysctl_register_oid_early to register permanent nodes");
257 }
258
259 /*
260 * The OID can be old-style (needs copy), new style without an earlier
261 * version (also needs copy), or new style with a matching version (no
262 * copy needed). Later versions are rejected (presumably, the OID
263 * structure was changed for a necessary reason).
264 */
265 if (!(new_oidp->oid_kind & CTLFLAG_OID2)) {
266 #if __x86_64__
267 oidp = kalloc_type(struct sysctl_oid, Z_WAITOK | Z_ZERO | Z_NOFAIL);
268 /*
269 * Copy the structure only through the oid_fmt field, which
270 * is the last field in a non-OID2 OID structure.
271 *
272 * Note: We may want to set the oid_descr to the
273 * oid_name (or "") at some future date.
274 */
275 memcpy(oidp, new_oidp, offsetof(struct sysctl_oid, oid_descr));
276 #else
277 panic("Old style sysctl without a version number isn't supported");
278 #endif
279 } else {
280 /* It's a later version; handle the versions we know about */
281 switch (new_oidp->oid_version) {
282 case SYSCTL_OID_VERSION:
283 /* current version */
284 oidp = new_oidp;
285 break;
286 default:
287 return; /* rejects unknown version */
288 }
289 }
290
291 lck_rw_lock_exclusive(&sysctl_geometry_lock);
292 sysctl_register_oid_locked(new_oidp, oidp);
293 lck_rw_unlock_exclusive(&sysctl_geometry_lock);
294 }
295
296 __startup_func
297 void
sysctl_register_oid_early(struct sysctl_oid * oidp)298 sysctl_register_oid_early(struct sysctl_oid *oidp)
299 {
300 assert((oidp->oid_kind & CTLFLAG_OID2) &&
301 (oidp->oid_kind & CTLFLAG_PERMANENT) &&
302 oidp->oid_version == SYSCTL_OID_VERSION);
303 assert(startup_phase < STARTUP_SUB_SYSCTL);
304
305 /*
306 * Clear the flag so that callers can use sysctl_register_oid_early
307 * again if they wish to register their node.
308 */
309 if (oidp->oid_kind & CTLFLAG_NOAUTO) {
310 oidp->oid_kind &= ~CTLFLAG_NOAUTO;
311 return;
312 }
313
314 sysctl_register_oid_locked(oidp, oidp);
315 }
316
317 void
sysctl_unregister_oid(struct sysctl_oid * oidp)318 sysctl_unregister_oid(struct sysctl_oid *oidp)
319 {
320 struct sysctl_oid *removed_oidp = NULL; /* OID removed from tree */
321 #if __x86_64__
322 struct sysctl_oid *old_oidp = NULL; /* OID compatibility copy */
323 #endif
324 struct sysctl_oid_list *lsp;
325
326 /* Get the write lock to modify the geometry */
327 lck_rw_lock_exclusive(&sysctl_geometry_lock);
328
329 lsp = oidp->oid_parent;
330 if (SLIST_FIRST(lsp) && SLIST_FIRST(lsp)->oid_number == OID_MUTABLE_ANCHOR) {
331 lsp = SLIST_FIRST(lsp)->oid_arg1;
332 }
333
334 if (oidp->oid_kind & CTLFLAG_PERMANENT) {
335 panic("Trying to unregister permanent sysctl %p", oidp);
336 }
337
338 if (!(oidp->oid_kind & CTLFLAG_OID2)) {
339 #if __x86_64__
340 /*
341 * We're using a copy so we can get the new fields in an
342 * old structure, so we have to iterate to compare the
343 * partial structure; when we find a match, we remove it
344 * normally and free the memory.
345 */
346 SLIST_FOREACH(old_oidp, lsp, oid_link) {
347 if (!memcmp(&oidp->oid_number, &old_oidp->oid_number, (offsetof(struct sysctl_oid, oid_descr) - offsetof(struct sysctl_oid, oid_number)))) {
348 break;
349 }
350 }
351 if (old_oidp != NULL) {
352 SLIST_REMOVE(lsp, old_oidp, sysctl_oid, oid_link);
353 removed_oidp = old_oidp;
354 }
355 #else
356 panic("Old style sysctl without a version number isn't supported");
357 #endif
358 } else {
359 /* It's a later version; handle the versions we know about */
360 switch (oidp->oid_version) {
361 case SYSCTL_OID_VERSION:
362 /* We can just remove the OID directly... */
363 SLIST_REMOVE(lsp, oidp, sysctl_oid, oid_link);
364 removed_oidp = oidp;
365 break;
366 default:
367 /* XXX: Can't happen; probably tree coruption.*/
368 break; /* rejects unknown version */
369 }
370 }
371
372 #if defined(HAS_APPLE_PAC)
373 if (removed_oidp && removed_oidp->oid_handler) {
374 /*
375 * Revert address-discriminated signing performed by
376 * sysctl_register_oid() (in case this oid is registered again).
377 */
378 removed_oidp->oid_handler = ptrauth_auth_and_resign(removed_oidp->oid_handler,
379 ptrauth_key_function_pointer,
380 ptrauth_blend_discriminator(&removed_oidp->oid_handler,
381 os_hash_kernel_pointer(removed_oidp->oid_arg1)),
382 ptrauth_key_function_pointer,
383 ptrauth_function_pointer_type_discriminator(typeof(removed_oidp->oid_handler)));
384 }
385 #endif /* defined(HAS_APPLE_PAC) */
386
387 /*
388 * We've removed it from the list at this point, but we don't want
389 * to return to the caller until all handler references have drained
390 * out. Doing things in this order prevent other people coming in
391 * and starting new operations against the OID node we want removed.
392 *
393 * Note: oidp could be NULL if it wasn't found.
394 */
395 while (removed_oidp && removed_oidp->oid_refcnt) {
396 lck_rw_sleep(&sysctl_geometry_lock, LCK_SLEEP_EXCLUSIVE,
397 &removed_oidp->oid_refcnt, THREAD_UNINT);
398 }
399
400 /* Release the write lock */
401 lck_rw_unlock_exclusive(&sysctl_geometry_lock);
402
403 #if __x86_64__
404 /* If it was allocated, free it after dropping the lock */
405 kfree_type(struct sysctl_oid, old_oidp);
406 #endif
407 }
408
409 /*
410 * Exported in BSDKernel.exports, kept for binary compatibility
411 */
412 #if defined(__x86_64__)
413 void
sysctl_register_fixed(void)414 sysctl_register_fixed(void)
415 {
416 }
417 #endif
418
419 /*
420 * New handler interface
421 * If the sysctl caller (user mode or kernel mode) is interested in the
422 * value (req->oldptr != NULL), we copy the data (bigValue etc.) out,
423 * if the caller wants to set the value (req->newptr), we copy
424 * the data in (*pValue etc.).
425 */
426
427 int
sysctl_io_number(struct sysctl_req * req,long long bigValue,size_t valueSize,void * pValue,int * changed)428 sysctl_io_number(struct sysctl_req *req, long long bigValue, size_t valueSize, void *pValue, int *changed)
429 {
430 int smallValue;
431 int error;
432
433 if (changed) {
434 *changed = 0;
435 }
436
437 /*
438 * Handle the various combinations of caller buffer size and
439 * data value size. We are generous in the case where the
440 * caller has specified a 32-bit buffer but the value is 64-bit
441 * sized.
442 */
443
444 /* 32 bit value expected or 32 bit buffer offered */
445 if (((valueSize == sizeof(int)) ||
446 ((req->oldlen == sizeof(int)) && (valueSize == sizeof(long long))))
447 && (req->oldptr)) {
448 smallValue = (int)bigValue;
449 if ((long long)smallValue != bigValue) {
450 return ERANGE;
451 }
452 error = SYSCTL_OUT(req, &smallValue, sizeof(smallValue));
453 } else {
454 /* any other case is either size-equal or a bug */
455 error = SYSCTL_OUT(req, &bigValue, valueSize);
456 }
457 /* error or nothing to set */
458 if (error || !req->newptr) {
459 return error;
460 }
461
462 /* set request for constant */
463 if (pValue == NULL) {
464 return EPERM;
465 }
466
467 /* set request needs to convert? */
468 if ((req->newlen == sizeof(int)) && (valueSize == sizeof(long long))) {
469 /* new value is 32 bits, upconvert to 64 bits */
470 error = SYSCTL_IN(req, &smallValue, sizeof(smallValue));
471 if (!error) {
472 *(long long *)pValue = (long long)smallValue;
473 }
474 } else if ((req->newlen == sizeof(long long)) && (valueSize == sizeof(int))) {
475 /* new value is 64 bits, downconvert to 32 bits and range check */
476 error = SYSCTL_IN(req, &bigValue, sizeof(bigValue));
477 if (!error) {
478 smallValue = (int)bigValue;
479 if ((long long)smallValue != bigValue) {
480 return ERANGE;
481 }
482 *(int *)pValue = smallValue;
483 }
484 } else {
485 /* sizes match, just copy in */
486 error = SYSCTL_IN(req, pValue, valueSize);
487 }
488 if (!error && changed) {
489 *changed = 1;
490 }
491 return error;
492 }
493
494 int
sysctl_io_string(struct sysctl_req * req,char * pValue,size_t valueSize,int trunc,int * changed)495 sysctl_io_string(struct sysctl_req *req, char *pValue, size_t valueSize, int trunc, int *changed)
496 {
497 int error;
498 size_t len = strlen(pValue) + 1;
499
500 if (changed) {
501 *changed = 0;
502 }
503
504 if (trunc && req->oldptr && req->oldlen && (req->oldlen < len)) {
505 /* If trunc != 0, if you give it a too small (but larger than
506 * 0 bytes) buffer, instead of returning ENOMEM, it truncates the
507 * returned string to the buffer size. This preserves the semantics
508 * of some library routines implemented via sysctl, which truncate
509 * their returned data, rather than simply returning an error. The
510 * returned string is always nul (ascii '\0') terminated. */
511 error = SYSCTL_OUT(req, pValue, req->oldlen - 1);
512 if (!error) {
513 char c = '\0';
514 error = SYSCTL_OUT(req, &c, 1);
515 }
516 } else {
517 /* Copy string out */
518 error = SYSCTL_OUT(req, pValue, len);
519 }
520
521 /* error or no new value */
522 if (error || !req->newptr) {
523 return error;
524 }
525
526 /* attempt to set read-only value */
527 if (valueSize == 0) {
528 return EPERM;
529 }
530
531 /* make sure there's room for the new string */
532 if (req->newlen >= valueSize) {
533 return EINVAL;
534 }
535
536 /* copy the string in and force nul termination */
537 error = SYSCTL_IN(req, pValue, req->newlen);
538 pValue[req->newlen] = '\0';
539
540 if (!error && changed) {
541 *changed = 1;
542 }
543 return error;
544 }
545
546 int
sysctl_io_opaque(struct sysctl_req * req,void * pValue,size_t valueSize,int * changed)547 sysctl_io_opaque(struct sysctl_req *req, void *pValue, size_t valueSize, int *changed)
548 {
549 int error;
550
551 if (changed) {
552 *changed = 0;
553 }
554
555 /* Copy blob out */
556 error = SYSCTL_OUT(req, pValue, valueSize);
557
558 /* error or nothing to set */
559 if (error || !req->newptr) {
560 return error;
561 }
562
563 error = SYSCTL_IN(req, pValue, valueSize);
564
565 if (!error && changed) {
566 *changed = 1;
567 }
568 return error;
569 }
570
571 /*
572 * SYSCTL_OID enumerators
573 *
574 * Because system OIDs are immutable, they are composed of 2 lists hanging from
575 * a first dummy OID_MUTABLE_ANCHOR node that has an immutable list hanging from
576 * its `oid_parent` field and a mutable list hanging from its oid_arg1 one.
577 *
578 * Those enumerators abstract away the implicit merging of those two lists in
579 * two possible order:
580 * - oid_number order (which will interleave both sorted lists)
581 * - system order which will list the immutable list first,
582 * and the mutable list second.
583 */
584 struct sysctl_oid_iterator {
585 struct sysctl_oid *a;
586 struct sysctl_oid *b;
587 };
588
589 static struct sysctl_oid_iterator
sysctl_oid_iterator_begin(struct sysctl_oid_list * l)590 sysctl_oid_iterator_begin(struct sysctl_oid_list *l)
591 {
592 struct sysctl_oid_iterator it = { };
593 struct sysctl_oid *a = SLIST_FIRST(l);
594
595 if (a == NULL) {
596 return it;
597 }
598
599 if (a->oid_number == OID_MUTABLE_ANCHOR) {
600 it.a = SLIST_NEXT(a, oid_link);
601 it.b = SLIST_FIRST((struct sysctl_oid_list *)a->oid_arg1);
602 } else {
603 it.a = a;
604 }
605 return it;
606 }
607
608 static struct sysctl_oid *
sysctl_oid_iterator_next_num_order(struct sysctl_oid_iterator * it)609 sysctl_oid_iterator_next_num_order(struct sysctl_oid_iterator *it)
610 {
611 struct sysctl_oid *a = it->a;
612 struct sysctl_oid *b = it->b;
613
614 if (a == NULL && b == NULL) {
615 return NULL;
616 }
617
618 if (a == NULL) {
619 it->b = SLIST_NEXT(b, oid_link);
620 return b;
621 }
622
623 if (b == NULL || a->oid_number <= b->oid_number) {
624 it->a = SLIST_NEXT(a, oid_link);
625 return a;
626 }
627
628 it->b = SLIST_NEXT(b, oid_link);
629 return b;
630 }
631
632 #define SYSCTL_OID_FOREACH_NUM_ORDER(oidp, l) \
633 for (struct sysctl_oid_iterator it = sysctl_oid_iterator_begin(l); \
634 ((oidp) = sysctl_oid_iterator_next_num_order(&it)); )
635
636 static struct sysctl_oid *
sysctl_oid_iterator_next_system_order(struct sysctl_oid_iterator * it)637 sysctl_oid_iterator_next_system_order(struct sysctl_oid_iterator *it)
638 {
639 struct sysctl_oid *a = it->a;
640 struct sysctl_oid *b = it->b;
641
642 if (a) {
643 it->a = SLIST_NEXT(a, oid_link);
644 return a;
645 }
646
647 if (b) {
648 it->b = SLIST_NEXT(b, oid_link);
649 return b;
650 }
651
652 return NULL;
653 }
654
655 #define SYSCTL_OID_FOREACH_SYS_ORDER(oidp, l) \
656 for (struct sysctl_oid_iterator it = sysctl_oid_iterator_begin(l); \
657 ((oidp) = sysctl_oid_iterator_next_system_order(&it)); )
658
659 /*
660 * "Staff-functions"
661 *
662 * These functions implement a presently undocumented interface
663 * used by the sysctl program to walk the tree, and get the type
664 * so it can print the value.
665 * This interface is under work and consideration, and should probably
666 * be killed with a big axe by the first person who can find the time.
667 * (be aware though, that the proper interface isn't as obvious as it
668 * may seem, there are various conflicting requirements.
669 *
670 * {0,0} printf the entire MIB-tree.
671 * {0,1,...} return the name of the "..." OID.
672 * {0,2,...} return the next OID.
673 * {0,3} return the OID of the name in "new"
674 * {0,4,...} return the kind & format info for the "..." OID.
675 */
676
677 /*
678 * sysctl_sysctl_debug_dump_node
679 *
680 * Description: Dump debug information for a given sysctl_oid_list at the
681 * given oid depth out to the kernel log, via printf
682 *
683 * Parameters: l sysctl_oid_list pointer
684 * i current node depth
685 *
686 * Returns: (void)
687 *
688 * Implicit: kernel log, modified
689 *
690 * Locks: Assumes sysctl_geometry_lock is held prior to calling
691 *
692 * Notes: This function may call itself recursively to resolve Node
693 * values, which potentially have an inferioer sysctl_oid_list
694 *
695 * This function is only callable indirectly via the function
696 * sysctl_sysctl_debug()
697 *
698 * Bugs: The node depth indentation does not work; this may be an
699 * artifact of leading space removal by the log daemon itself
700 * or some intermediate routine.
701 */
702 STATIC void
sysctl_sysctl_debug_dump_node(struct sysctl_oid_list * l,int i)703 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
704 {
705 struct sysctl_oid *oidp;
706 struct sysctl_oid_list *lp;
707 const char *what;
708
709 SYSCTL_OID_FOREACH_SYS_ORDER(oidp, l) {
710 switch (oidp->oid_kind & CTLTYPE) {
711 case CTLTYPE_NODE:
712 lp = oidp->oid_arg1;
713 what = "Node ";
714 if (lp && SLIST_FIRST(lp) &&
715 SLIST_FIRST(lp)->oid_number == OID_MUTABLE_ANCHOR) {
716 what = "NodeExt";
717 } else {
718 }
719 break;
720 case CTLTYPE_INT:
721 what = "Int ";
722 break;
723 case CTLTYPE_STRING:
724 what = "String ";
725 break;
726 case CTLTYPE_QUAD:
727 what = "Quad ";
728 break;
729 case CTLTYPE_OPAQUE:
730 what = "Opaque ";
731 break;
732 default:
733 what = "Unknown";
734 break;
735 }
736
737 printf("%*s%-3d[%c%c%c%c%c] %s %s\n", i, "", oidp->oid_number,
738 oidp->oid_kind & CTLFLAG_LOCKED ? 'L':' ',
739 oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
740 oidp->oid_kind & CTLFLAG_WR ? 'W':' ',
741 oidp->oid_kind & CTLFLAG_PERMANENT ? ' ':'*',
742 oidp->oid_handler ? 'h' : ' ',
743 what, oidp->oid_name);
744
745 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
746 if (!oidp->oid_handler) {
747 sysctl_sysctl_debug_dump_node(lp, i + 2);
748 }
749 }
750 }
751 }
752
753 /*
754 * sysctl_sysctl_debug
755 *
756 * Description: This function implements the "sysctl.debug" portion of the
757 * OID space for sysctl.
758 *
759 * OID: 0, 0
760 *
761 * Parameters: __unused
762 *
763 * Returns: ENOENT
764 *
765 * Implicit: kernel log, modified
766 *
767 * Locks: Acquires and then releases a read lock on the
768 * sysctl_geometry_lock
769 */
770 STATIC int
sysctl_sysctl_debug(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,__unused struct sysctl_req * req)771 sysctl_sysctl_debug(__unused struct sysctl_oid *oidp, __unused void *arg1,
772 __unused int arg2, __unused struct sysctl_req *req)
773 {
774 lck_rw_lock_shared(&sysctl_geometry_lock);
775 sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
776 lck_rw_done(&sysctl_geometry_lock);
777 return ENOENT;
778 }
779
780 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
781 0, 0, sysctl_sysctl_debug, "-", "");
782
783 /*
784 * sysctl_sysctl_name
785 *
786 * Description: Convert an OID into a string name; this is used by the user
787 * space sysctl() command line utility; this is done in a purely
788 * advisory capacity (e.g. to provide node names for "sysctl -A"
789 * output).
790 *
791 * OID: 0, 1
792 *
793 * Parameters: oidp __unused
794 * arg1 A pointer to the OID name list
795 * integer array, beginning at
796 * adjusted option base 2
797 * arg2 The number of elements which
798 * remain in the name array
799 *
800 * Returns: 0 Success
801 * SYSCTL_OUT:EPERM Permission denied
802 * SYSCTL_OUT:EFAULT Bad user supplied buffer
803 * SYSCTL_OUT:??? Return value from user function
804 * for SYSCTL_PROC leaf node
805 *
806 * Implict: Contents of user request buffer, modified
807 *
808 * Locks: Acquires and then releases a read lock on the
809 * sysctl_geometry_lock
810 *
811 * Notes: SPI (System Programming Interface); this is subject to change
812 * and may not be relied upon by third party applications; use
813 * a subprocess to communicate with the "sysctl" command line
814 * command instead, if you believe you need this functionality.
815 * Preferrably, use sysctlbyname() instead.
816 *
817 * Setting of the NULL termination of the output string is
818 * delayed until after the geometry lock is dropped. If there
819 * are no Entries remaining in the OID name list when this
820 * function is called, it will still write out the termination
821 * byte.
822 *
823 * This function differs from other sysctl functions in that
824 * it can not take an output buffer length of 0 to determine the
825 * space which will be required. It is suggested that the buffer
826 * length be PATH_MAX, and that authors of new sysctl's refrain
827 * from exceeding this string length.
828 */
829 STATIC int
sysctl_sysctl_name(__unused struct sysctl_oid * oidp,void * arg1,int arg2,struct sysctl_req * req)830 sysctl_sysctl_name(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
831 struct sysctl_req *req)
832 {
833 int *name = (int *) arg1;
834 u_int namelen = arg2;
835 int error = 0;
836 struct sysctl_oid *oid;
837 struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
838 char tempbuf[10] = {};
839
840 lck_rw_lock_shared(&sysctl_geometry_lock);
841 while (namelen) {
842 if (!lsp) {
843 snprintf(tempbuf, sizeof(tempbuf), "%d", *name);
844 if (req->oldidx) {
845 error = SYSCTL_OUT(req, ".", 1);
846 }
847 if (!error) {
848 error = SYSCTL_OUT(req, tempbuf, strlen(tempbuf));
849 }
850 if (error) {
851 lck_rw_done(&sysctl_geometry_lock);
852 return error;
853 }
854 namelen--;
855 name++;
856 continue;
857 }
858 lsp2 = 0;
859 SYSCTL_OID_FOREACH_NUM_ORDER(oid, lsp) {
860 if (oid->oid_number != *name) {
861 continue;
862 }
863
864 if (req->oldidx) {
865 error = SYSCTL_OUT(req, ".", 1);
866 }
867 if (!error) {
868 error = SYSCTL_OUT(req, oid->oid_name,
869 strlen(oid->oid_name));
870 }
871 if (error) {
872 lck_rw_done(&sysctl_geometry_lock);
873 return error;
874 }
875
876 namelen--;
877 name++;
878
879 if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
880 break;
881 }
882
883 if (oid->oid_handler) {
884 break;
885 }
886
887 lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
888 break;
889 }
890 lsp = lsp2;
891 }
892 lck_rw_done(&sysctl_geometry_lock);
893 return SYSCTL_OUT(req, "", 1);
894 }
895
896 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_name, "");
897
898 /*
899 * sysctl_sysctl_next_ls
900 *
901 * Description: For a given OID name value, return the next consecutive OID
902 * name value within the geometry tree
903 *
904 * Parameters: lsp The OID list to look in
905 * name The OID name to start from
906 * namelen The length of the OID name
907 * next Pointer to new oid storage to
908 * fill in
909 * len Pointer to receive new OID
910 * length value of storage written
911 * level OID tree depth (used to compute
912 * len value)
913 * oidpp Pointer to OID list entry
914 * pointer; used to walk the list
915 * forward across recursion
916 *
917 * Returns: 0 Returning a new entry
918 * 1 End of geometry list reached
919 *
920 * Implicit: *next Modified to contain the new OID
921 * *len Modified to contain new length
922 *
923 * Locks: Assumes sysctl_geometry_lock is held prior to calling
924 *
925 * Notes: This function will not return OID values that have special
926 * handlers, since we can not tell wheter these handlers consume
927 * elements from the OID space as parameters. For this reason,
928 * we STRONGLY discourage these types of handlers
929 */
930 STATIC int
sysctl_sysctl_next_ls(struct sysctl_oid_list * lsp,int * name,u_int namelen,int * next,int * len,int level,struct sysctl_oid ** oidpp)931 sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
932 int *next, int *len, int level, struct sysctl_oid **oidpp)
933 {
934 struct sysctl_oid *oidp;
935
936 *len = level;
937 SYSCTL_OID_FOREACH_NUM_ORDER(oidp, lsp) {
938 *next = oidp->oid_number;
939 *oidpp = oidp;
940
941 if (!namelen) {
942 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
943 return 0;
944 }
945 if (oidp->oid_handler) {
946 /* We really should call the handler here...*/
947 return 0;
948 }
949 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
950
951 if (!SLIST_FIRST(lsp)) {
952 /* This node had no children - skip it! */
953 continue;
954 }
955
956 if (!sysctl_sysctl_next_ls(lsp, 0, 0, next + 1,
957 len, level + 1, oidpp)) {
958 return 0;
959 }
960 goto next;
961 }
962
963 if (oidp->oid_number < *name) {
964 continue;
965 }
966
967 if (oidp->oid_number > *name) {
968 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
969 return 0;
970 }
971 if (oidp->oid_handler) {
972 return 0;
973 }
974 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
975 if (!sysctl_sysctl_next_ls(lsp, name + 1, namelen - 1,
976 next + 1, len, level + 1, oidpp)) {
977 return 0;
978 }
979 goto next;
980 }
981 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
982 continue;
983 }
984
985 if (oidp->oid_handler) {
986 continue;
987 }
988
989 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
990 if (!sysctl_sysctl_next_ls(lsp, name + 1, namelen - 1, next + 1,
991 len, level + 1, oidpp)) {
992 return 0;
993 }
994 next:
995 /* We expect to be reducing namelen here, don't reset to 1 if this
996 * is actually an increase.
997 */
998 if (namelen > 1) {
999 namelen = 1;
1000 }
1001 *len = level;
1002 }
1003 return 1;
1004 }
1005
1006 /*
1007 * sysctl_sysctl_next
1008 *
1009 * Description: This is an iterator function designed to iterate the oid tree
1010 * and provide a list of OIDs for use by the user space "sysctl"
1011 * command line tool
1012 *
1013 * OID: 0, 2
1014 *
1015 * Parameters: oidp __unused
1016 * arg1 Pointer to start OID name
1017 * arg2 Start OID name length
1018 * req Pointer to user request buffer
1019 *
1020 * Returns: 0 Success
1021 * ENOENT Reached end of OID space
1022 * SYSCTL_OUT:EPERM Permission denied
1023 * SYSCTL_OUT:EFAULT Bad user supplied buffer
1024 * SYSCTL_OUT:??? Return value from user function
1025 * for SYSCTL_PROC leaf node
1026 *
1027 * Implict: Contents of user request buffer, modified
1028 *
1029 * Locks: Acquires and then releases a read lock on the
1030 * sysctl_geometry_lock
1031 *
1032 * Notes: SPI (System Programming Interface); this is subject to change
1033 * and may not be relied upon by third party applications; use
1034 * a subprocess to communicate with the "sysctl" command line
1035 * command instead, if you believe you need this functionality.
1036 * Preferrably, use sysctlbyname() instead.
1037 *
1038 * This function differs from other sysctl functions in that
1039 * it can not take an output buffer length of 0 to determine the
1040 * space which will be required. It is suggested that the buffer
1041 * length be PATH_MAX, and that authors of new sysctl's refrain
1042 * from exceeding this string length.
1043 */
1044 STATIC int
sysctl_sysctl_next(__unused struct sysctl_oid * oidp,void * arg1,int arg2,struct sysctl_req * req)1045 sysctl_sysctl_next(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
1046 struct sysctl_req *req)
1047 {
1048 int *name = (int *) arg1;
1049 u_int namelen = arg2;
1050 int i, j, error;
1051 struct sysctl_oid *oid;
1052 struct sysctl_oid_list *lsp = &sysctl__children;
1053 int newoid[CTL_MAXNAME] = {};
1054
1055 lck_rw_lock_shared(&sysctl_geometry_lock);
1056 i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
1057 lck_rw_done(&sysctl_geometry_lock);
1058 if (i) {
1059 return ENOENT;
1060 }
1061 error = SYSCTL_OUT(req, newoid, j * sizeof(int));
1062 return error;
1063 }
1064
1065 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_next, "");
1066
1067 /*
1068 * name2oid
1069 *
1070 * Description: Support function for use by sysctl_sysctl_name2oid(); looks
1071 * up an OID name given a string name.
1072 *
1073 * Parameters: name NULL terminated string name
1074 * oid Pointer to receive OID name
1075 * len Pointer to receive OID length
1076 * pointer value (see "Notes")
1077 *
1078 * Returns: 0 Success
1079 * ENOENT Entry not found
1080 *
1081 * Implicit: *oid Modified to contain OID value
1082 * *len Modified to contain OID length
1083 *
1084 * Locks: Assumes sysctl_geometry_lock is held prior to calling
1085 */
1086 STATIC int
name2oid(char * name,int * oid,size_t * len)1087 name2oid(char *name, int *oid, size_t *len)
1088 {
1089 struct sysctl_oid_iterator it;
1090 struct sysctl_oid *oidp;
1091 char *p;
1092 char i;
1093
1094 if (!*name) {
1095 return ENOENT;
1096 }
1097
1098 p = name + strlen(name) - 1;
1099 if (*p == '.') {
1100 *p = '\0';
1101 }
1102
1103 *len = 0;
1104
1105 for (p = name; *p && *p != '.'; p++) {
1106 ;
1107 }
1108 i = *p;
1109 if (i == '.') {
1110 *p = '\0';
1111 }
1112
1113 it = sysctl_oid_iterator_begin(&sysctl__children);
1114 oidp = sysctl_oid_iterator_next_system_order(&it);
1115
1116 while (oidp && *len < CTL_MAXNAME) {
1117 if (strcmp(name, oidp->oid_name)) {
1118 oidp = sysctl_oid_iterator_next_system_order(&it);
1119 continue;
1120 }
1121 *oid++ = oidp->oid_number;
1122 (*len)++;
1123
1124 if (i == '\0') {
1125 return 0;
1126 }
1127
1128 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) {
1129 break;
1130 }
1131
1132 if (oidp->oid_handler) {
1133 break;
1134 }
1135
1136 it = sysctl_oid_iterator_begin(oidp->oid_arg1);
1137 oidp = sysctl_oid_iterator_next_system_order(&it);
1138
1139 *p = i; /* restore */
1140 name = p + 1;
1141 for (p = name; *p && *p != '.'; p++) {
1142 ;
1143 }
1144 i = *p;
1145 if (i == '.') {
1146 *p = '\0';
1147 }
1148 }
1149 return ENOENT;
1150 }
1151
1152 /*
1153 * sysctl_sysctl_name2oid
1154 *
1155 * Description: Translate a string name to an OID name value; this is used by
1156 * the sysctlbyname() function as well as by the "sysctl" command
1157 * line command.
1158 *
1159 * OID: 0, 3
1160 *
1161 * Parameters: oidp __unused
1162 * arg1 __unused
1163 * arg2 __unused
1164 * req Request structure
1165 *
1166 * Returns: ENOENT Input length too short
1167 * ENAMETOOLONG Input length too long
1168 * ENOMEM Could not allocate work area
1169 * SYSCTL_IN/OUT:EPERM Permission denied
1170 * SYSCTL_IN/OUT:EFAULT Bad user supplied buffer
1171 * SYSCTL_IN/OUT:??? Return value from user function
1172 * name2oid:ENOENT Not found
1173 *
1174 * Implicit: *req Contents of request, modified
1175 *
1176 * Locks: Acquires and then releases a read lock on the
1177 * sysctl_geometry_lock
1178 *
1179 * Notes: SPI (System Programming Interface); this is subject to change
1180 * and may not be relied upon by third party applications; use
1181 * a subprocess to communicate with the "sysctl" command line
1182 * command instead, if you believe you need this functionality.
1183 * Preferrably, use sysctlbyname() instead.
1184 *
1185 * This function differs from other sysctl functions in that
1186 * it can not take an output buffer length of 0 to determine the
1187 * space which will be required. It is suggested that the buffer
1188 * length be PATH_MAX, and that authors of new sysctl's refrain
1189 * from exceeding this string length.
1190 */
1191 STATIC int
sysctl_sysctl_name2oid(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1192 sysctl_sysctl_name2oid(__unused struct sysctl_oid *oidp, __unused void *arg1,
1193 __unused int arg2, struct sysctl_req *req)
1194 {
1195 char *p;
1196 int error, oid[CTL_MAXNAME] = {};
1197 size_t len = 0; /* set by name2oid() */
1198
1199 if (req->newlen < 1) {
1200 return ENOENT;
1201 }
1202 if (req->newlen >= MAXPATHLEN) { /* XXX arbitrary, undocumented */
1203 return ENAMETOOLONG;
1204 }
1205
1206 p = (char *)kalloc_data(req->newlen + 1, Z_WAITOK);
1207 if (!p) {
1208 return ENOMEM;
1209 }
1210
1211 error = SYSCTL_IN(req, p, req->newlen);
1212 if (error) {
1213 kfree_data(p, req->newlen + 1);
1214 return error;
1215 }
1216
1217 p[req->newlen] = '\0';
1218
1219 /*
1220 * Note: We acquire and release the geometry lock here to
1221 * avoid making name2oid needlessly complex.
1222 */
1223 lck_rw_lock_shared(&sysctl_geometry_lock);
1224 error = name2oid(p, oid, &len);
1225 lck_rw_done(&sysctl_geometry_lock);
1226
1227 kfree_data(p, req->newlen + 1);
1228
1229 if (error) {
1230 return error;
1231 }
1232
1233 error = SYSCTL_OUT(req, oid, len * sizeof *oid);
1234 return error;
1235 }
1236
1237 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED, 0, 0,
1238 sysctl_sysctl_name2oid, "I", "");
1239
1240 /*
1241 * find_oid_by_name
1242 *
1243 * Description: Support function for use by sysctl_sysctl_oidfmt() and
1244 * sysctl_sysctl_oiddescr()); looks up an OID given an
1245 * OID name.
1246 *
1247 * Parameters: name A pointer to the OID name list
1248 * integer array
1249 * namelen The length of the OID name
1250 * oidp Pointer to receive OID pointer
1251 *
1252 * Returns: 0 Success
1253 * ENOENT Entry not found
1254 * EISDIR Malformed request
1255 *
1256 * Implicit: *oidp Modified to contain pointer to
1257 * the OID, or NULL if not found
1258 *
1259 * Locks: Assumes sysctl_geometry_lock is held prior to calling
1260 */
1261 STATIC int
find_oid_by_name(int * name,u_int namelen,struct sysctl_oid ** oidp)1262 find_oid_by_name(int *name, u_int namelen, struct sysctl_oid **oidp)
1263 {
1264 LCK_RW_ASSERT(&sysctl_geometry_lock, LCK_RW_ASSERT_SHARED);
1265
1266 struct sysctl_oid_iterator it = sysctl_oid_iterator_begin(&sysctl__children);
1267 struct sysctl_oid *oid = sysctl_oid_iterator_next_system_order(&it);
1268
1269 u_int indx = 0;
1270
1271 *oidp = NULL;
1272
1273 while (oid && indx < CTL_MAXNAME) {
1274 if (oid->oid_number == name[indx]) {
1275 indx++;
1276 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1277 if (oid->oid_handler) {
1278 goto found;
1279 }
1280 if (indx == namelen) {
1281 goto found;
1282 }
1283 it = sysctl_oid_iterator_begin(oid->oid_arg1);
1284 oid = sysctl_oid_iterator_next_system_order(&it);
1285 } else {
1286 if (indx != namelen) {
1287 return EISDIR;
1288 }
1289 goto found;
1290 }
1291 } else {
1292 oid = sysctl_oid_iterator_next_system_order(&it);
1293 }
1294 }
1295
1296 return ENOENT;
1297
1298 found:
1299 *oidp = oid;
1300 return 0;
1301 }
1302
1303 /*
1304 * sysctl_sysctl_oidfmt
1305 *
1306 * Description: For a given OID name, determine the format of the data which
1307 * is associated with it. This is used by the "sysctl" command
1308 * line command.
1309 *
1310 * OID: 0, 4
1311 *
1312 * Parameters: oidp __unused
1313 * arg1 The OID name to look up
1314 * arg2 The length of the OID name
1315 * req Pointer to user request buffer
1316 *
1317 * Returns: 0 Success
1318 * EISDIR Malformed request
1319 * ENOENT No such OID name
1320 * SYSCTL_OUT:EPERM Permission denied
1321 * SYSCTL_OUT:EFAULT Bad user supplied buffer
1322 * SYSCTL_OUT:??? Return value from user function
1323 *
1324 * Implict: Contents of user request buffer, modified
1325 *
1326 * Locks: Acquires and then releases a read lock on the
1327 * sysctl_geometry_lock
1328 *
1329 * Notes: SPI (System Programming Interface); this is subject to change
1330 * and may not be relied upon by third party applications; use
1331 * a subprocess to communicate with the "sysctl" command line
1332 * command instead, if you believe you need this functionality.
1333 *
1334 * This function differs from other sysctl functions in that
1335 * it can not take an output buffer length of 0 to determine the
1336 * space which will be required. It is suggested that the buffer
1337 * length be PATH_MAX, and that authors of new sysctl's refrain
1338 * from exceeding this string length.
1339 */
1340 STATIC int
sysctl_sysctl_oidfmt(__unused struct sysctl_oid * oidp,void * arg1,int arg2,struct sysctl_req * req)1341 sysctl_sysctl_oidfmt(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
1342 struct sysctl_req *req)
1343 {
1344 int *name = (int *) arg1;
1345 int error;
1346 u_int namelen = arg2;
1347 struct sysctl_oid *oid;
1348
1349 lck_rw_lock_shared(&sysctl_geometry_lock);
1350
1351 error = find_oid_by_name(name, namelen, &oid);
1352 if (error) {
1353 goto err;
1354 }
1355
1356 if (!oid->oid_fmt) {
1357 error = ENOENT;
1358 goto err;
1359 }
1360
1361 error = SYSCTL_OUT(req,
1362 &oid->oid_kind, sizeof(oid->oid_kind));
1363 if (!error) {
1364 error = SYSCTL_OUT(req, oid->oid_fmt,
1365 strlen(oid->oid_fmt) + 1);
1366 }
1367
1368 err:
1369 lck_rw_unlock_shared(&sysctl_geometry_lock);
1370 return error;
1371 }
1372
1373 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_oidfmt, "");
1374
1375 /*
1376 * sysctl_sysctl_oiddescr
1377 *
1378 * Description: For a given OID name, determine the description of the
1379 * data which is associated with it. This is used by the
1380 * "sysctl" command line command.
1381 *
1382 * OID: 0, 5
1383 *
1384 * Parameters: oidp __unused
1385 * arg1 The OID name to look up
1386 * arg2 The length of the OID name
1387 * req Pointer to user request buffer
1388 *
1389 * Returns: 0 Success
1390 * EISDIR Malformed request
1391 * ENOENT No such OID name
1392 * SYSCTL_OUT:EPERM Permission denied
1393 * SYSCTL_OUT:EFAULT Bad user supplied buffer
1394 * SYSCTL_OUT:??? Return value from user function
1395 *
1396 * Implict: Contents of user request buffer, modified
1397 *
1398 * Locks: Acquires and then releases a read lock on the
1399 * sysctl_geometry_lock
1400 *
1401 * Notes: SPI (System Programming Interface); this is subject to change
1402 * and may not be relied upon by third party applications; use
1403 * a subprocess to communicate with the "sysctl" command line
1404 * command instead, if you believe you need this functionality.
1405 *
1406 * This function differs from other sysctl functions in that
1407 * it can not take an output buffer length of 0 to determine the
1408 * space which will be required. It is suggested that the buffer
1409 * length be PATH_MAX, and that authors of new sysctl's refrain
1410 * from exceeding this string length.
1411 */
1412 STATIC int
sysctl_sysctl_oiddescr(__unused struct sysctl_oid * oidp,void * arg1,int arg2,struct sysctl_req * req)1413 sysctl_sysctl_oiddescr(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
1414 struct sysctl_req *req)
1415 {
1416 int *name = (int *) arg1;
1417 int error;
1418 u_int namelen = arg2;
1419 struct sysctl_oid *oid;
1420
1421 lck_rw_lock_shared(&sysctl_geometry_lock);
1422
1423 error = find_oid_by_name(name, namelen, &oid);
1424 if (error) {
1425 goto err;
1426 }
1427
1428 if (!oid->oid_descr) {
1429 error = ENOENT;
1430 goto err;
1431 }
1432
1433 error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
1434 err:
1435 lck_rw_unlock_shared(&sysctl_geometry_lock);
1436 return error;
1437 }
1438
1439 SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_oiddescr, "");
1440
1441
1442 /*
1443 * Default "handler" functions.
1444 */
1445
1446 /*
1447 * Handle an int, signed or unsigned.
1448 * Two cases:
1449 * a variable: point arg1 at it.
1450 * a constant: pass it in arg2.
1451 */
1452
1453 int
sysctl_handle_int(__unused struct sysctl_oid * oidp,void * arg1,int arg2,struct sysctl_req * req)1454 sysctl_handle_int(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
1455 struct sysctl_req *req)
1456 {
1457 return sysctl_io_number(req, arg1? *(int*)arg1: arg2, sizeof(int), arg1, NULL);
1458 }
1459
1460 /*
1461 * Handle a long, signed or unsigned. arg1 points to it.
1462 */
1463
1464 int
sysctl_handle_long(__unused struct sysctl_oid * oidp,void * arg1,__unused int arg2,struct sysctl_req * req)1465 sysctl_handle_long(__unused struct sysctl_oid *oidp, void *arg1,
1466 __unused int arg2, struct sysctl_req *req)
1467 {
1468 if (!arg1) {
1469 return EINVAL;
1470 }
1471 return sysctl_io_number(req, *(long*)arg1, sizeof(long), arg1, NULL);
1472 }
1473
1474 /*
1475 * Handle a quad, signed or unsigned. arg1 points to it.
1476 */
1477
1478 int
sysctl_handle_quad(__unused struct sysctl_oid * oidp,void * arg1,__unused int arg2,struct sysctl_req * req)1479 sysctl_handle_quad(__unused struct sysctl_oid *oidp, void *arg1,
1480 __unused int arg2, struct sysctl_req *req)
1481 {
1482 if (!arg1) {
1483 return EINVAL;
1484 }
1485 return sysctl_io_number(req, *(long long*)arg1, sizeof(long long), arg1, NULL);
1486 }
1487
1488 /*
1489 * Expose an int value as a quad.
1490 *
1491 * This interface allows us to support interfaces defined
1492 * as using quad values while the implementation is still
1493 * using ints.
1494 */
1495 int
sysctl_handle_int2quad(__unused struct sysctl_oid * oidp,void * arg1,__unused int arg2,struct sysctl_req * req)1496 sysctl_handle_int2quad(__unused struct sysctl_oid *oidp, void *arg1,
1497 __unused int arg2, struct sysctl_req *req)
1498 {
1499 int error = 0;
1500 long long val;
1501 int newval;
1502
1503 if (!arg1) {
1504 return EINVAL;
1505 }
1506 val = (long long)*(int *)arg1;
1507 error = SYSCTL_OUT(req, &val, sizeof(long long));
1508
1509 if (error || !req->newptr) {
1510 return error;
1511 }
1512
1513 error = SYSCTL_IN(req, &val, sizeof(long long));
1514 if (!error) {
1515 /*
1516 * Value must be representable; check by
1517 * casting and then casting back.
1518 */
1519 newval = (int)val;
1520 if ((long long)newval != val) {
1521 error = ERANGE;
1522 } else {
1523 *(int *)arg1 = newval;
1524 }
1525 }
1526 return error;
1527 }
1528
1529 /*
1530 * Handle our generic '\0' terminated 'C' string.
1531 * Two cases:
1532 * a variable string: point arg1 at it, arg2 is max length.
1533 * a constant string: point arg1 at it, arg2 is zero.
1534 */
1535
1536 int
sysctl_handle_string(__unused struct sysctl_oid * oidp,void * arg1,int arg2,struct sysctl_req * req)1537 sysctl_handle_string( __unused struct sysctl_oid *oidp, void *arg1, int arg2,
1538 struct sysctl_req *req)
1539 {
1540 return sysctl_io_string(req, arg1, arg2, 0, NULL);
1541 }
1542
1543 /*
1544 * Handle any kind of opaque data.
1545 * arg1 points to it, arg2 is the size.
1546 */
1547
1548 int
sysctl_handle_opaque(__unused struct sysctl_oid * oidp,void * arg1,int arg2,struct sysctl_req * req)1549 sysctl_handle_opaque(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
1550 struct sysctl_req *req)
1551 {
1552 return sysctl_io_opaque(req, arg1, arg2, NULL);
1553 }
1554
1555 /*
1556 * Transfer functions to/from kernel space.
1557 */
1558 STATIC int
sysctl_old_kernel(struct sysctl_req * req,const void * p,size_t l)1559 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
1560 {
1561 size_t i = 0;
1562
1563 if (req->oldptr) {
1564 i = l;
1565 if (i > req->oldlen - req->oldidx) {
1566 i = req->oldlen - req->oldidx;
1567 }
1568 if (i > 0) {
1569 bcopy((const void*)p, CAST_DOWN(char *, (req->oldptr + req->oldidx)), i);
1570 }
1571 }
1572 req->oldidx += l;
1573 if (req->oldptr && i != l) {
1574 return ENOMEM;
1575 }
1576 return 0;
1577 }
1578
1579 STATIC int
sysctl_new_kernel(struct sysctl_req * req,void * p,size_t l)1580 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
1581 {
1582 if (!req->newptr) {
1583 return 0;
1584 }
1585 if (req->newlen - req->newidx < l) {
1586 return EINVAL;
1587 }
1588 bcopy(CAST_DOWN(char *, (req->newptr + req->newidx)), p, l);
1589 req->newidx += l;
1590 return 0;
1591 }
1592
1593 int
kernel_sysctl(struct proc * p,int * name,size_t namelen,void * old,size_t * oldlenp,void * new,size_t newlen)1594 kernel_sysctl(struct proc *p, int *name, size_t namelen, void *old, size_t *oldlenp, void *new, size_t newlen)
1595 {
1596 int error = 0;
1597 struct sysctl_req req;
1598
1599 /*
1600 * Construct request.
1601 */
1602 bzero(&req, sizeof req);
1603 req.p = p;
1604 if (oldlenp) {
1605 req.oldlen = *oldlenp;
1606 }
1607 if (old) {
1608 req.oldptr = CAST_USER_ADDR_T(old);
1609 }
1610 if (newlen) {
1611 req.newlen = newlen;
1612 req.newptr = CAST_USER_ADDR_T(new);
1613 }
1614 req.oldfunc = sysctl_old_kernel;
1615 req.newfunc = sysctl_new_kernel;
1616 req.lock = 1;
1617
1618 /* make the request */
1619 error = sysctl_root(TRUE, FALSE, NULL, 0, name, namelen, &req);
1620
1621 if (error && error != ENOMEM) {
1622 return error;
1623 }
1624
1625 if (oldlenp) {
1626 *oldlenp = req.oldidx;
1627 }
1628
1629 return error;
1630 }
1631
1632 /*
1633 * Transfer function to/from user space.
1634 */
1635 STATIC int
sysctl_old_user(struct sysctl_req * req,const void * p,size_t l)1636 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1637 {
1638 int error = 0;
1639 size_t i = 0;
1640
1641 if (req->oldptr) {
1642 if (req->oldlen - req->oldidx < l) {
1643 return ENOMEM;
1644 }
1645 i = l;
1646 if (i > req->oldlen - req->oldidx) {
1647 i = req->oldlen - req->oldidx;
1648 }
1649 if (i > 0) {
1650 error = copyout((const void*)p, (req->oldptr + req->oldidx), i);
1651 }
1652 }
1653 req->oldidx += l;
1654 if (error) {
1655 return error;
1656 }
1657 if (req->oldptr && i < l) {
1658 return ENOMEM;
1659 }
1660 return 0;
1661 }
1662
1663 STATIC int
sysctl_new_user(struct sysctl_req * req,void * p,size_t l)1664 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1665 {
1666 int error;
1667
1668 if (!req->newptr) {
1669 return 0;
1670 }
1671 if (req->newlen - req->newidx < l) {
1672 return EINVAL;
1673 }
1674 error = copyin((req->newptr + req->newidx), p, l);
1675 req->newidx += l;
1676 return error;
1677 }
1678
1679 #define WRITE_EXPERIMENT_FACTORS_ENTITLEMENT "com.apple.private.write-kr-experiment-factors"
1680 /*
1681 * Is the current task allowed to write to experiment factors?
1682 * tasks with the WRITE_EXPERIMENT_FACTORS_ENTITLEMENT are always allowed to write these.
1683 * In the development / debug kernel we also allow root to write them.
1684 */
1685 STATIC bool
can_write_experiment_factors(__unused struct sysctl_req * req)1686 can_write_experiment_factors(__unused struct sysctl_req *req)
1687 {
1688 if (IOCurrentTaskHasEntitlement(WRITE_EXPERIMENT_FACTORS_ENTITLEMENT)) {
1689 return true;
1690 }
1691 #if DEBUG || DEVELOPMENT
1692 return !proc_suser(req->p);
1693 #else
1694 return false;
1695 #endif /* DEBUG || DEVELOPMENT */
1696 }
1697
1698 /*
1699 * Traverse our tree, and find the right node, execute whatever it points
1700 * at, and return the resulting error code.
1701 */
1702
1703 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)1704 sysctl_root(boolean_t from_kernel, boolean_t string_is_canonical,
1705 char *namestring, size_t namestringlen,
1706 int *name, size_t namelen, struct sysctl_req *req)
1707 {
1708 u_int indx;
1709 int i;
1710 struct sysctl_oid_iterator it;
1711 struct sysctl_oid *oid;
1712 sysctl_handler_t oid_handler = NULL;
1713 int error;
1714 boolean_t unlocked_node_found = FALSE;
1715 boolean_t namestring_started = FALSE;
1716
1717 /* Get the read lock on the geometry */
1718 lck_rw_lock_shared(&sysctl_geometry_lock);
1719
1720 if (string_is_canonical) {
1721 /* namestring is actually canonical, name/namelen needs to be populated */
1722 error = name2oid(namestring, name, &namelen);
1723 if (error) {
1724 goto err;
1725 }
1726 }
1727
1728 it = sysctl_oid_iterator_begin(&sysctl__children);
1729 oid = sysctl_oid_iterator_next_system_order(&it);
1730
1731 indx = 0;
1732 while (oid && indx < CTL_MAXNAME) {
1733 if (oid->oid_number == name[indx]) {
1734 if (!from_kernel && !string_is_canonical) {
1735 if (namestring_started) {
1736 if (strlcat(namestring, ".", namestringlen) >= namestringlen) {
1737 error = ENAMETOOLONG;
1738 goto err;
1739 }
1740 }
1741
1742 if (strlcat(namestring, oid->oid_name, namestringlen) >= namestringlen) {
1743 error = ENAMETOOLONG;
1744 goto err;
1745 }
1746 namestring_started = TRUE;
1747 }
1748
1749 indx++;
1750 if (!(oid->oid_kind & CTLFLAG_LOCKED)) {
1751 unlocked_node_found = TRUE;
1752 }
1753 if (oid->oid_kind & CTLFLAG_NOLOCK) {
1754 req->lock = 0;
1755 }
1756 /*
1757 * For SYSCTL_PROC() functions which are for sysctl's
1758 * which have parameters at the end of their OID
1759 * space, you need to OR CTLTYPE_NODE into their
1760 * access value.
1761 *
1762 * NOTE: For binary backward compatibility ONLY! Do
1763 * NOT add new sysctl's that do this! Existing
1764 * sysctl's which do this will eventually have
1765 * compatibility code in user space, and this method
1766 * will become unsupported.
1767 */
1768 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1769 if (oid->oid_handler) {
1770 goto found;
1771 }
1772 if (indx == namelen) {
1773 error = ENOENT;
1774 goto err;
1775 }
1776
1777 it = sysctl_oid_iterator_begin(oid->oid_arg1);
1778 oid = sysctl_oid_iterator_next_system_order(&it);
1779 } else {
1780 if (indx != namelen) {
1781 error = EISDIR;
1782 goto err;
1783 }
1784 goto found;
1785 }
1786 } else {
1787 oid = sysctl_oid_iterator_next_system_order(&it);
1788 }
1789 }
1790 error = ENOENT;
1791 goto err;
1792 found:
1793
1794 /*
1795 * indx is the index of the first remaining OID name,
1796 * for sysctls that take them as arguments
1797 */
1798 if (!from_kernel && !string_is_canonical && (indx < namelen)) {
1799 char tempbuf[10];
1800 u_int indx2;
1801
1802 for (indx2 = indx; indx2 < namelen; indx2++) {
1803 snprintf(tempbuf, sizeof(tempbuf), "%d", name[indx2]);
1804
1805 if (namestring_started) {
1806 if (strlcat(namestring, ".", namestringlen) >= namestringlen) {
1807 error = ENAMETOOLONG;
1808 goto err;
1809 }
1810 }
1811
1812 if (strlcat(namestring, tempbuf, namestringlen) >= namestringlen) {
1813 error = ENAMETOOLONG;
1814 goto err;
1815 }
1816 namestring_started = TRUE;
1817 }
1818 }
1819
1820 /* If writing isn't allowed */
1821 if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
1822 ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) {
1823 error = (EPERM);
1824 goto err;
1825 }
1826
1827 /*
1828 * If we're inside the kernel, the OID must be marked as kernel-valid.
1829 */
1830 if (from_kernel && !(oid->oid_kind & CTLFLAG_KERN)) {
1831 error = (EPERM);
1832 goto err;
1833 }
1834
1835 if (req->newptr && req->p) {
1836 if (oid->oid_kind & CTLFLAG_EXPERIMENT) {
1837 /*
1838 * Experiment factors have different permissions since they need to be
1839 * writable by procs with WRITE_EXPERIMENT_FACTORS_ENTITLEMENT.
1840 */
1841 if (!can_write_experiment_factors(req)) {
1842 error = (EPERM);
1843 goto err;
1844 }
1845 } else {
1846 /*
1847 * This is where legacy enforcement of permissions occurs. If the
1848 * flag does not say CTLFLAG_ANYBODY, then we prohibit anyone but
1849 * root from writing new values down. If local enforcement happens
1850 * at the leaf node, then it needs to be set as CTLFLAG_ANYBODY. In
1851 * addition, if the leaf node is set this way, then in order to do
1852 * specific enforcement, it has to be of type SYSCTL_PROC.
1853 */
1854 if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
1855 (error = proc_suser(req->p))) {
1856 goto err;
1857 }
1858 }
1859 }
1860
1861 /*
1862 * sysctl_unregister_oid() may change the handler value, so grab it
1863 * under the lock.
1864 */
1865 oid_handler = oid->oid_handler;
1866 if (!oid_handler) {
1867 error = EINVAL;
1868 goto err;
1869 }
1870
1871 /*
1872 * Reference the OID and drop the geometry lock; this prevents the
1873 * OID from being deleted out from under the handler call, but does
1874 * not prevent other calls into handlers or calls to manage the
1875 * geometry elsewhere from blocking...
1876 */
1877 if ((oid->oid_kind & CTLFLAG_PERMANENT) == 0) {
1878 OSAddAtomic(1, &oid->oid_refcnt);
1879 }
1880
1881 lck_rw_done(&sysctl_geometry_lock);
1882
1883 #if CONFIG_MACF
1884 if (!from_kernel) {
1885 error = mac_system_check_sysctlbyname(kauth_cred_get(),
1886 namestring,
1887 name,
1888 namelen,
1889 req->oldptr,
1890 req->oldlen,
1891 req->newptr,
1892 req->newlen);
1893 if (error) {
1894 goto dropref;
1895 }
1896 }
1897 #endif
1898
1899 /*
1900 * ...however, we still have to grab the mutex for those calls which
1901 * may be into code whose reentrancy is protected by it.
1902 */
1903 if (unlocked_node_found) {
1904 lck_mtx_lock(&sysctl_unlocked_node_lock);
1905 }
1906
1907 #if defined(HAS_APPLE_PAC)
1908 /*
1909 * oid_handler is signed address-discriminated by sysctl_register_oid().
1910 */
1911 oid_handler = ptrauth_auth_and_resign(oid_handler,
1912 ptrauth_key_function_pointer,
1913 ptrauth_blend_discriminator(&oid->oid_handler,
1914 os_hash_kernel_pointer(oid->oid_arg1)),
1915 ptrauth_key_function_pointer,
1916 ptrauth_function_pointer_type_discriminator(typeof(oid_handler)));
1917 #endif /* defined(HAS_APPLE_PAC) */
1918
1919 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1920 i = oid_handler(oid, name + indx, (int)(namelen - indx), req);
1921 } else {
1922 i = oid_handler(oid, oid->oid_arg1, oid->oid_arg2, req);
1923 }
1924 error = i;
1925
1926 if (unlocked_node_found) {
1927 lck_mtx_unlock(&sysctl_unlocked_node_lock);
1928 }
1929
1930 #if CONFIG_MACF
1931 /* only used from another CONFIG_MACF block */
1932 dropref:
1933 #endif
1934
1935 /*
1936 * This is tricky... we re-grab the geometry lock in order to drop
1937 * the reference and wake on the address; since the geometry
1938 * lock is a reader/writer lock rather than a mutex, we have to
1939 * wake on all apparent 1->0 transitions. This abuses the drop
1940 * after the reference decrement in order to wake any lck_rw_sleep()
1941 * in progress in sysctl_unregister_oid() that slept because of a
1942 * non-zero reference count.
1943 *
1944 * Note: OSAddAtomic() is defined to return the previous value;
1945 * we use this and the fact that the lock itself is a
1946 * barrier to avoid waking every time through on "hot"
1947 * OIDs.
1948 */
1949 lck_rw_lock_shared(&sysctl_geometry_lock);
1950
1951 if ((oid->oid_kind & CTLFLAG_PERMANENT) == 0) {
1952 if (OSAddAtomic(-1, &oid->oid_refcnt) == 1) {
1953 wakeup(&oid->oid_refcnt);
1954 }
1955 }
1956
1957 err:
1958 lck_rw_done(&sysctl_geometry_lock);
1959 return error;
1960 }
1961
1962 void
sysctl_create_user_req(struct sysctl_req * req,struct proc * p,user_addr_t oldp,size_t oldlen,user_addr_t newp,size_t newlen)1963 sysctl_create_user_req(struct sysctl_req *req, struct proc *p, user_addr_t oldp,
1964 size_t oldlen, user_addr_t newp, size_t newlen)
1965 {
1966 bzero(req, sizeof(*req));
1967
1968 req->p = p;
1969
1970 req->oldlen = oldlen;
1971 req->oldptr = oldp;
1972
1973 if (newlen) {
1974 req->newlen = newlen;
1975 req->newptr = newp;
1976 }
1977
1978 req->oldfunc = sysctl_old_user;
1979 req->newfunc = sysctl_new_user;
1980 req->lock = 1;
1981
1982 return;
1983 }
1984
1985 int
sysctl(proc_t p,struct sysctl_args * uap,__unused int32_t * retval)1986 sysctl(proc_t p, struct sysctl_args *uap, __unused int32_t *retval)
1987 {
1988 int error, new_error;
1989 size_t oldlen = 0, newlen;
1990 int name[CTL_MAXNAME];
1991 struct sysctl_req req;
1992 char *namestring;
1993 size_t namestringlen = MAXPATHLEN;
1994
1995 /*
1996 * all top-level sysctl names are non-terminal
1997 */
1998 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) {
1999 return EINVAL;
2000 }
2001 error = copyin(uap->name, &name[0], uap->namelen * sizeof(int));
2002 if (error) {
2003 return error;
2004 }
2005
2006 AUDIT_ARG(ctlname, name, uap->namelen);
2007
2008 if (uap->newlen > SIZE_T_MAX) {
2009 return EINVAL;
2010 }
2011 newlen = (size_t)uap->newlen;
2012
2013 if (uap->oldlenp != USER_ADDR_NULL) {
2014 uint64_t oldlen64 = fuulong(uap->oldlenp);
2015
2016 /*
2017 * If more than 4G, clamp to 4G
2018 */
2019 if (oldlen64 > SIZE_T_MAX) {
2020 oldlen = SIZE_T_MAX;
2021 } else {
2022 oldlen = (size_t)oldlen64;
2023 }
2024 }
2025
2026 sysctl_create_user_req(&req, p, uap->old, oldlen, uap->new, newlen);
2027
2028 /* Guess that longest length for the passed-in MIB, if we can be more aggressive than MAXPATHLEN */
2029 if (uap->namelen == 2) {
2030 if (name[0] == CTL_KERN && name[1] < KERN_MAXID) {
2031 namestringlen = 32; /* "kern.speculative_reads_disabled" */
2032 } else if (name[0] == CTL_HW && name[1] < HW_MAXID) {
2033 namestringlen = 32; /* "hw.cachelinesize_compat" */
2034 }
2035 }
2036
2037 namestring = (char *)kalloc_data(namestringlen, Z_WAITOK);
2038 if (!namestring) {
2039 oldlen = 0;
2040 goto err;
2041 }
2042
2043 error = userland_sysctl(FALSE, namestring, namestringlen, name, uap->namelen, &req, &oldlen);
2044
2045 kfree_data(namestring, namestringlen);
2046
2047 if ((error) && (error != ENOMEM)) {
2048 return error;
2049 }
2050
2051 err:
2052 if (uap->oldlenp != USER_ADDR_NULL) {
2053 /*
2054 * Only overwrite the old error value on a new error
2055 */
2056 new_error = suulong(uap->oldlenp, oldlen);
2057
2058 if (new_error) {
2059 error = new_error;
2060 }
2061 }
2062
2063 return error;
2064 }
2065
2066 // sysctlbyname is also exported as KPI to kexts
2067 // and the syscall name cannot conflict with it
2068 int
sys_sysctlbyname(proc_t p,struct sysctlbyname_args * uap,__unused int32_t * retval)2069 sys_sysctlbyname(proc_t p, struct sysctlbyname_args *uap, __unused int32_t *retval)
2070 {
2071 int error, new_error;
2072 size_t oldlen = 0, newlen;
2073 char *name;
2074 size_t namelen = 0;
2075 struct sysctl_req req;
2076 int oid[CTL_MAXNAME];
2077
2078 if (uap->namelen >= MAXPATHLEN) { /* XXX arbitrary, undocumented */
2079 return ENAMETOOLONG;
2080 }
2081 namelen = (size_t)uap->namelen;
2082
2083 name = (char *)kalloc_data(namelen + 1, Z_WAITOK);
2084 if (!name) {
2085 return ENOMEM;
2086 }
2087
2088 error = copyin(uap->name, name, namelen);
2089 if (error) {
2090 kfree_data(name, namelen + 1);
2091 return error;
2092 }
2093 name[namelen] = '\0';
2094
2095 /* XXX
2096 * AUDIT_ARG(ctlname, name, uap->namelen);
2097 */
2098
2099 if (uap->newlen > SIZE_T_MAX) {
2100 kfree_data(name, namelen + 1);
2101 return EINVAL;
2102 }
2103 newlen = (size_t)uap->newlen;
2104
2105 if (uap->oldlenp != USER_ADDR_NULL) {
2106 uint64_t oldlen64 = fuulong(uap->oldlenp);
2107
2108 /*
2109 * If more than 4G, clamp to 4G
2110 */
2111 if (oldlen64 > SIZE_T_MAX) {
2112 oldlen = SIZE_T_MAX;
2113 } else {
2114 oldlen = (size_t)oldlen64;
2115 }
2116 }
2117
2118 sysctl_create_user_req(&req, p, uap->old, oldlen, uap->new, newlen);
2119
2120 error = userland_sysctl(TRUE, name, namelen + 1, oid, CTL_MAXNAME, &req, &oldlen);
2121
2122 kfree_data(name, namelen + 1);
2123
2124 if ((error) && (error != ENOMEM)) {
2125 return error;
2126 }
2127
2128 if (uap->oldlenp != USER_ADDR_NULL) {
2129 /*
2130 * Only overwrite the old error value on a new error
2131 */
2132 new_error = suulong(uap->oldlenp, oldlen);
2133
2134 if (new_error) {
2135 error = new_error;
2136 }
2137 }
2138
2139 return error;
2140 }
2141
2142 /*
2143 * This is used from various compatibility syscalls too. That's why name
2144 * must be in kernel space.
2145 */
2146 int
userland_sysctl(boolean_t string_is_canonical,char * namestring,size_t namestringlen,int * name,u_int namelen,struct sysctl_req * req,size_t * retval)2147 userland_sysctl(boolean_t string_is_canonical,
2148 char *namestring, size_t namestringlen,
2149 int *name, u_int namelen, struct sysctl_req *req,
2150 size_t *retval)
2151 {
2152 int error = 0;
2153 struct sysctl_req req2;
2154
2155 do {
2156 /* if EAGAIN, reset output cursor */
2157 req2 = *req;
2158 if (!string_is_canonical) {
2159 namestring[0] = '\0';
2160 }
2161
2162 error = sysctl_root(FALSE, string_is_canonical, namestring, namestringlen, name, namelen, &req2);
2163 } while (error == EAGAIN);
2164
2165 if (error && error != ENOMEM) {
2166 return error;
2167 }
2168
2169 if (retval) {
2170 if (req2.oldptr && req2.oldidx > req2.oldlen) {
2171 *retval = req2.oldlen;
2172 } else {
2173 *retval = req2.oldidx;
2174 }
2175 }
2176 return error;
2177 }
2178
2179 /*
2180 * Kernel versions of the userland sysctl helper functions.
2181 *
2182 * These allow sysctl to be used in the same fashion in both
2183 * userland and the kernel.
2184 *
2185 * Note that some sysctl handlers use copyin/copyout, which
2186 * may not work correctly.
2187 *
2188 * The "sysctlbyname" KPI for use by kexts is aliased to this function.
2189 */
2190
2191 int
kernel_sysctlbyname(const char * name,void * oldp,size_t * oldlenp,void * newp,size_t newlen)2192 kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
2193 {
2194 int oid[CTL_MAXNAME];
2195 int name2mib_oid[2];
2196 int error;
2197 size_t oidlen;
2198
2199 /* look up the OID with magic service node */
2200 name2mib_oid[0] = 0;
2201 name2mib_oid[1] = 3;
2202
2203 oidlen = sizeof(oid);
2204 error = kernel_sysctl(current_proc(), name2mib_oid, 2, oid, &oidlen, __DECONST(void *, name), strlen(name));
2205 oidlen /= sizeof(int);
2206 if (oidlen > UINT_MAX) {
2207 error = EDOM;
2208 }
2209
2210 /* now use the OID */
2211 if (error == 0) {
2212 error = kernel_sysctl(current_proc(), oid, (u_int)oidlen, oldp, oldlenp, newp, newlen);
2213 }
2214 return error;
2215 }
2216
2217 int
2218 scalable_counter_sysctl_handler SYSCTL_HANDLER_ARGS
2219 {
2220 #pragma unused(arg2, oidp)
2221 scalable_counter_t counter = *(scalable_counter_t*) arg1;
2222 uint64_t value = counter_load(&counter);
2223 return SYSCTL_OUT(req, &value, sizeof(value));
2224 }
2225
2226 #define X(name, T) \
2227 int \
2228 experiment_factor_##name##_handler SYSCTL_HANDLER_ARGS \
2229 { \
2230 int error, changed = 0; \
2231 T *ptr; \
2232 T new_value, current_value; \
2233 struct experiment_spec *spec = (struct experiment_spec *) arg1; \
2234 if (!arg1) { \
2235 return EINVAL; \
2236 } \
2237 ptr = (T *)(spec->ptr); \
2238 current_value = *ptr; \
2239 error = sysctl_io_number(req, current_value, sizeof(T), &new_value, &changed); \
2240 if (error != 0) { \
2241 return error; \
2242 } \
2243 if (changed) { \
2244 if (new_value < (T) spec->min_value || new_value > (T) spec->max_value) { \
2245 return EINVAL; \
2246 } \
2247 if (os_atomic_cmpxchg(&spec->modified, false, true, acq_rel)) { \
2248 spec->original_value = current_value; \
2249 } \
2250 os_atomic_store_wide(ptr, new_value, relaxed); \
2251 } \
2252 return 0; \
2253 }
2254
2255 experiment_factor_numeric_types
2256 #undef X
2257
2258 #if DEBUG || DEVELOPMENT
2259 static int
2260 sysctl_test_handler SYSCTL_HANDLER_ARGS
2261 {
2262 int error;
2263 int64_t value, out = 0;
2264
2265 error = SYSCTL_IN(req, &value, sizeof(value));
2266 /* Only run test when new value was provided to prevent just reading or
2267 * querying from triggering the test, but still allow for sysctl
2268 * presence tests via read requests with NULL oldptr */
2269 if (error == 0 && req->newptr) {
2270 /* call the test that was specified in SYSCTL_TEST_REGISTER */
2271 error = ((int (*)(int64_t, int64_t *))(uintptr_t)arg1)(value, &out);
2272 }
2273 if (error == 0) {
2274 error = SYSCTL_OUT(req, &out, sizeof(out));
2275 }
2276 return error;
2277 }
2278
2279 void
sysctl_register_test_startup(struct sysctl_test_setup_spec * spec)2280 sysctl_register_test_startup(struct sysctl_test_setup_spec *spec)
2281 {
2282 struct sysctl_oid *oid = zalloc_permanent_type(struct sysctl_oid);
2283
2284 *oid = (struct sysctl_oid){
2285 .oid_parent = &sysctl__debug_test_children,
2286 .oid_number = OID_AUTO,
2287 .oid_kind = CTLTYPE_QUAD | CTLFLAG_OID2 | CTLFLAG_WR |
2288 CTLFLAG_PERMANENT | CTLFLAG_LOCKED | CTLFLAG_MASKED,
2289 .oid_arg1 = (void *)(uintptr_t)spec->st_func,
2290 .oid_name = spec->st_name,
2291 .oid_handler = sysctl_test_handler,
2292 .oid_fmt = "Q",
2293 .oid_version = SYSCTL_OID_VERSION,
2294 .oid_descr = "",
2295 };
2296 sysctl_register_oid_early(oid);
2297 }
2298
2299
2300 extern void vm_analytics_tick(void *arg0, void *arg1);
2301
2302 /* Manual trigger of vm_analytics_tick for testing on dev/debug kernel. */
2303 static int
2304 sysctl_vm_analytics_tick SYSCTL_HANDLER_ARGS
2305 {
2306 #pragma unused(arg1, arg2)
2307 int error, val = 0;
2308 error = sysctl_handle_int(oidp, &val, 0, req);
2309 if (error || !req->newptr) {
2310 return error;
2311 }
2312 vm_analytics_tick(NULL, NULL);
2313 return 0;
2314 }
2315
2316 SYSCTL_PROC(_vm, OID_AUTO, analytics_report, CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_MASKED, 0, 0, &sysctl_vm_analytics_tick, "I", "");
2317
2318 /* Manual trigger of record_system_event for testing on dev/debug kernel */
2319 static int
2320 sysctl_test_record_system_event SYSCTL_HANDLER_ARGS
2321 {
2322 #pragma unused(arg1, arg2)
2323 int error, val = 0;
2324 error = sysctl_handle_int(oidp, &val, 0, req);
2325 if (error || !req->newptr) {
2326 return error;
2327 }
2328 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_TEST, "sysctl test", "this is a test %s", "message");
2329 return 0;
2330 }
2331
2332 SYSCTL_PROC(_kern, OID_AUTO, test_record_system_event, CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_MASKED, 0, 0, &sysctl_test_record_system_event, "-", "");
2333
2334 #endif /* DEBUG || DEVELOPMENT */
2335
2336
2337 CA_EVENT(ca_test_event,
2338 CA_INT, TestKey,
2339 CA_BOOL, TestBool,
2340 CA_STATIC_STRING(CA_UUID_LEN), TestString);
2341
2342 /*
2343 * Manual testing of sending a CoreAnalytics event
2344 */
2345 static int
2346 sysctl_test_ca_event SYSCTL_HANDLER_ARGS
2347 {
2348 #pragma unused(arg1, arg2)
2349 int error, val = 0;
2350 /*
2351 * Only send on write
2352 */
2353 error = sysctl_handle_int(oidp, &val, 0, req);
2354 if (error || !req->newptr) {
2355 return error;
2356 }
2357
2358 ca_event_t event = CA_EVENT_ALLOCATE(ca_test_event);
2359 CA_EVENT_TYPE(ca_test_event) * event_data = event->data;
2360 event_data->TestKey = val;
2361 event_data->TestBool = true;
2362 uuid_string_t test_str = "sysctl_test_ca_event";
2363 strlcpy(event_data->TestString, test_str, CA_UUID_LEN);
2364 CA_EVENT_SEND(event);
2365 return 0;
2366 }
2367
2368 SYSCTL_PROC(_kern, OID_AUTO, test_ca_event, CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_MASKED, 0, 0, &sysctl_test_ca_event, "I", "");
2369
2370
2371 #if DEVELOPMENT || DEBUG
2372 struct perf_compressor_data {
2373 user_addr_t buffer;
2374 size_t buffer_size;
2375 uint64_t benchmark_time;
2376 uint64_t bytes_processed;
2377 uint64_t compressor_growth;
2378 };
2379
2380 static int
2381 sysctl_perf_compressor SYSCTL_HANDLER_ARGS
2382 {
2383 int error = EINVAL;
2384 size_t len = sizeof(struct perf_compressor_data);
2385 struct perf_compressor_data benchmark_data = {0};
2386
2387 if (req->oldptr == USER_ADDR_NULL || req->oldlen != len ||
2388 req->newptr == USER_ADDR_NULL || req->newlen != len) {
2389 return EINVAL;
2390 }
2391
2392 error = SYSCTL_IN(req, &benchmark_data, len);
2393 if (error) {
2394 return error;
2395 }
2396
2397 kern_return_t ret = run_compressor_perf_test(benchmark_data.buffer, benchmark_data.buffer_size,
2398 &benchmark_data.benchmark_time, &benchmark_data.bytes_processed, &benchmark_data.compressor_growth);
2399 switch (ret) {
2400 case KERN_SUCCESS:
2401 error = 0;
2402 break;
2403 case KERN_NOT_SUPPORTED:
2404 error = ENOTSUP;
2405 break;
2406 case KERN_INVALID_ARGUMENT:
2407 error = EINVAL;
2408 break;
2409 case KERN_RESOURCE_SHORTAGE:
2410 error = EAGAIN;
2411 break;
2412 default:
2413 error = ret;
2414 break;
2415 }
2416 if (error != 0) {
2417 return error;
2418 }
2419
2420 return SYSCTL_OUT(req, &benchmark_data, len);
2421 }
2422
2423 /*
2424 * Compressor & swap performance test
2425 */
2426 SYSCTL_PROC(_kern, OID_AUTO, perf_compressor, CTLFLAG_WR | CTLFLAG_MASKED | CTLTYPE_STRUCT,
2427 0, 0, sysctl_perf_compressor, "S", "Compressor & swap benchmark");
2428 #endif /* DEVELOPMENT || DEBUG */
2429
2430 #if CONFIG_JETSAM
2431 extern uint32_t swapout_sleep_threshold;
2432 #if DEVELOPMENT || DEBUG
2433 SYSCTL_UINT(_vm, OID_AUTO, swapout_sleep_threshold, CTLFLAG_RW | CTLFLAG_LOCKED, &swapout_sleep_threshold, 0, "");
2434 #else /* DEVELOPMENT || DEBUG */
2435 SYSCTL_UINT(_vm, OID_AUTO, swapout_sleep_threshold, CTLFLAG_RD | CTLFLAG_LOCKED, &swapout_sleep_threshold, 0, "");
2436 #endif /* DEVELOPMENT || DEBUG */
2437 #endif /* CONFIG_JETSAM */
2438
2439 #if DEBUG || DEVELOPMENT
2440
2441 /* The following sysctl nodes set up a tree that our walking logic
2442 * previously stumbled on. This tree gets walked in a unit test.
2443 */
2444 SYSCTL_NODE(_debug_test, OID_AUTO, sysctl_node_test, CTLFLAG_RW | CTLFLAG_LOCKED,
2445 0, "rdar://138698424 parent node");
2446
2447 SYSCTL_NODE(_debug_test_sysctl_node_test, OID_AUTO, l2, CTLFLAG_RW | CTLFLAG_LOCKED,
2448 0, "rdar://138698424 L2 node");
2449
2450 SYSCTL_NODE(_debug_test_sysctl_node_test_l2, OID_AUTO, l3,
2451 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "rdar://138698424 L3 node");
2452
2453 SYSCTL_NODE(_debug_test_sysctl_node_test_l2_l3, OID_AUTO, l4,
2454 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "rdar://138698424 L4 node");
2455
2456 SYSCTL_OID(_debug_test_sysctl_node_test_l2, OID_AUTO, hanging_oid,
2457 CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, NULL, "", "rdar://138698424 L2 hanging OID");
2458
2459 #endif /* DEBUG || DEVELOPMENT */
2460