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