X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e7c99d92bf4e4d1189c904195ed317951f9a35ad..43866e378188c25dd1e2208016ab3cbeb086ae6c:/bsd/kern/kern_sysctl.c diff --git a/bsd/kern/kern_sysctl.c b/bsd/kern/kern_sysctl.c index 047eb70b1..fe123db9b 100644 --- a/bsd/kern/kern_sysctl.c +++ b/bsd/kern/kern_sysctl.c @@ -1,21 +1,24 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ @@ -76,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -92,11 +96,10 @@ extern vm_map_t bsd_pageable_map; #include #if __ppc__ -#include +#include #endif sysctlfn kern_sysctl; -sysctlfn hw_sysctl; #ifdef DEBUG sysctlfn debug_sysctl; #endif @@ -121,6 +124,7 @@ fill_externproc(struct proc *p, struct extern_proc *exp); /* * temporary location for vm_sysctl. This should be machine independant */ +int vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) int *name; u_int namelen; @@ -130,26 +134,20 @@ vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) size_t newlen; struct proc *p; { - int error, level, inthostid; - extern long avenrun[3], mach_factor[3]; + extern uint32_t mach_factor[3]; struct loadavg loadinfo; - //if (namelen != 1 && !(name[0] == VM_LOADAVG)) - //return (ENOTDIR); /* overloaded */ - switch (name[0]) { case VM_LOADAVG: - loadinfo.ldavg[0] = avenrun[0]; - loadinfo.ldavg[1] = avenrun[1]; - loadinfo.ldavg[2] = avenrun[2]; - loadinfo.fscale = LSCALE; - return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg))); + return (sysctl_struct(oldp, oldlenp, newp, newlen, + &averunnable, sizeof(struct loadavg))); case VM_MACHFACTOR: loadinfo.ldavg[0] = mach_factor[0]; loadinfo.ldavg[1] = mach_factor[1]; loadinfo.ldavg[2] = mach_factor[2]; loadinfo.fscale = LSCALE; - return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg))); + return (sysctl_struct(oldp, oldlenp, newp, newlen, + &loadinfo, sizeof(struct loadavg))); case VM_METER: return (EOPNOTSUPP); case VM_MAXID: @@ -189,6 +187,7 @@ __sysctl(p, uap, retval) sysctlfn *fn; int name[CTL_MAXNAME]; int i; + int error1; /* * all top-level sysctl names are non-terminal @@ -200,22 +199,22 @@ __sysctl(p, uap, retval) return (error); /* CTL_UNSPEC is used to get oid to AUTO_OID */ - if (uap->new != NULL && - (((name[0] == CTL_KERN) && (name[1] != KERN_IPC)) || - (name[0] == CTL_HW) || (name[0] == CTL_VM) || - (name[0] == CTL_VFS)) && - (error = suser(p->p_ucred, &p->p_acflag))) + if (uap->new != NULL + && ((name[0] == CTL_KERN + && !(name[1] == KERN_IPC || name[1] == KERN_PANICINFO)) + || (name[0] == CTL_HW) + || (name[0] == CTL_VM) + || (name[0] == CTL_VFS)) + && (error = suser(p->p_ucred, &p->p_acflag))) return (error); switch (name[0]) { case CTL_KERN: fn = kern_sysctl; - if (name[1] != KERN_VNODE) /* XXX */ + if ((name[1] != KERN_VNODE) && (name[1] != KERN_FILE) + && (name[1] != KERN_PROC)) dolock = 0; break; - case CTL_HW: - fn = hw_sysctl; - break; case CTL_VM: fn = vm_sysctl; break; @@ -223,11 +222,6 @@ __sysctl(p, uap, retval) case CTL_VFS: fn = vfs_sysctl; break; -#if FIXME /* [ */ - case CTL_MACHDEP: - fn = cpu_sysctl; - break; -#endif /* FIXME ] */ #ifdef DEBUG case CTL_DEBUG: fn = debug_sysctl; @@ -246,7 +240,8 @@ __sysctl(p, uap, retval) return (EFAULT); /* The pc sampling mechanism does not need to take this lock */ - if (name[1] != KERN_PCSAMPLES) { + if ((name[1] != KERN_PCSAMPLES) && + (!((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) { while (memlock.sl_lock) { memlock.sl_want = 1; sleep((caddr_t)&memlock, PRIBIO+1); @@ -255,8 +250,17 @@ __sysctl(p, uap, retval) memlock.sl_lock = 1; } - if (dolock) - vslock(uap->old, oldlen); + if (dolock && oldlen && (error = vslock(uap->old, oldlen))) { + if ((name[1] != KERN_PCSAMPLES) && + (! ((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) { + memlock.sl_lock = 0; + if (memlock.sl_want) { + memlock.sl_want = 0; + wakeup((caddr_t)&memlock); + } + } + return(error); + } savelen = oldlen; } @@ -272,8 +276,11 @@ __sysctl(p, uap, retval) uap->new, uap->newlen, &oldlen); if (uap->old != NULL) { - if (dolock) - vsunlock(uap->old, savelen, B_WRITE); + if (dolock && savelen) { + error1 = vsunlock(uap->old, savelen, B_WRITE); + if (!error && error1) + error = error1; + } if (name[1] != KERN_PCSAMPLES) { memlock.sl_lock = 0; if (memlock.sl_want) { @@ -308,11 +315,14 @@ int securelevel = -1; int securelevel; #endif -int get_kernel_symfile( struct proc *p, char **symfile ); +extern int get_kernel_symfile( struct proc *, char **); +extern int sysctl_dopanicinfo(int *, u_int, void *, size_t *, + void *, size_t, struct proc *); /* * kernel related system variables. */ +int kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) int *name; u_int namelen; @@ -324,15 +334,21 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) { int error, level, inthostid; unsigned int oldval=0; + char *str; extern char ostype[], osrelease[], version[]; - - /* all sysctl names at this level are terminal */ - if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF - || name[0] == KERN_KDEBUG - || name[0] == KERN_PROCARGS - || name[0] == KERN_PCSAMPLES - || name[0] == KERN_IPC - )) + extern int netboot_root(); + + /* all sysctl names not listed below are terminal at this level */ + if (namelen != 1 + && !(name[0] == KERN_PROC + || name[0] == KERN_PROF + || name[0] == KERN_KDEBUG + || name[0] == KERN_PROCARGS + || name[0] == KERN_PCSAMPLES + || name[0] == KERN_IPC + || name[0] == KERN_SYSV + || name[0] == KERN_PANICINFO) + ) return (ENOTDIR); /* overloaded */ switch (name[0]) { @@ -410,123 +426,29 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) #else return (sysctl_rdint(oldp, oldlenp, newp, 0)); #endif -#if FIXME /* [ */ - case KERN_MAXPARTITIONS: - return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); -#endif /* FIXME ] */ case KERN_KDEBUG: return (kdebug_ops(name + 1, namelen - 1, oldp, oldlenp, p)); case KERN_PCSAMPLES: return (pcsamples_ops(name + 1, namelen - 1, oldp, oldlenp, p)); case KERN_PROCARGS: /* new one as it does not use kinfo_proc */ - return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp)); - case KERN_SYMFILE: - { - char *str; - error = get_kernel_symfile( p, &str ); - if ( error ) return error; - return (sysctl_rdstring(oldp, oldlenp, newp, str)); - } + return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp, p)); + case KERN_SYMFILE: + error = get_kernel_symfile( p, &str ); + if ( error ) + return error; + return (sysctl_rdstring(oldp, oldlenp, newp, str)); + case KERN_NETBOOT: + return (sysctl_rdint(oldp, oldlenp, newp, netboot_root())); + case KERN_PANICINFO: + return(sysctl_dopanicinfo(name + 1, namelen - 1, oldp, oldlenp, + newp, newlen, p)); default: return (EOPNOTSUPP); } /* NOTREACHED */ } -/* - * hardware related system variables. - */ -hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; - struct proc *p; -{ - char dummy[65]; - int epochTemp; - extern int vm_page_wire_count; -#if __ppc__ - ml_ppc_cpu_info_t cpu_info; - - ml_ppc_get_info(&cpu_info); -#endif - - /* all sysctl names at this level are terminal */ - if (namelen != 1) - return (ENOTDIR); /* overloaded */ - - switch (name[0]) { - case HW_MACHINE: - if(!PEGetMachineName(dummy,64)) - return(EINVAL); - return (sysctl_rdstring(oldp, oldlenp, newp, dummy)); - case HW_MODEL: - if(!PEGetModelName(dummy,64)) - return(EINVAL); - return (sysctl_rdstring(oldp, oldlenp, newp, dummy)); - case HW_NCPU: { - int numcpus=1; - host_basic_info_data_t hinfo; - kern_return_t kret; - int count= HOST_BASIC_INFO_COUNT; -#define BSD_HOST 1 - - kret = host_info(BSD_HOST, HOST_BASIC_INFO, &hinfo, &count); - if (kret == KERN_SUCCESS) { - numcpus = hinfo.avail_cpus; - return (sysctl_rdint(oldp, oldlenp, newp, numcpus)); - } else { - return(EINVAL); - } - } - case HW_BYTEORDER: - return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); - case HW_PHYSMEM: - return (sysctl_rdint(oldp, oldlenp, newp, mem_size)); - case HW_USERMEM: - return (sysctl_rdint(oldp, oldlenp, newp, - (mem_size - vm_page_wire_count * page_size))); - case HW_PAGESIZE: - return (sysctl_rdint(oldp, oldlenp, newp, page_size)); - case HW_EPOCH: - epochTemp = PEGetPlatformEpoch(); - if (epochTemp == -1) return(EINVAL); - return (sysctl_rdint(oldp, oldlenp, newp, epochTemp)); - case HW_BUS_FREQ: - return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.bus_clock_rate_hz)); - case HW_CPU_FREQ: - return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.cpu_clock_rate_hz)); -#if __ppc__ - case HW_VECTORUNIT: - return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.vector_unit)); - case HW_CACHELINE: - return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.cache_line_size)); - case HW_L1ICACHESIZE: - return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l1_icache_size)); - case HW_L1DCACHESIZE: - return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l1_dcache_size)); - case HW_L2SETTINGS: - if (cpu_info.l2_cache_size == 0xFFFFFFFF) return(EINVAL); - return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l2_settings)); - case HW_L2CACHESIZE: - if (cpu_info.l2_cache_size == 0xFFFFFFFF) return(EINVAL); - return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l2_cache_size)); - case HW_L3SETTINGS: - if (cpu_info.l3_cache_size == 0xFFFFFFFF) return(EINVAL); - return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l3_settings)); - case HW_L3CACHESIZE: - if (cpu_info.l3_cache_size == 0xFFFFFFFF) return(EINVAL); - return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l3_cache_size)); -#endif - default: - return (EOPNOTSUPP); - } -} - #ifdef DEBUG /* * Debugging related system variables. @@ -579,6 +501,7 @@ debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) * Validate parameters and get old / set new parameters * for an integer-valued sysctl function. */ +int sysctl_int(oldp, oldlenp, newp, newlen, valp) void *oldp; size_t *oldlenp; @@ -603,6 +526,7 @@ sysctl_int(oldp, oldlenp, newp, newlen, valp) /* * As above, but read-only. */ +int sysctl_rdint(oldp, oldlenp, newp, val) void *oldp; size_t *oldlenp; @@ -621,10 +545,59 @@ sysctl_rdint(oldp, oldlenp, newp, val) return (error); } +/* + * Validate parameters and get old / set new parameters + * for an quad(64bit)-valued sysctl function. + */ +int +sysctl_quad(oldp, oldlenp, newp, newlen, valp) + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + quad_t *valp; +{ + int error = 0; + + if (oldp && *oldlenp < sizeof(quad_t)) + return (ENOMEM); + if (newp && newlen != sizeof(quad_t)) + return (EINVAL); + *oldlenp = sizeof(quad_t); + if (oldp) + error = copyout(valp, oldp, sizeof(quad_t)); + if (error == 0 && newp) + error = copyin(newp, valp, sizeof(quad_t)); + return (error); +} + +/* + * As above, but read-only. + */ +int +sysctl_rdquad(oldp, oldlenp, newp, val) + void *oldp; + size_t *oldlenp; + void *newp; + quad_t val; +{ + int error = 0; + + if (oldp && *oldlenp < sizeof(quad_t)) + return (ENOMEM); + if (newp) + return (EPERM); + *oldlenp = sizeof(quad_t); + if (oldp) + error = copyout((caddr_t)&val, oldp, sizeof(quad_t)); + return (error); +} + /* * Validate parameters and get old / set new parameters * for a string-valued sysctl function. */ +int sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) void *oldp; size_t *oldlenp; @@ -640,8 +613,8 @@ sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) return (ENOMEM); if (newp && newlen >= maxlen) return (EINVAL); + *oldlenp = len -1; /* deal with NULL strings correctly */ if (oldp) { - *oldlenp = len; error = copyout(str, oldp, len); } if (error == 0 && newp) { @@ -654,6 +627,7 @@ sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) /* * As above, but read-only. */ +int sysctl_rdstring(oldp, oldlenp, newp, str) void *oldp; size_t *oldlenp; @@ -677,6 +651,7 @@ sysctl_rdstring(oldp, oldlenp, newp, str) * Validate parameters and get old / set new parameters * for a structure oriented sysctl function. */ +int sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) void *oldp; size_t *oldlenp; @@ -704,6 +679,7 @@ sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) * Validate parameters and get old parameters * for a structure oriented sysctl function. */ +int sysctl_rdstruct(oldp, oldlenp, newp, sp, len) void *oldp; size_t *oldlenp; @@ -725,6 +701,7 @@ sysctl_rdstruct(oldp, oldlenp, newp, sp, len) /* * Get file structures. */ +int sysctl_file(where, sizep) char *where; size_t *sizep; @@ -776,6 +753,7 @@ sysctl_file(where, sizep) */ #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) +int sysctl_doproc(name, namelen, where, sizep) int *name; u_int namelen; @@ -894,23 +872,11 @@ fill_eproc(p, ep) ep->e_pcred = *p->p_cred; ep->e_ucred = *p->p_ucred; if (p->p_stat == SIDL || p->p_stat == SZOMB) { - ep->e_vm.vm_rssize = 0; ep->e_vm.vm_tsize = 0; ep->e_vm.vm_dsize = 0; ep->e_vm.vm_ssize = 0; - /* ep->e_vm.vm_pmap = XXX; */ - } else { -#if FIXME /* [ */ - register vm_map_t vm = ((task_t)p->task)->map; - - ep->e_vm.vm_rssize = pmap_resident_count(vm->pmap); /*XXX*/ -// ep->e_vm.vm_tsize = vm->vm_tsize; -// ep->e_vm.vm_dsize = vm->vm_dsize; -// ep->e_vm.vm_ssize = vm->vm_ssize; -#else /* FIXME ][ */ - ep->e_vm.vm_rssize = 0; /*XXX*/ -#endif /* FIXME ] */ } + ep->e_vm.vm_rssize = 0; if (p->p_pptr) ep->e_ppid = p->p_pptr->p_pid; else @@ -941,6 +907,8 @@ fill_externproc(p, exp) register struct extern_proc *exp; { exp->p_forw = exp->p_back = NULL; + if (p->p_stats) + exp->p_starttime = p->p_stats->p_start; exp->p_vmspace = NULL; exp->p_sigacts = p->p_sigacts; exp->p_flag = p->p_flag; @@ -968,10 +936,10 @@ fill_externproc(p, exp) exp->p_iticks = p->p_iticks ; exp->p_traceflag = p->p_traceflag ; exp->p_tracep = p->p_tracep ; - exp->p_siglist = p->p_siglist ; + exp->p_siglist = 0 ; /* No longer relevant */ exp->p_textvp = p->p_textvp ; exp->p_holdcnt = 0 ; - exp->p_sigmask = p->p_sigmask ; + exp->p_sigmask = 0 ; /* no longer avaialable */ exp->p_sigignore = p->p_sigignore ; exp->p_sigcatch = p->p_sigcatch ; exp->p_priority = p->p_priority ; @@ -986,6 +954,7 @@ fill_externproc(p, exp) exp->p_ru = p->p_ru ; } +int kdebug_ops(name, namelen, where, sizep, p) int *name; u_int namelen; @@ -993,12 +962,13 @@ char *where; size_t *sizep; struct proc *p; { -int size=*sizep; -int ret=0; -extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep); + int size=*sizep; + int ret=0; + extern int kdbg_control(int *name, u_int namelen, + char * where,size_t * sizep); - if (ret = suser(p->p_ucred, &p->p_acflag)) - return(ret); + if (ret = suser(p->p_ucred, &p->p_acflag)) + return(ret); switch(name[0]) { case KERN_KDEFLAGS: @@ -1015,6 +985,7 @@ extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep); case KERN_KDPIDEX: case KERN_KDSETRTCDEC: case KERN_KDSETBUF: + case KERN_KDGETENTROPY: ret = kdbg_control(name, namelen, where, sizep); break; default: @@ -1024,6 +995,7 @@ extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep); return(ret); } +int pcsamples_ops(name, namelen, where, sizep, p) int *name; u_int namelen; @@ -1031,11 +1003,12 @@ char *where; size_t *sizep; struct proc *p; { -int ret=0; -extern int pcsamples_control(int *name, u_int namelen, char * where,size_t * sizep); + int ret=0; + extern int pcsamples_control(int *name, u_int namelen, + char * where,size_t * sizep); - if (ret = suser(p->p_ucred, &p->p_acflag)) - return(ret); + if (ret = suser(p->p_ucred, &p->p_acflag)) + return(ret); switch(name[0]) { case KERN_PCDISABLE: @@ -1061,11 +1034,13 @@ extern int pcsamples_control(int *name, u_int namelen, char * where,size_t * siz * zeroed for security reasons. * Odd data structure is for compatibility. */ -sysctl_procargs(name, namelen, where, sizep) +int +sysctl_procargs(name, namelen, where, sizep, cur_proc) int *name; u_int namelen; char *where; size_t *sizep; + struct proc *cur_proc; { register struct proc *p; register int needed = 0; @@ -1096,6 +1071,7 @@ sysctl_procargs(name, namelen, where, sizep) */ pid = name[0]; + restart: p = pfind(pid); if (p == NULL) { return(EINVAL); @@ -1114,6 +1090,9 @@ sysctl_procargs(name, namelen, where, sizep) if (!p->user_stack) return(EINVAL); + if ((p->p_ucred->cr_uid != cur_proc->p_ucred->cr_uid) + && suser(cur_proc->p_ucred, &cur_proc->p_acflag)) + return (EINVAL); arg_addr = (vm_offset_t)(p->user_stack - arg_size); @@ -1126,7 +1105,16 @@ sysctl_procargs(name, namelen, where, sizep) if (task == NULL) return(EINVAL); - task_reference(task); + /* + * A regular task_reference call can block, causing the funnel + * to be dropped and allowing the proc/task to get freed. + * Instead, we issue a non-blocking attempt at the task reference, + * and look up the proc/task all over again if that fails. + */ + if (!task_reference_try(task)) { + mutex_pause(); + goto restart; + } ret = kmem_alloc(kernel_map, ©_start, round_page(arg_size)); if (ret != KERN_SUCCESS) {