X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..90556fb8d47e7b68fd301dde9dbb3ae7495cf323:/bsd/kern/kern_sysctl.c?ds=sidebyside diff --git a/bsd/kern/kern_sysctl.c b/bsd/kern/kern_sysctl.c index c7332ad05..cf5ec167c 100644 --- a/bsd/kern/kern_sysctl.c +++ b/bsd/kern/kern_sysctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +93,7 @@ extern vm_map_t bsd_pageable_map; #include #if __ppc__ -#include +#include #endif sysctlfn kern_sysctl; @@ -121,6 +122,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 +132,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 +185,7 @@ __sysctl(p, uap, retval) sysctlfn *fn; int name[CTL_MAXNAME]; int i; + int error1; /* * all top-level sysctl names are non-terminal @@ -200,17 +197,20 @@ __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: @@ -223,11 +223,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 +241,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 +251,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 +277,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 +316,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 +335,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,24 +427,23 @@ 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); } @@ -468,7 +484,8 @@ hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) if(!PEGetModelName(dummy,64)) return(EINVAL); return (sysctl_rdstring(oldp, oldlenp, newp, dummy)); - case HW_NCPU: { + case HW_NCPU: + { int numcpus=1; host_basic_info_data_t hinfo; kern_return_t kret; @@ -500,6 +517,8 @@ hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 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)); + case HW_TB_FREQ: + return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.timebase_frequency_hz)); #if __ppc__ case HW_VECTORUNIT: return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.vector_unit)); @@ -579,6 +598,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 +623,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 +642,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 +710,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 +724,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 +748,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 +776,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 +798,7 @@ sysctl_rdstruct(oldp, oldlenp, newp, sp, len) /* * Get file structures. */ +int sysctl_file(where, sizep) char *where; size_t *sizep; @@ -776,6 +850,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; @@ -837,6 +912,7 @@ again: break; } if (buflen >= sizeof(struct kinfo_proc)) { + bzero(&kproc, sizeof(struct kinfo_proc)); fill_proc(p, &kproc, doingzomb); if (error = copyout((caddr_t)&kproc, &dp->kp_proc, sizeof(struct kinfo_proc))) @@ -882,28 +958,22 @@ fill_eproc(p, ep) { register struct tty *tp; + /* + * Skip zombie processes. + */ + if (p->p_stat == SZOMB) + return; + ep->e_paddr = p; ep->e_sess = p->p_pgrp->pg_session; 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 @@ -934,6 +1004,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; @@ -961,10 +1033,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 ; @@ -979,6 +1051,7 @@ fill_externproc(p, exp) exp->p_ru = p->p_ru ; } +int kdebug_ops(name, namelen, where, sizep, p) int *name; u_int namelen; @@ -986,12 +1059,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: @@ -1008,6 +1082,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: @@ -1017,6 +1092,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; @@ -1024,11 +1100,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: @@ -1054,11 +1131,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; @@ -1089,6 +1168,7 @@ sysctl_procargs(name, namelen, where, sizep) */ pid = name[0]; + restart: p = pfind(pid); if (p == NULL) { return(EINVAL); @@ -1107,6 +1187,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); @@ -1119,7 +1202,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) {