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();