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