]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_sysctl.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / kern / kern_sysctl.c
index 047eb70b1a38cb0dd8958324dd1a5629e86e302e..fe123db9b1ec46353161ac7e39f2fbce2f6af066 100644 (file)
@@ -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 <sys/disklabel.h>
 #include <sys/vm.h>
 #include <sys/sysctl.h>
+#include <sys/user.h>
 #include <mach/machine.h>
 #include <mach/mach_types.h>
 #include <mach/vm_param.h>
@@ -92,11 +96,10 @@ extern vm_map_t bsd_pageable_map;
 #include <pexpert/pexpert.h>
 
 #if __ppc__
-#include <osfmk/ppc/machine_routines.h>
+#include <ppc/machine_routines.h>
 #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, &copy_start, round_page(arg_size));
        if (ret != KERN_SUCCESS) {