]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_newsysctl.c
xnu-4570.41.2.tar.gz
[apple/xnu.git] / bsd / kern / kern_newsysctl.c
CommitLineData
1c79356b 1/*
fe8ab488 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
b0d623f7
A
27 *
28 *
1c79356b
A
29 * Copyright (c) 1982, 1986, 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * This code is derived from software contributed to Berkeley by
33 * Mike Karels at Berkeley Software Design, Inc.
34 *
35 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
36 * project, to make these variables more userfriendly.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
67 */
68
69
70#include <sys/param.h>
71#include <sys/buf.h>
72#include <sys/kernel.h>
73#include <sys/sysctl.h>
74#include <sys/malloc.h>
91447636 75#include <sys/proc_internal.h>
fe8ab488 76#include <sys/kauth.h>
1c79356b 77#include <sys/systm.h>
fe8ab488 78#include <sys/sysproto.h>
1c79356b 79
b0d623f7 80#include <security/audit/audit.h>
39037602 81#include <pexpert/pexpert.h>
e5568f75 82
5ba3f43e
A
83#if CONFIG_MACF
84#include <security/mac_framework.h>
85#endif
86
fe8ab488 87lck_grp_t * sysctl_lock_group = NULL;
2d21ac55 88lck_rw_t * sysctl_geometry_lock = NULL;
fe8ab488 89lck_mtx_t * sysctl_unlocked_node_lock = NULL;
1c79356b 90
6d2010ae
A
91/*
92 * Conditionally allow dtrace to see these functions for debugging purposes.
93 */
94#ifdef STATIC
95#undef STATIC
96#endif
97#if 0
98#define STATIC
99#else
100#define STATIC static
101#endif
102
103/* forward declarations of static functions */
6d2010ae
A
104STATIC void sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i);
105STATIC int sysctl_sysctl_debug(struct sysctl_oid *oidp, void *arg1,
106 int arg2, struct sysctl_req *req);
107STATIC int sysctl_sysctl_name(struct sysctl_oid *oidp, void *arg1,
108 int arg2, struct sysctl_req *req);
109STATIC int sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp,
110 int *name, u_int namelen, int *next, int *len, int level,
111 struct sysctl_oid **oidpp);
112STATIC int sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l);
113STATIC int sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l);
fe8ab488 114STATIC int name2oid (char *name, int *oid, u_int *len);
6d2010ae
A
115STATIC int sysctl_sysctl_name2oid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
116STATIC int sysctl_sysctl_next(struct sysctl_oid *oidp, void *arg1, int arg2,
117 struct sysctl_req *req);
118STATIC int sysctl_sysctl_oidfmt(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
6d2010ae
A
119STATIC int sysctl_old_user(struct sysctl_req *req, const void *p, size_t l);
120STATIC int sysctl_new_user(struct sysctl_req *req, void *p, size_t l);
1c79356b 121
fe8ab488
A
122STATIC void sysctl_create_user_req(struct sysctl_req *req, struct proc *p, user_addr_t oldp,
123 size_t oldlen, user_addr_t newp, size_t newlen);
124STATIC int sysctl_root(boolean_t from_kernel, boolean_t string_is_canonical, char *namestring, size_t namestringlen, int *name, u_int namelen, struct sysctl_req *req);
1c79356b 125
fe8ab488
A
126int kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen);
127int kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
128int userland_sysctl(boolean_t string_is_canonical,
129 char *namestring, size_t namestringlen,
130 int *name, u_int namelen, struct sysctl_req *req,
131 size_t *retval);
1c79356b
A
132
133struct sysctl_oid_list sysctl__children; /* root list */
134
135/*
136 * Initialization of the MIB tree.
137 *
138 * Order by number in each list.
139 */
140
6d2010ae
A
141void
142sysctl_register_oid(struct sysctl_oid *new_oidp)
1c79356b 143{
6d2010ae
A
144 struct sysctl_oid *oidp = NULL;
145 struct sysctl_oid_list *parent = new_oidp->oid_parent;
1c79356b
A
146 struct sysctl_oid *p;
147 struct sysctl_oid *q;
148 int n;
6d2010ae
A
149
150 /*
151 * The OID can be old-style (needs copy), new style without an earlier
152 * version (also needs copy), or new style with a matching version (no
153 * copy needed). Later versions are rejected (presumably, the OID
154 * structure was changed for a necessary reason).
155 */
156 if (!(new_oidp->oid_kind & CTLFLAG_OID2)) {
157 /*
158 * XXX: M_TEMP is perhaps not the most apropriate zone, as it
159 * XXX: will subject us to use-after-free by other consumers.
160 */
161 MALLOC(oidp, struct sysctl_oid *, sizeof(*oidp), M_TEMP, M_WAITOK | M_ZERO);
162 if (oidp == NULL)
163 return; /* reject: no memory */
164
165 /*
166 * Copy the structure only through the oid_fmt field, which
167 * is the last field in a non-OID2 OID structure.
168 *
169 * Note: We may want to set the oid_descr to the
170 * oid_name (or "") at some future date.
171 */
172 memcpy(oidp, new_oidp, offsetof(struct sysctl_oid, oid_descr));
173 } else {
174 /* It's a later version; handle the versions we know about */
175 switch (new_oidp->oid_version) {
176 case SYSCTL_OID_VERSION:
177 /* current version */
178 oidp = new_oidp;
179 break;
180 default:
181 return; /* rejects unknown version */
182 }
183 }
43866e37 184
2d21ac55
A
185 /* Get the write lock to modify the geometry */
186 lck_rw_lock_exclusive(sysctl_geometry_lock);
187
1c79356b
A
188 /*
189 * If this oid has a number OID_AUTO, give it a number which
190 * is greater than any current oid. Make sure it is at least
2d21ac55 191 * OID_AUTO_START to leave space for pre-assigned oid numbers.
1c79356b 192 */
1c79356b 193 if (oidp->oid_number == OID_AUTO) {
2d21ac55
A
194 /* First, find the highest oid in the parent list >OID_AUTO_START-1 */
195 n = OID_AUTO_START;
1c79356b
A
196 SLIST_FOREACH(p, parent, oid_link) {
197 if (p->oid_number > n)
198 n = p->oid_number;
199 }
200 oidp->oid_number = n + 1;
6d2010ae
A
201 /*
202 * Reflect the number in an llocated OID into the template
203 * of the caller for sysctl_unregister_oid() compares.
204 */
205 if (oidp != new_oidp)
206 new_oidp->oid_number = oidp->oid_number;
1c79356b
A
207 }
208
209 /*
210 * Insert the oid into the parent's list in order.
211 */
212 q = NULL;
213 SLIST_FOREACH(p, parent, oid_link) {
214 if (oidp->oid_number < p->oid_number)
215 break;
216 q = p;
217 }
218 if (q)
219 SLIST_INSERT_AFTER(q, oidp, oid_link);
220 else
221 SLIST_INSERT_HEAD(parent, oidp, oid_link);
43866e37 222
2d21ac55
A
223 /* Release the write lock */
224 lck_rw_unlock_exclusive(sysctl_geometry_lock);
1c79356b
A
225}
226
6d2010ae
A
227void
228sysctl_unregister_oid(struct sysctl_oid *oidp)
1c79356b 229{
6d2010ae
A
230 struct sysctl_oid *removed_oidp = NULL; /* OID removed from tree */
231 struct sysctl_oid *old_oidp = NULL; /* OID compatibility copy */
2d21ac55
A
232
233 /* Get the write lock to modify the geometry */
234 lck_rw_lock_exclusive(sysctl_geometry_lock);
235
6d2010ae
A
236 if (!(oidp->oid_kind & CTLFLAG_OID2)) {
237 /*
238 * We're using a copy so we can get the new fields in an
239 * old structure, so we have to iterate to compare the
240 * partial structure; when we find a match, we remove it
241 * normally and free the memory.
242 */
243 SLIST_FOREACH(old_oidp, oidp->oid_parent, oid_link) {
244 if (!memcmp(&oidp->oid_number, &old_oidp->oid_number, (offsetof(struct sysctl_oid, oid_descr)-offsetof(struct sysctl_oid, oid_number)))) {
245 break;
246 }
247 }
248 if (old_oidp != NULL) {
249 SLIST_REMOVE(old_oidp->oid_parent, old_oidp, sysctl_oid, oid_link);
250 removed_oidp = old_oidp;
251 }
252 } else {
253 /* It's a later version; handle the versions we know about */
254 switch (oidp->oid_version) {
255 case SYSCTL_OID_VERSION:
256 /* We can just remove the OID directly... */
257 SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
258 removed_oidp = oidp;
259 break;
260 default:
261 /* XXX: Can't happen; probably tree coruption.*/
262 break; /* rejects unknown version */
263 }
264 }
265
266 /*
267 * We've removed it from the list at this point, but we don't want
268 * to return to the caller until all handler references have drained
269 * out. Doing things in this order prevent other people coming in
270 * and starting new operations against the OID node we want removed.
271 *
272 * Note: oidp could be NULL if it wasn't found.
273 */
274 while(removed_oidp && removed_oidp->oid_refcnt) {
275 lck_rw_sleep(sysctl_geometry_lock, LCK_SLEEP_EXCLUSIVE, &removed_oidp->oid_refcnt, THREAD_UNINT);
276 }
2d21ac55
A
277
278 /* Release the write lock */
279 lck_rw_unlock_exclusive(sysctl_geometry_lock);
280
6d2010ae
A
281 /* If it was allocated, free it after dropping the lock */
282 if (old_oidp != NULL) {
283 FREE(old_oidp, M_TEMP);
284 }
1c79356b
A
285}
286
287/*
288 * Bulk-register all the oids in a linker_set.
289 */
6d2010ae
A
290void
291sysctl_register_set(const char *set)
1c79356b 292{
2d21ac55
A
293 struct sysctl_oid **oidpp, *oidp;
294
b0d623f7 295 LINKER_SET_FOREACH(oidpp, struct sysctl_oid **, set) {
2d21ac55
A
296 oidp = *oidpp;
297 if (!(oidp->oid_kind & CTLFLAG_NOAUTO)) {
298 sysctl_register_oid(oidp);
299 }
300 }
1c79356b
A
301}
302
6d2010ae
A
303void
304sysctl_unregister_set(const char *set)
1c79356b 305{
2d21ac55
A
306 struct sysctl_oid **oidpp, *oidp;
307
b0d623f7 308 LINKER_SET_FOREACH(oidpp, struct sysctl_oid **, set) {
2d21ac55
A
309 oidp = *oidpp;
310 if (!(oidp->oid_kind & CTLFLAG_NOAUTO)) {
311 sysctl_unregister_oid(oidp);
312 }
313 }
1c79356b
A
314}
315
1c79356b 316/*
39037602 317 * Exported in BSDKernel.exports, kept for binary compatibility
1c79356b 318 */
39037602 319#if defined(__x86_64__)
2d21ac55 320void
39037602 321sysctl_register_fixed(void)
2d21ac55 322{
2d21ac55 323}
39037602
A
324#endif
325
326/*
327 * Register the kernel's oids on startup.
328 */
2d21ac55
A
329
330void
39037602 331sysctl_early_init(void)
1c79356b 332{
39037602
A
333 /*
334 * Initialize the geometry lock for reading/modifying the
335 * sysctl tree. This is done here because IOKit registers
336 * some sysctl's before bsd_init() would otherwise perform
337 * subsystem initialization.
338 */
339
340 sysctl_lock_group = lck_grp_alloc_init("sysctl", NULL);
341 sysctl_geometry_lock = lck_rw_alloc_init(sysctl_lock_group, NULL);
342 sysctl_unlocked_node_lock = lck_mtx_alloc_init(sysctl_lock_group, NULL);
343
344 sysctl_register_set("__sysctl_set");
1c79356b
A
345}
346
347/*
2d21ac55
A
348 * New handler interface
349 * If the sysctl caller (user mode or kernel mode) is interested in the
350 * value (req->oldptr != NULL), we copy the data (bigValue etc.) out,
351 * if the caller wants to set the value (req->newptr), we copy
352 * the data in (*pValue etc.).
1c79356b 353 */
1c79356b 354
2d21ac55
A
355int
356sysctl_io_number(struct sysctl_req *req, long long bigValue, size_t valueSize, void *pValue, int *changed) {
357 int smallValue;
358 int error;
359
360 if (changed) *changed = 0;
361
362 /*
363 * Handle the various combinations of caller buffer size and
364 * data value size. We are generous in the case where the
365 * caller has specified a 32-bit buffer but the value is 64-bit
366 * sized.
367 */
368
369 /* 32 bit value expected or 32 bit buffer offered */
b0d623f7
A
370 if (((valueSize == sizeof(int)) ||
371 ((req->oldlen == sizeof(int)) && (valueSize == sizeof(long long))))
372 && (req->oldptr)) {
2d21ac55
A
373 smallValue = (int)bigValue;
374 if ((long long)smallValue != bigValue)
375 return(ERANGE);
376 error = SYSCTL_OUT(req, &smallValue, sizeof(smallValue));
377 } else {
378 /* any other case is either size-equal or a bug */
379 error = SYSCTL_OUT(req, &bigValue, valueSize);
380 }
381 /* error or nothing to set */
382 if (error || !req->newptr)
383 return(error);
384
385 /* set request for constant */
386 if (pValue == NULL)
387 return(EPERM);
388
389 /* set request needs to convert? */
390 if ((req->newlen == sizeof(int)) && (valueSize == sizeof(long long))) {
391 /* new value is 32 bits, upconvert to 64 bits */
392 error = SYSCTL_IN(req, &smallValue, sizeof(smallValue));
393 if (!error)
394 *(long long *)pValue = (long long)smallValue;
395 } else if ((req->newlen == sizeof(long long)) && (valueSize == sizeof(int))) {
396 /* new value is 64 bits, downconvert to 32 bits and range check */
397 error = SYSCTL_IN(req, &bigValue, sizeof(bigValue));
398 if (!error) {
399 smallValue = (int)bigValue;
400 if ((long long)smallValue != bigValue)
401 return(ERANGE);
402 *(int *)pValue = smallValue;
403 }
404 } else {
405 /* sizes match, just copy in */
406 error = SYSCTL_IN(req, pValue, valueSize);
407 }
408 if (!error && changed)
409 *changed = 1;
410 return(error);
411}
412
413int
414sysctl_io_string(struct sysctl_req *req, char *pValue, size_t valueSize, int trunc, int *changed)
1c79356b 415{
2d21ac55
A
416 int error;
417
418 if (changed) *changed = 0;
419
420 if (trunc && req->oldptr && req->oldlen && (req->oldlen<strlen(pValue) + 1)) {
421 /* If trunc != 0, if you give it a too small (but larger than
422 * 0 bytes) buffer, instead of returning ENOMEM, it truncates the
423 * returned string to the buffer size. This preserves the semantics
424 * of some library routines implemented via sysctl, which truncate
425 * their returned data, rather than simply returning an error. The
426 * returned string is always NUL terminated. */
427 error = SYSCTL_OUT(req, pValue, req->oldlen-1);
428 if (!error) {
429 char c = 0;
430 error = SYSCTL_OUT(req, &c, 1);
431 }
432 } else {
433 /* Copy string out */
434 error = SYSCTL_OUT(req, pValue, strlen(pValue) + 1);
435 }
436
437 /* error or no new value */
438 if (error || !req->newptr)
439 return(error);
440
441 /* attempt to set read-only value */
442 if (valueSize == 0)
443 return(EPERM);
444
445 /* make sure there's room for the new string */
446 if (req->newlen >= valueSize)
447 return(EINVAL);
448
449 /* copy the string in and force NUL termination */
450 error = SYSCTL_IN(req, pValue, req->newlen);
451 pValue[req->newlen] = '\0';
452
453 if (!error && changed)
454 *changed = 1;
455 return(error);
1c79356b
A
456}
457
2d21ac55
A
458int sysctl_io_opaque(struct sysctl_req *req,void *pValue, size_t valueSize, int *changed)
459{
460 int error;
461
462 if (changed) *changed = 0;
463
464 /* Copy blob out */
465 error = SYSCTL_OUT(req, pValue, valueSize);
466
467 /* error or nothing to set */
468 if (error || !req->newptr)
469 return(error);
470
471 error = SYSCTL_IN(req, pValue, valueSize);
472
473 if (!error && changed)
474 *changed = 1;
475 return(error);
476}
1c79356b
A
477
478/*
479 * "Staff-functions"
480 *
481 * These functions implement a presently undocumented interface
482 * used by the sysctl program to walk the tree, and get the type
483 * so it can print the value.
484 * This interface is under work and consideration, and should probably
485 * be killed with a big axe by the first person who can find the time.
486 * (be aware though, that the proper interface isn't as obvious as it
487 * may seem, there are various conflicting requirements.
488 *
489 * {0,0} printf the entire MIB-tree.
490 * {0,1,...} return the name of the "..." OID.
491 * {0,2,...} return the next OID.
492 * {0,3} return the OID of the name in "new"
493 * {0,4,...} return the kind & format info for the "..." OID.
494 */
495
6d2010ae
A
496/*
497 * sysctl_sysctl_debug_dump_node
498 *
499 * Description: Dump debug information for a given sysctl_oid_list at the
500 * given oid depth out to the kernel log, via printf
501 *
502 * Parameters: l sysctl_oid_list pointer
503 * i current node depth
504 *
505 * Returns: (void)
506 *
507 * Implicit: kernel log, modified
508 *
509 * Locks: Assumes sysctl_geometry_lock is held prior to calling
510 *
511 * Notes: This function may call itself recursively to resolve Node
512 * values, which potentially have an inferioer sysctl_oid_list
513 *
514 * This function is only callable indirectly via the function
515 * sysctl_sysctl_debug()
516 *
517 * Bugs: The node depth indentation does not work; this may be an
518 * artifact of leading space removal by the log daemon itself
519 * or some intermediate routine.
520 */
521STATIC void
1c79356b
A
522sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
523{
524 int k;
525 struct sysctl_oid *oidp;
526
527 SLIST_FOREACH(oidp, l, oid_link) {
528
529 for (k=0; k<i; k++)
530 printf(" ");
531
532 printf("%d %s ", oidp->oid_number, oidp->oid_name);
533
6d2010ae
A
534 printf("%c%c%c",
535 oidp->oid_kind & CTLFLAG_LOCKED ? 'L':' ',
1c79356b
A
536 oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
537 oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
538
539 if (oidp->oid_handler)
540 printf(" *Handler");
541
542 switch (oidp->oid_kind & CTLTYPE) {
543 case CTLTYPE_NODE:
544 printf(" Node\n");
545 if (!oidp->oid_handler) {
546 sysctl_sysctl_debug_dump_node(
547 oidp->oid_arg1, i+2);
548 }
549 break;
550 case CTLTYPE_INT: printf(" Int\n"); break;
551 case CTLTYPE_STRING: printf(" String\n"); break;
552 case CTLTYPE_QUAD: printf(" Quad\n"); break;
553 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
554 default: printf("\n");
555 }
556
557 }
558}
559
6d2010ae
A
560/*
561 * sysctl_sysctl_debug
562 *
563 * Description: This function implements the "sysctl.debug" portion of the
564 * OID space for sysctl.
565 *
566 * OID: 0, 0
567 *
568 * Parameters: __unused
569 *
570 * Returns: ENOENT
571 *
572 * Implicit: kernel log, modified
573 *
574 * Locks: Acquires and then releases a read lock on the
575 * sysctl_geometry_lock
576 */
577STATIC int
2d21ac55
A
578sysctl_sysctl_debug(__unused struct sysctl_oid *oidp, __unused void *arg1,
579 __unused int arg2, __unused struct sysctl_req *req)
1c79356b 580{
6d2010ae 581 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b 582 sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
6d2010ae 583 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
584 return ENOENT;
585}
586
6d2010ae 587SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD | CTLFLAG_LOCKED,
1c79356b
A
588 0, 0, sysctl_sysctl_debug, "-", "");
589
6d2010ae
A
590/*
591 * sysctl_sysctl_name
592 *
593 * Description: Convert an OID into a string name; this is used by the user
594 * space sysctl() command line utility; this is done in a purely
595 * advisory capacity (e.g. to provide node names for "sysctl -A"
596 * output).
597 *
598 * OID: 0, 1
599 *
600 * Parameters: oidp __unused
601 * arg1 A pointer to the OID name list
602 * integer array, beginning at
603 * adjusted option base 2
604 * arg2 The number of elements which
605 * remain in the name array
606 *
607 * Returns: 0 Success
608 * SYSCTL_OUT:EPERM Permission denied
609 * SYSCTL_OUT:EFAULT Bad user supplied buffer
610 * SYSCTL_OUT:??? Return value from user function
611 * for SYSCTL_PROC leaf node
612 *
613 * Implict: Contents of user request buffer, modified
614 *
615 * Locks: Acquires and then releases a read lock on the
616 * sysctl_geometry_lock
617 *
618 * Notes: SPI (System Programming Interface); this is subject to change
619 * and may not be relied upon by third party applications; use
620 * a subprocess to communicate with the "sysctl" command line
621 * command instead, if you believe you need this functionality.
622 * Preferrably, use sysctlbyname() instead.
623 *
624 * Setting of the NULL termination of the output string is
625 * delayed until after the geometry lock is dropped. If there
626 * are no Entries remaining in the OID name list when this
627 * function is called, it will still write out the termination
628 * byte.
629 *
630 * This function differs from other sysctl functions in that
631 * it can not take an output buffer length of 0 to determine the
632 * space which will be required. It is suggested that the buffer
633 * length be PATH_MAX, and that authors of new sysctl's refrain
634 * from exceeding this string length.
635 */
636STATIC int
2d21ac55
A
637sysctl_sysctl_name(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
638 struct sysctl_req *req)
1c79356b
A
639{
640 int *name = (int *) arg1;
641 u_int namelen = arg2;
642 int error = 0;
643 struct sysctl_oid *oid;
644 struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
91447636 645 char tempbuf[10];
1c79356b 646
6d2010ae 647 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b
A
648 while (namelen) {
649 if (!lsp) {
91447636 650 snprintf(tempbuf,sizeof(tempbuf),"%d",*name);
1c79356b
A
651 if (req->oldidx)
652 error = SYSCTL_OUT(req, ".", 1);
653 if (!error)
91447636 654 error = SYSCTL_OUT(req, tempbuf, strlen(tempbuf));
6d2010ae
A
655 if (error) {
656 lck_rw_done(sysctl_geometry_lock);
1c79356b 657 return (error);
6d2010ae 658 }
1c79356b
A
659 namelen--;
660 name++;
661 continue;
662 }
663 lsp2 = 0;
664 SLIST_FOREACH(oid, lsp, oid_link) {
665 if (oid->oid_number != *name)
666 continue;
667
668 if (req->oldidx)
669 error = SYSCTL_OUT(req, ".", 1);
670 if (!error)
671 error = SYSCTL_OUT(req, oid->oid_name,
672 strlen(oid->oid_name));
6d2010ae
A
673 if (error) {
674 lck_rw_done(sysctl_geometry_lock);
1c79356b 675 return (error);
6d2010ae 676 }
1c79356b
A
677
678 namelen--;
679 name++;
680
681 if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
682 break;
683
684 if (oid->oid_handler)
685 break;
686
687 lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
688 break;
689 }
690 lsp = lsp2;
691 }
6d2010ae 692 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
693 return (SYSCTL_OUT(req, "", 1));
694}
695
6d2010ae 696SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_name, "");
1c79356b 697
6d2010ae
A
698/*
699 * sysctl_sysctl_next_ls
700 *
701 * Description: For a given OID name value, return the next consecutive OID
702 * name value within the geometry tree
703 *
704 * Parameters: lsp The OID list to look in
705 * name The OID name to start from
706 * namelen The length of the OID name
707 * next Pointer to new oid storage to
708 * fill in
709 * len Pointer to receive new OID
710 * length value of storage written
711 * level OID tree depth (used to compute
712 * len value)
713 * oidpp Pointer to OID list entry
714 * pointer; used to walk the list
715 * forward across recursion
716 *
717 * Returns: 0 Returning a new entry
718 * 1 End of geometry list reached
719 *
720 * Implicit: *next Modified to contain the new OID
721 * *len Modified to contain new length
722 *
723 * Locks: Assumes sysctl_geometry_lock is held prior to calling
724 *
725 * Notes: This function will not return OID values that have special
726 * handlers, since we can not tell wheter these handlers consume
727 * elements from the OID space as parameters. For this reason,
728 * we STRONGLY discourage these types of handlers
729 */
730STATIC int
1c79356b
A
731sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen,
732 int *next, int *len, int level, struct sysctl_oid **oidpp)
733{
734 struct sysctl_oid *oidp;
735
736 *len = level;
737 SLIST_FOREACH(oidp, lsp, oid_link) {
738 *next = oidp->oid_number;
739 *oidpp = oidp;
740
741 if (!namelen) {
742 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
743 return 0;
744 if (oidp->oid_handler)
745 /* We really should call the handler here...*/
746 return 0;
747 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
2d21ac55
A
748
749 if (!SLIST_FIRST(lsp))
750 /* This node had no children - skip it! */
751 continue;
752
1c79356b
A
753 if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
754 len, level+1, oidpp))
755 return 0;
756 goto next;
757 }
758
759 if (oidp->oid_number < *name)
760 continue;
761
762 if (oidp->oid_number > *name) {
763 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
764 return 0;
765 if (oidp->oid_handler)
766 return 0;
767 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
768 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
769 next+1, len, level+1, oidpp))
770 return (0);
771 goto next;
772 }
773 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
774 continue;
775
776 if (oidp->oid_handler)
777 continue;
778
779 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
780 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
781 len, level+1, oidpp))
782 return (0);
783 next:
784 namelen = 1;
785 *len = level;
786 }
787 return 1;
788}
789
6d2010ae
A
790/*
791 * sysctl_sysctl_next
792 *
793 * Description: This is an iterator function designed to iterate the oid tree
794 * and provide a list of OIDs for use by the user space "sysctl"
795 * command line tool
796 *
797 * OID: 0, 2
798 *
799 * Parameters: oidp __unused
800 * arg1 Pointer to start OID name
801 * arg2 Start OID name length
802 * req Pointer to user request buffer
803 *
804 * Returns: 0 Success
805 * ENOENT Reached end of OID space
806 * SYSCTL_OUT:EPERM Permission denied
807 * SYSCTL_OUT:EFAULT Bad user supplied buffer
808 * SYSCTL_OUT:??? Return value from user function
809 * for SYSCTL_PROC leaf node
810 *
811 * Implict: Contents of user request buffer, modified
812 *
813 * Locks: Acquires and then releases a read lock on the
814 * sysctl_geometry_lock
815 *
816 * Notes: SPI (System Programming Interface); this is subject to change
817 * and may not be relied upon by third party applications; use
818 * a subprocess to communicate with the "sysctl" command line
819 * command instead, if you believe you need this functionality.
820 * Preferrably, use sysctlbyname() instead.
821 *
822 * This function differs from other sysctl functions in that
823 * it can not take an output buffer length of 0 to determine the
824 * space which will be required. It is suggested that the buffer
825 * length be PATH_MAX, and that authors of new sysctl's refrain
826 * from exceeding this string length.
827 */
828STATIC int
2d21ac55
A
829sysctl_sysctl_next(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
830 struct sysctl_req *req)
1c79356b
A
831{
832 int *name = (int *) arg1;
833 u_int namelen = arg2;
834 int i, j, error;
835 struct sysctl_oid *oid;
836 struct sysctl_oid_list *lsp = &sysctl__children;
837 int newoid[CTL_MAXNAME];
838
6d2010ae 839 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b 840 i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
6d2010ae 841 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
842 if (i)
843 return ENOENT;
844 error = SYSCTL_OUT(req, newoid, j * sizeof (int));
845 return (error);
846}
847
6d2010ae 848SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_next, "");
1c79356b 849
6d2010ae
A
850/*
851 * name2oid
852 *
853 * Description: Support function for use by sysctl_sysctl_name2oid(); looks
854 * up an OID name given a string name.
855 *
856 * Parameters: name NULL terminated string name
857 * oid Pointer to receive OID name
858 * len Pointer to receive OID length
859 * pointer value (see "Notes")
860 *
861 * Returns: 0 Success
862 * ENOENT Entry not found
863 *
864 * Implicit: *oid Modified to contain OID value
865 * *len Modified to contain OID length
866 *
867 * Locks: Assumes sysctl_geometry_lock is held prior to calling
868 */
869STATIC int
fe8ab488 870name2oid (char *name, int *oid, u_int *len)
1c79356b
A
871{
872 int i;
873 struct sysctl_oid *oidp;
874 struct sysctl_oid_list *lsp = &sysctl__children;
875 char *p;
876
877 if (!*name)
878 return ENOENT;
879
880 p = name + strlen(name) - 1 ;
881 if (*p == '.')
882 *p = '\0';
883
884 *len = 0;
885
886 for (p = name; *p && *p != '.'; p++)
887 ;
888 i = *p;
889 if (i == '.')
890 *p = '\0';
891
892 oidp = SLIST_FIRST(lsp);
893
894 while (oidp && *len < CTL_MAXNAME) {
895 if (strcmp(name, oidp->oid_name)) {
896 oidp = SLIST_NEXT(oidp, oid_link);
897 continue;
898 }
899 *oid++ = oidp->oid_number;
900 (*len)++;
901
902 if (!i) {
1c79356b
A
903 return (0);
904 }
905
906 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
907 break;
908
909 if (oidp->oid_handler)
910 break;
911
912 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
913 oidp = SLIST_FIRST(lsp);
fe8ab488 914 *p = i; /* restore */
1c79356b
A
915 name = p+1;
916 for (p = name; *p && *p != '.'; p++)
917 ;
918 i = *p;
919 if (i == '.')
920 *p = '\0';
921 }
922 return ENOENT;
923}
924
6d2010ae
A
925/*
926 * sysctl_sysctl_name2oid
927 *
928 * Description: Translate a string name to an OID name value; this is used by
929 * the sysctlbyname() function as well as by the "sysctl" command
930 * line command.
931 *
932 * OID: 0, 3
933 *
934 * Parameters: oidp __unused
935 * arg1 __unused
936 * arg2 __unused
937 * req Request structure
938 *
939 * Returns: ENOENT Input length too short
940 * ENAMETOOLONG Input length too long
941 * ENOMEM Could not allocate work area
942 * SYSCTL_IN/OUT:EPERM Permission denied
943 * SYSCTL_IN/OUT:EFAULT Bad user supplied buffer
944 * SYSCTL_IN/OUT:??? Return value from user function
945 * name2oid:ENOENT Not found
946 *
947 * Implicit: *req Contents of request, modified
948 *
949 * Locks: Acquires and then releases a read lock on the
950 * sysctl_geometry_lock
951 *
952 * Notes: SPI (System Programming Interface); this is subject to change
953 * and may not be relied upon by third party applications; use
954 * a subprocess to communicate with the "sysctl" command line
955 * command instead, if you believe you need this functionality.
956 * Preferrably, use sysctlbyname() instead.
957 *
958 * This function differs from other sysctl functions in that
959 * it can not take an output buffer length of 0 to determine the
960 * space which will be required. It is suggested that the buffer
961 * length be PATH_MAX, and that authors of new sysctl's refrain
962 * from exceeding this string length.
963 */
964STATIC int
2d21ac55
A
965sysctl_sysctl_name2oid(__unused struct sysctl_oid *oidp, __unused void *arg1,
966 __unused int arg2, struct sysctl_req *req)
1c79356b
A
967{
968 char *p;
2d21ac55 969 int error, oid[CTL_MAXNAME];
fe8ab488 970 u_int len = 0; /* set by name2oid() */
1c79356b 971
6d2010ae 972 if (req->newlen < 1)
1c79356b
A
973 return ENOENT;
974 if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */
975 return (ENAMETOOLONG);
976
91447636 977 MALLOC(p, char *,req->newlen+1, M_TEMP, M_WAITOK);
1c79356b
A
978 if (!p)
979 return ENOMEM;
980
981 error = SYSCTL_IN(req, p, req->newlen);
982 if (error) {
983 FREE(p, M_TEMP);
984 return (error);
985 }
986
987 p [req->newlen] = '\0';
988
6d2010ae
A
989 /*
990 * Note: We acquire and release the geometry lock here to
991 * avoid making name2oid needlessly complex.
992 */
993 lck_rw_lock_shared(sysctl_geometry_lock);
994 error = name2oid(p, oid, &len);
995 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
996
997 FREE(p, M_TEMP);
998
999 if (error)
1000 return (error);
1001
1002 error = SYSCTL_OUT(req, oid, len * sizeof *oid);
1003 return (error);
1004}
1005
6d2010ae 1006SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY|CTLFLAG_KERN | CTLFLAG_LOCKED, 0, 0,
1c79356b
A
1007 sysctl_sysctl_name2oid, "I", "");
1008
6d2010ae
A
1009/*
1010 * sysctl_sysctl_oidfmt
1011 *
1012 * Description: For a given OID name, determine the format of the data which
1013 * is associated with it. This is used by the "sysctl" command
1014 * line command.
1015 *
1016 * OID: 0, 4
1017 *
1018 * Parameters: oidp __unused
1019 * arg1 The OID name to look up
1020 * arg2 The length of the OID name
1021 * req Pointer to user request buffer
1022 *
1023 * Returns: 0 Success
1024 * EISDIR Malformed request
1025 * ENOENT No such OID name
1026 * SYSCTL_OUT:EPERM Permission denied
1027 * SYSCTL_OUT:EFAULT Bad user supplied buffer
1028 * SYSCTL_OUT:??? Return value from user function
1029 *
1030 * Implict: Contents of user request buffer, modified
1031 *
1032 * Locks: Acquires and then releases a read lock on the
1033 * sysctl_geometry_lock
1034 *
1035 * Notes: SPI (System Programming Interface); this is subject to change
1036 * and may not be relied upon by third party applications; use
1037 * a subprocess to communicate with the "sysctl" command line
1038 * command instead, if you believe you need this functionality.
1039 *
1040 * This function differs from other sysctl functions in that
1041 * it can not take an output buffer length of 0 to determine the
1042 * space which will be required. It is suggested that the buffer
1043 * length be PATH_MAX, and that authors of new sysctl's refrain
1044 * from exceeding this string length.
1045 */
1046STATIC int
2d21ac55
A
1047sysctl_sysctl_oidfmt(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
1048 struct sysctl_req *req)
1c79356b 1049{
6d2010ae
A
1050 int *name = (int *) arg1;
1051 int error = ENOENT; /* default error: not found */
1c79356b 1052 u_int namelen = arg2;
2d21ac55 1053 u_int indx;
1c79356b
A
1054 struct sysctl_oid *oid;
1055 struct sysctl_oid_list *lsp = &sysctl__children;
1056
6d2010ae 1057 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b
A
1058 oid = SLIST_FIRST(lsp);
1059
1060 indx = 0;
1061 while (oid && indx < CTL_MAXNAME) {
1062 if (oid->oid_number == name[indx]) {
1063 indx++;
1064 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1065 if (oid->oid_handler)
1066 goto found;
1067 if (indx == namelen)
1068 goto found;
1069 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
1070 oid = SLIST_FIRST(lsp);
1071 } else {
6d2010ae
A
1072 if (indx != namelen) {
1073 error = EISDIR;
1074 goto err;
1075 }
1c79356b
A
1076 goto found;
1077 }
1078 } else {
1079 oid = SLIST_NEXT(oid, oid_link);
1080 }
1081 }
6d2010ae
A
1082 /* Not found */
1083 goto err;
1084
1c79356b
A
1085found:
1086 if (!oid->oid_fmt)
6d2010ae 1087 goto err;
1c79356b
A
1088 error = SYSCTL_OUT(req,
1089 &oid->oid_kind, sizeof(oid->oid_kind));
1090 if (!error)
1091 error = SYSCTL_OUT(req, oid->oid_fmt,
1092 strlen(oid->oid_fmt)+1);
6d2010ae
A
1093err:
1094 lck_rw_done(sysctl_geometry_lock);
1c79356b
A
1095 return (error);
1096}
1097
6d2010ae 1098SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_sysctl_oidfmt, "");
1c79356b 1099
1c79356b
A
1100
1101/*
1102 * Default "handler" functions.
1103 */
1104
1105/*
1106 * Handle an int, signed or unsigned.
1107 * Two cases:
1108 * a variable: point arg1 at it.
1109 * a constant: pass it in arg2.
1110 */
1111
1112int
2d21ac55
A
1113sysctl_handle_int(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
1114 struct sysctl_req *req)
1c79356b 1115{
2d21ac55 1116 return sysctl_io_number(req, arg1? *(int*)arg1: arg2, sizeof(int), arg1, NULL);
1c79356b
A
1117}
1118
1119/*
1120 * Handle a long, signed or unsigned. arg1 points to it.
1121 */
1122
1123int
2d21ac55
A
1124sysctl_handle_long(__unused struct sysctl_oid *oidp, void *arg1,
1125 __unused int arg2, struct sysctl_req *req)
1c79356b 1126{
1c79356b
A
1127 if (!arg1)
1128 return (EINVAL);
2d21ac55 1129 return sysctl_io_number(req, *(long*)arg1, sizeof(long), arg1, NULL);
1c79356b
A
1130}
1131
43866e37
A
1132/*
1133 * Handle a quad, signed or unsigned. arg1 points to it.
1134 */
1135
1136int
2d21ac55
A
1137sysctl_handle_quad(__unused struct sysctl_oid *oidp, void *arg1,
1138 __unused int arg2, struct sysctl_req *req)
43866e37 1139{
43866e37
A
1140 if (!arg1)
1141 return (EINVAL);
2d21ac55 1142 return sysctl_io_number(req, *(long long*)arg1, sizeof(long long), arg1, NULL);
43866e37
A
1143}
1144
1145/*
1146 * Expose an int value as a quad.
1147 *
1148 * This interface allows us to support interfaces defined
1149 * as using quad values while the implementation is still
1150 * using ints.
1151 */
1152int
2d21ac55
A
1153sysctl_handle_int2quad(__unused struct sysctl_oid *oidp, void *arg1,
1154 __unused int arg2, struct sysctl_req *req)
43866e37
A
1155{
1156 int error = 0;
1157 long long val;
1158 int newval;
1159
1160 if (!arg1)
1161 return (EINVAL);
1162 val = (long long)*(int *)arg1;
1163 error = SYSCTL_OUT(req, &val, sizeof(long long));
1164
1165 if (error || !req->newptr)
1166 return (error);
1167
1168 error = SYSCTL_IN(req, &val, sizeof(long long));
1169 if (!error) {
1170 /*
1171 * Value must be representable; check by
1172 * casting and then casting back.
1173 */
1174 newval = (int)val;
1175 if ((long long)newval != val) {
1176 error = ERANGE;
1177 } else {
1178 *(int *)arg1 = newval;
1179 }
1180 }
1181 return (error);
1182}
1183
1c79356b
A
1184/*
1185 * Handle our generic '\0' terminated 'C' string.
1186 * Two cases:
1187 * a variable string: point arg1 at it, arg2 is max length.
1188 * a constant string: point arg1 at it, arg2 is zero.
1189 */
1190
1191int
2d21ac55
A
1192sysctl_handle_string( __unused struct sysctl_oid *oidp, void *arg1, int arg2,
1193 struct sysctl_req *req)
1c79356b 1194{
2d21ac55 1195 return sysctl_io_string(req, arg1, arg2, 0, NULL);
1c79356b
A
1196}
1197
1198/*
1199 * Handle any kind of opaque data.
1200 * arg1 points to it, arg2 is the size.
1201 */
1202
1203int
2d21ac55
A
1204sysctl_handle_opaque(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
1205 struct sysctl_req *req)
1c79356b 1206{
2d21ac55 1207 return sysctl_io_opaque(req, arg1, arg2, NULL);
1c79356b
A
1208}
1209
1210/*
1211 * Transfer functions to/from kernel space.
1c79356b 1212 */
6d2010ae 1213STATIC int
1c79356b
A
1214sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
1215{
1216 size_t i = 0;
1c79356b
A
1217
1218 if (req->oldptr) {
1219 i = l;
1220 if (i > req->oldlen - req->oldidx)
1221 i = req->oldlen - req->oldidx;
43866e37 1222 if (i > 0)
2d21ac55 1223 bcopy((const void*)p, CAST_DOWN(char *, (req->oldptr + req->oldidx)), i);
1c79356b
A
1224 }
1225 req->oldidx += l;
1226 if (req->oldptr && i != l)
1227 return (ENOMEM);
1228 return (0);
1229}
1230
6d2010ae 1231STATIC int
1c79356b
A
1232sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
1233{
1234 if (!req->newptr)
1235 return 0;
1236 if (req->newlen - req->newidx < l)
1237 return (EINVAL);
91447636 1238 bcopy(CAST_DOWN(char *, (req->newptr + req->newidx)), p, l);
1c79356b
A
1239 req->newidx += l;
1240 return (0);
1241}
1242
1243int
43866e37 1244kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen)
1c79356b
A
1245{
1246 int error = 0;
1247 struct sysctl_req req;
1248
43866e37
A
1249 /*
1250 * Construct request.
1251 */
1c79356b 1252 bzero(&req, sizeof req);
1c79356b 1253 req.p = p;
43866e37 1254 if (oldlenp)
1c79356b 1255 req.oldlen = *oldlenp;
43866e37 1256 if (old)
91447636 1257 req.oldptr = CAST_USER_ADDR_T(old);
1c79356b
A
1258 if (newlen) {
1259 req.newlen = newlen;
91447636 1260 req.newptr = CAST_USER_ADDR_T(new);
1c79356b 1261 }
1c79356b
A
1262 req.oldfunc = sysctl_old_kernel;
1263 req.newfunc = sysctl_new_kernel;
1264 req.lock = 1;
1265
43866e37 1266 /* make the request */
fe8ab488 1267 error = sysctl_root(TRUE, FALSE, NULL, 0, name, namelen, &req);
1c79356b 1268
1c79356b
A
1269 if (error && error != ENOMEM)
1270 return (error);
1271
43866e37
A
1272 if (oldlenp)
1273 *oldlenp = req.oldidx;
1274
1c79356b
A
1275 return (error);
1276}
1277
1278/*
1279 * Transfer function to/from user space.
1280 */
6d2010ae 1281STATIC int
1c79356b
A
1282sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1283{
1284 int error = 0;
1285 size_t i = 0;
1286
1287 if (req->oldptr) {
1288 if (req->oldlen - req->oldidx < l)
1289 return (ENOMEM);
1290 i = l;
1291 if (i > req->oldlen - req->oldidx)
1292 i = req->oldlen - req->oldidx;
1293 if (i > 0)
2d21ac55 1294 error = copyout((const void*)p, (req->oldptr + req->oldidx), i);
1c79356b
A
1295 }
1296 req->oldidx += l;
1297 if (error)
1298 return (error);
1299 if (req->oldptr && i < l)
1300 return (ENOMEM);
1301 return (0);
1302}
1303
6d2010ae 1304STATIC int
1c79356b
A
1305sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1306{
1307 int error;
1308
1309 if (!req->newptr)
1310 return 0;
1311 if (req->newlen - req->newidx < l)
1312 return (EINVAL);
91447636 1313 error = copyin((req->newptr + req->newidx), p, l);
1c79356b
A
1314 req->newidx += l;
1315 return (error);
1316}
1317
1318/*
1319 * Traverse our tree, and find the right node, execute whatever it points
1320 * at, and return the resulting error code.
1321 */
1322
1323int
fe8ab488 1324sysctl_root(boolean_t from_kernel, boolean_t string_is_canonical, char *namestring, size_t namestringlen, int *name, u_int namelen, struct sysctl_req *req)
1c79356b 1325{
2d21ac55
A
1326 u_int indx;
1327 int i;
1c79356b
A
1328 struct sysctl_oid *oid;
1329 struct sysctl_oid_list *lsp = &sysctl__children;
1330 int error;
fe8ab488
A
1331 boolean_t unlocked_node_found = FALSE;
1332 boolean_t namestring_started = FALSE;
2d21ac55
A
1333
1334 /* Get the read lock on the geometry */
1335 lck_rw_lock_shared(sysctl_geometry_lock);
1c79356b 1336
fe8ab488
A
1337 if (string_is_canonical) {
1338 /* namestring is actually canonical, name/namelen needs to be populated */
1339 error = name2oid(namestring, name, &namelen);
1340 if (error) {
1341 goto err;
1342 }
1343 }
1344
1c79356b
A
1345 oid = SLIST_FIRST(lsp);
1346
1347 indx = 0;
1348 while (oid && indx < CTL_MAXNAME) {
1349 if (oid->oid_number == name[indx]) {
fe8ab488
A
1350
1351 if (!from_kernel && !string_is_canonical) {
1352 if (namestring_started) {
1353 if (strlcat(namestring, ".", namestringlen) >= namestringlen) {
1354 error = ENAMETOOLONG;
1355 goto err;
1356 }
1357 }
1358
1359 if (strlcat(namestring, oid->oid_name, namestringlen) >= namestringlen) {
1360 error = ENAMETOOLONG;
1361 goto err;
1362 }
1363 namestring_started = TRUE;
1364 }
1365
1c79356b 1366 indx++;
2d21ac55
A
1367 if (!(oid->oid_kind & CTLFLAG_LOCKED))
1368 {
fe8ab488 1369 unlocked_node_found = TRUE;
2d21ac55 1370 }
1c79356b
A
1371 if (oid->oid_kind & CTLFLAG_NOLOCK)
1372 req->lock = 0;
6d2010ae
A
1373 /*
1374 * For SYSCTL_PROC() functions which are for sysctl's
1375 * which have parameters at the end of their OID
1376 * space, you need to OR CTLTYPE_NODE into their
1377 * access value.
1378 *
1379 * NOTE: For binary backward compatibility ONLY! Do
1380 * NOT add new sysctl's that do this! Existing
1381 * sysctl's which do this will eventually have
1382 * compatibility code in user space, and this method
1383 * will become unsupported.
1384 */
1c79356b
A
1385 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1386 if (oid->oid_handler)
1387 goto found;
1388 if (indx == namelen)
2d21ac55
A
1389 {
1390 error = ENOENT;
1391 goto err;
1392 }
1393
1c79356b
A
1394 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
1395 oid = SLIST_FIRST(lsp);
1396 } else {
1397 if (indx != namelen)
2d21ac55
A
1398 {
1399 error = EISDIR;
1400 goto err;
1401 }
1c79356b
A
1402 goto found;
1403 }
1404 } else {
1405 oid = SLIST_NEXT(oid, oid_link);
1406 }
1407 }
2d21ac55
A
1408 error = ENOENT;
1409 goto err;
1c79356b 1410found:
fe8ab488
A
1411
1412 /*
1413 * indx is the index of the first remaining OID name,
1414 * for sysctls that take them as arguments
1415 */
1416 if (!from_kernel && !string_is_canonical && (indx < namelen)) {
1417 char tempbuf[10];
1418 u_int indx2;
1419
1420 for (indx2 = indx; indx2 < namelen; indx2++) {
1421 snprintf(tempbuf, sizeof(tempbuf), "%d",name[indx2]);
1422
1423 if (namestring_started) {
1424 if (strlcat(namestring, ".", namestringlen) >= namestringlen) {
1425 error = ENAMETOOLONG;
1426 goto err;
1427 }
1428 }
1429
1430 if (strlcat(namestring, tempbuf, namestringlen) >= namestringlen) {
1431 error = ENAMETOOLONG;
1432 goto err;
1433 }
1434 namestring_started = TRUE;
1435 }
1436 }
1437
1c79356b
A
1438 /* If writing isn't allowed */
1439 if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
1440 ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) {
2d21ac55
A
1441 error = (EPERM);
1442 goto err;
1c79356b
A
1443 }
1444
43866e37
A
1445 /*
1446 * If we're inside the kernel, the OID must be marked as kernel-valid.
43866e37 1447 */
fe8ab488 1448 if (from_kernel && !(oid->oid_kind & CTLFLAG_KERN))
2d21ac55
A
1449 {
1450 error = (EPERM);
1451 goto err;
1452 }
43866e37 1453
6d2010ae
A
1454 /*
1455 * This is where legacy enforcement of permissions occurs. If the
1456 * flag does not say CTLFLAG_ANYBODY, then we prohibit anyone but
1457 * root from writing new values down. If local enforcement happens
1458 * at the leaf node, then it needs to be set as CTLFLAG_ANYBODY. In
1459 * addition, if the leaf node is set this way, then in order to do
1460 * specific enforcement, it has to be of type SYSCTL_PROC.
1461 */
1c79356b
A
1462 if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
1463 req->newptr && req->p &&
2d21ac55
A
1464 (error = proc_suser(req->p)))
1465 goto err;
1c79356b
A
1466
1467 if (!oid->oid_handler) {
2d21ac55
A
1468 error = EINVAL;
1469 goto err;
1c79356b
A
1470 }
1471
6d2010ae
A
1472 /*
1473 * Reference the OID and drop the geometry lock; this prevents the
1474 * OID from being deleted out from under the handler call, but does
1475 * not prevent other calls into handlers or calls to manage the
1476 * geometry elsewhere from blocking...
1477 */
1478 OSAddAtomic(1, &oid->oid_refcnt);
1479
1480 lck_rw_done(sysctl_geometry_lock);
1481
fe8ab488
A
1482#if CONFIG_MACF
1483 if (!from_kernel) {
1484 error = mac_system_check_sysctlbyname(kauth_cred_get(),
1485 namestring,
1486 name,
1487 namelen,
1488 req->oldptr,
1489 req->oldlen,
1490 req->newptr,
1491 req->newlen);
1492 if (error)
1493 goto dropref;
1494 }
1495#endif
1496
6d2010ae 1497 /*
fe8ab488
A
1498 * ...however, we still have to grab the mutex for those calls which
1499 * may be into code whose reentrancy is protected by it.
6d2010ae 1500 */
fe8ab488 1501 if (unlocked_node_found)
2d21ac55 1502 {
fe8ab488 1503 lck_mtx_lock(sysctl_unlocked_node_lock);
2d21ac55 1504 }
1c79356b
A
1505
1506 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1507 i = (oid->oid_handler) (oid,
1508 name + indx, namelen - indx,
1509 req);
1510 } else {
1511 i = (oid->oid_handler) (oid,
1512 oid->oid_arg1, oid->oid_arg2,
1513 req);
1514 }
2d21ac55
A
1515 error = i;
1516
fe8ab488 1517 if (unlocked_node_found)
2d21ac55 1518 {
fe8ab488 1519 lck_mtx_unlock(sysctl_unlocked_node_lock);
2d21ac55 1520 }
1c79356b 1521
fe8ab488
A
1522#if CONFIG_MACF
1523 /* only used from another CONFIG_MACF block */
1524dropref:
1525#endif
1526
6d2010ae
A
1527 /*
1528 * This is tricky... we re-grab the geometry lock in order to drop
1529 * the reference and wake on the address; since the geometry
1530 * lock is a reader/writer lock rather than a mutex, we have to
1531 * wake on all apparent 1->0 transitions. This abuses the drop
1532 * after the reference decrement in order to wake any lck_rw_sleep()
1533 * in progress in sysctl_unregister_oid() that slept because of a
1534 * non-zero reference count.
1535 *
1536 * Note: OSAddAtomic() is defined to return the previous value;
1537 * we use this and the fact that the lock itself is a
1538 * barrier to avoid waking every time through on "hot"
1539 * OIDs.
1540 */
1541 lck_rw_lock_shared(sysctl_geometry_lock);
1542 if (OSAddAtomic(-1, &oid->oid_refcnt) == 1)
1543 wakeup(&oid->oid_refcnt);
1544
2d21ac55
A
1545err:
1546 lck_rw_done(sysctl_geometry_lock);
1547 return (error);
1c79356b
A
1548}
1549
fe8ab488
A
1550void sysctl_create_user_req(struct sysctl_req *req, struct proc *p, user_addr_t oldp,
1551 size_t oldlen, user_addr_t newp, size_t newlen)
1552{
1553 bzero(req, sizeof(*req));
1554
1555 req->p = p;
1556
1557 req->oldlen = oldlen;
1558 req->oldptr = oldp;
1559
1560 if (newlen) {
1561 req->newlen = newlen;
1562 req->newptr = newp;
1563 }
1564
1565 req->oldfunc = sysctl_old_user;
1566 req->newfunc = sysctl_new_user;
1567 req->lock = 1;
1568
1569 return;
1570}
1c79356b
A
1571
1572int
fe8ab488 1573sysctl(proc_t p, struct sysctl_args *uap, __unused int32_t *retval)
1c79356b 1574{
fe8ab488
A
1575 int error;
1576 size_t oldlen = 0, newlen;
1577 int name[CTL_MAXNAME];
1578 struct sysctl_req req;
1579 char *namestring;
1580 size_t namestringlen = MAXPATHLEN;
1581
1582 /*
1583 * all top-level sysctl names are non-terminal
1584 */
1c79356b
A
1585 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1586 return (EINVAL);
fe8ab488
A
1587 error = copyin(uap->name, &name[0], uap->namelen * sizeof(int));
1588 if (error)
1589 return (error);
1590
1591 AUDIT_ARG(ctlname, name, uap->namelen);
1592
1593 if (uap->newlen > SIZE_T_MAX)
1594 return (EINVAL);
1595 newlen = (size_t)uap->newlen;
1596
1597 if (uap->oldlenp != USER_ADDR_NULL) {
1598 uint64_t oldlen64 = fuulong(uap->oldlenp);
1599
1600 /*
1601 * If more than 4G, clamp to 4G
1602 */
1603 if (oldlen64 > SIZE_T_MAX)
1604 oldlen = SIZE_T_MAX;
1605 else
1606 oldlen = (size_t)oldlen64;
1607 }
1608
1609 sysctl_create_user_req(&req, p, uap->old, oldlen, uap->new, newlen);
1610
1611 /* Guess that longest length for the passed-in MIB, if we can be more aggressive than MAXPATHLEN */
1612 if (uap->namelen == 2) {
1613 if (name[0] == CTL_KERN && name[1] < KERN_MAXID) {
1614 namestringlen = 32; /* "kern.speculative_reads_disabled" */
1615 } else if (name[0] == CTL_HW && name[1] < HW_MAXID) {
1616 namestringlen = 32; /* "hw.cachelinesize_compat" */
1617 }
1618 }
1619
1620 MALLOC(namestring, char *, namestringlen, M_TEMP, M_WAITOK);
1621 if (!namestring) {
1622 oldlen = 0;
1623 goto err;
1624 }
1c79356b 1625
fe8ab488
A
1626 error = userland_sysctl(FALSE, namestring, namestringlen, name, uap->namelen, &req, &oldlen);
1627
1628 FREE(namestring, M_TEMP);
1629
1630 if ((error) && (error != ENOMEM))
1c79356b 1631 return (error);
fe8ab488
A
1632
1633err:
1634 if (uap->oldlenp != USER_ADDR_NULL)
1635 error = suulong(uap->oldlenp, oldlen);
1636
1637 return (error);
1638}
1c79356b 1639
fe8ab488
A
1640int
1641sysctlbyname(proc_t p, struct sysctlbyname_args *uap, __unused int32_t *retval)
1642{
1643 int error;
1644 size_t oldlen = 0, newlen;
1645 char *name;
1646 size_t namelen = 0;
1647 struct sysctl_req req;
1648 int oid[CTL_MAXNAME];
1649
1650 if (uap->namelen >= MAXPATHLEN) /* XXX arbitrary, undocumented */
1651 return (ENAMETOOLONG);
1652 namelen = (size_t)uap->namelen;
1653
1654 MALLOC(name, char *, namelen+1, M_TEMP, M_WAITOK);
1655 if (!name)
1656 return ENOMEM;
1657
1658 error = copyin(uap->name, name, namelen);
1659 if (error) {
1660 FREE(name, M_TEMP);
1c79356b 1661 return (error);
1c79356b 1662 }
fe8ab488
A
1663 name[namelen] = '\0';
1664
1665 /* XXX
1666 * AUDIT_ARG(ctlname, name, uap->namelen);
1667 */
1668
1669 if (uap->newlen > SIZE_T_MAX) {
1670 FREE(name, M_TEMP);
1671 return (EINVAL);
1672 }
1673 newlen = (size_t)uap->newlen;
1674
1675 if (uap->oldlenp != USER_ADDR_NULL) {
1676 uint64_t oldlen64 = fuulong(uap->oldlenp);
1677
1678 /*
1679 * If more than 4G, clamp to 4G
1680 */
1681 if (oldlen64 > SIZE_T_MAX)
1682 oldlen = SIZE_T_MAX;
1683 else
1684 oldlen = (size_t)oldlen64;
1685 }
1686
1687 sysctl_create_user_req(&req, p, uap->old, oldlen, uap->new, newlen);
1688
1689 error = userland_sysctl(TRUE, name, namelen+1, oid, CTL_MAXNAME, &req, &oldlen);
1690
1691 FREE(name, M_TEMP);
1692
1693 if ((error) && (error != ENOMEM))
1694 return (error);
1695
1696 if (uap->oldlenp != USER_ADDR_NULL)
1697 error = suulong(uap->oldlenp, oldlen);
1698
1c79356b
A
1699 return (error);
1700}
1701
1702/*
1703 * This is used from various compatibility syscalls too. That's why name
1704 * must be in kernel space.
1705 */
1706int
fe8ab488
A
1707userland_sysctl(boolean_t string_is_canonical,
1708 char *namestring, size_t namestringlen,
1709 int *name, u_int namelen, struct sysctl_req *req,
91447636 1710 size_t *retval)
1c79356b
A
1711{
1712 int error = 0;
fe8ab488 1713 struct sysctl_req req2;
1c79356b
A
1714
1715 do {
fe8ab488
A
1716 /* if EAGAIN, reset output cursor */
1717 req2 = *req;
1718 if (!string_is_canonical)
1719 namestring[0] = '\0';
1c79356b 1720
fe8ab488
A
1721 error = sysctl_root(FALSE, string_is_canonical, namestring, namestringlen, name, namelen, &req2);
1722 } while (error == EAGAIN);
1c79356b
A
1723
1724 if (error && error != ENOMEM)
1725 return (error);
1726
1727 if (retval) {
fe8ab488
A
1728 if (req2.oldptr && req2.oldidx > req2.oldlen)
1729 *retval = req2.oldlen;
1c79356b 1730 else
fe8ab488 1731 *retval = req2.oldidx;
1c79356b
A
1732 }
1733 return (error);
1734}
1c79356b
A
1735
1736/*
43866e37
A
1737 * Kernel versions of the userland sysctl helper functions.
1738 *
1739 * These allow sysctl to be used in the same fashion in both
1740 * userland and the kernel.
1741 *
1742 * Note that some sysctl handlers use copyin/copyout, which
1743 * may not work correctly.
fe8ab488
A
1744 *
1745 * The "sysctlbyname" KPI for use by kexts is aliased to this function.
de355530 1746 */
1c79356b 1747
43866e37 1748int
fe8ab488 1749kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
43866e37 1750{
fe8ab488
A
1751 int oid[CTL_MAXNAME];
1752 int name2mib_oid[2];
43866e37
A
1753 int error;
1754 size_t oidlen;
de355530 1755
fe8ab488
A
1756 /* look up the OID with magic service node */
1757 name2mib_oid[0] = 0;
1758 name2mib_oid[1] = 3;
de355530 1759
fe8ab488 1760 oidlen = sizeof(oid);
3e170ce0 1761 error = kernel_sysctl(current_proc(), name2mib_oid, 2, oid, &oidlen, __DECONST(void *, name), strlen(name));
fe8ab488
A
1762 oidlen /= sizeof(int);
1763
43866e37
A
1764 /* now use the OID */
1765 if (error == 0)
fe8ab488 1766 error = kernel_sysctl(current_proc(), oid, oidlen, oldp, oldlenp, newp, newlen);
43866e37 1767 return(error);
1c79356b 1768}
1c79356b 1769