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