Module Name: src Committed By: snj Date: Wed Jul 1 22:42:29 UTC 2009
Modified Files: src/sys/kern [netbsd-5]: init_sysctl.c Log Message: Pull up following revision(s) (requested by rmind in ticket #839): sys/kern/init_sysctl.c: revision 1.163 sysctl_doeproc: - simplify. - KERN_PROC: fix possible stale proc pointer dereference. - KERN_PROC: don't do copyout with proc_lock held. To generate a diff of this commit: cvs rdiff -u -r1.149.4.6 -r1.149.4.7 src/sys/kern/init_sysctl.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/init_sysctl.c diff -u src/sys/kern/init_sysctl.c:1.149.4.6 src/sys/kern/init_sysctl.c:1.149.4.7 --- src/sys/kern/init_sysctl.c:1.149.4.6 Wed Jul 1 22:39:20 2009 +++ src/sys/kern/init_sysctl.c Wed Jul 1 22:42:28 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: init_sysctl.c,v 1.149.4.6 2009/07/01 22:39:20 snj Exp $ */ +/* $NetBSD: init_sysctl.c,v 1.149.4.7 2009/07/01 22:42:28 snj Exp $ */ /*- * Copyright (c) 2003, 2007, 2008 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: init_sysctl.c,v 1.149.4.6 2009/07/01 22:39:20 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: init_sysctl.c,v 1.149.4.7 2009/07/01 22:42:28 snj Exp $"); #include "opt_sysv.h" #include "opt_compat_netbsd32.h" @@ -2152,21 +2152,21 @@ static int sysctl_doeproc(SYSCTLFN_ARGS) { - struct eproc *eproc; - struct kinfo_proc2 *kproc2; - struct kinfo_proc *dp; + union { + struct kinfo_proc kproc; + struct kinfo_proc2 kproc2; + } *kbuf; struct proc *p, *next, *marker; - char *where, *dp2; + char *where, *dp; int type, op, arg, error; - u_int elem_size, elem_count; + u_int elem_size, kelem_size, elem_count; size_t buflen, needed; bool match, zombie, mmmbrains; if (namelen == 1 && name[0] == CTL_QUERY) return (sysctl_query(SYSCTLFN_CALL(rnode))); - dp = oldp; - dp2 = where = oldp; + dp = where = oldp; buflen = where != NULL ? *oldlenp : 0; error = 0; needed = 0; @@ -2180,7 +2180,8 @@ arg = name[1]; else arg = 0; /* Quell compiler warning */ - elem_size = elem_count = 0; /* Ditto */ + elem_count = 0; /* Ditto */ + kelem_size = elem_size = sizeof(kbuf->kproc); } else { if (namelen != 4) return (EINVAL); @@ -2188,17 +2189,12 @@ arg = name[1]; elem_size = name[2]; elem_count = name[3]; + kelem_size = sizeof(kbuf->kproc2); } sysctl_unlock(); - if (type == KERN_PROC) { - eproc = kmem_alloc(sizeof(*eproc), KM_SLEEP); - kproc2 = NULL; - } else { - eproc = NULL; - kproc2 = kmem_alloc(sizeof(*kproc2), KM_SLEEP); - } + kbuf = kmem_alloc(sizeof(*kbuf), KM_SLEEP); marker = kmem_alloc(sizeof(*marker), KM_SLEEP); marker->p_flag = PK_MARKER; @@ -2312,51 +2308,32 @@ LIST_INSERT_AFTER(p, marker, p_list); } - if (type == KERN_PROC) { - if (buflen >= sizeof(struct kinfo_proc)) { - fill_eproc(p, eproc, zombie); - mutex_exit(p->p_lock); - mutex_exit(proc_lock); - error = dcopyout(l, p, &dp->kp_proc, - sizeof(struct proc)); - mutex_enter(proc_lock); - if (error) { - goto bah; - } - error = dcopyout(l, eproc, &dp->kp_eproc, - sizeof(*eproc)); - if (error) { - goto bah; - } - dp++; - buflen -= sizeof(struct kinfo_proc); + if (buflen >= elem_size && + (type == KERN_PROC || elem_count > 0)) { + if (type == KERN_PROC) { + kbuf->kproc.kp_proc = *p; + fill_eproc(p, &kbuf->kproc.kp_eproc, zombie); } else { - mutex_exit(p->p_lock); - } - needed += sizeof(struct kinfo_proc); - } else { /* KERN_PROC2 */ - if (buflen >= elem_size && elem_count > 0) { - fill_kproc2(p, kproc2, zombie); - mutex_exit(p->p_lock); - mutex_exit(proc_lock); - /* - * Copy out elem_size, but not larger than - * the size of a struct kinfo_proc2. - */ - error = dcopyout(l, kproc2, dp2, - min(sizeof(*kproc2), elem_size)); - mutex_enter(proc_lock); - if (error) { - goto bah; - } - dp2 += elem_size; - buflen -= elem_size; + fill_kproc2(p, &kbuf->kproc2, zombie); elem_count--; - } else { - mutex_exit(p->p_lock); } - needed += elem_size; + mutex_exit(p->p_lock); + mutex_exit(proc_lock); + /* + * Copy out elem_size, but not larger than kelem_size + */ + error = dcopyout(l, kbuf, dp, + min(kelem_size, elem_size)); + mutex_enter(proc_lock); + if (error) { + goto bah; + } + dp += elem_size; + buflen -= elem_size; + } else { + mutex_exit(p->p_lock); } + needed += elem_size; /* * Release reference to process. @@ -2371,10 +2348,7 @@ mutex_exit(proc_lock); if (where != NULL) { - if (type == KERN_PROC) - *oldlenp = (char *)dp - where; - else - *oldlenp = dp2 - where; + *oldlenp = dp - where; if (needed > *oldlenp) { error = ENOMEM; goto out; @@ -2383,10 +2357,8 @@ needed += KERN_PROCSLOP; *oldlenp = needed; } - if (kproc2) - kmem_free(kproc2, sizeof(*kproc2)); - if (eproc) - kmem_free(eproc, sizeof(*eproc)); + if (kbuf) + kmem_free(kbuf, sizeof(*kbuf)); if (marker) kmem_free(marker, sizeof(*marker)); sysctl_relock(); @@ -2399,10 +2371,8 @@ cleanup: mutex_exit(proc_lock); out: - if (kproc2) - kmem_free(kproc2, sizeof(*kproc2)); - if (eproc) - kmem_free(eproc, sizeof(*eproc)); + if (kbuf) + kmem_free(kbuf, sizeof(*kbuf)); if (marker) kmem_free(marker, sizeof(*marker)); sysctl_relock();