aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacques Vidrine <nectar@FreeBSD.org>2003-10-03 13:02:50 +0000
committerJacques Vidrine <nectar@FreeBSD.org>2003-10-03 13:02:50 +0000
commitebdea8551c84be312711a2eccf5852298d35b7d3 (patch)
tree2eba4ce9fc67e831345925e748ff6bd8458441f0
parent94d7dea5781a1187359d28940745fbe7d12412e2 (diff)
downloadsrc-ebdea8551c84be312711a2eccf5852298d35b7d3.tar.gz
src-ebdea8551c84be312711a2eccf5852298d35b7d3.zip
MFC procfs_dbregs.c 1.23, procfs_fpregs.c 1.29, procfs_regs.c 1.28,
pseudofs_vnops.c 1.42, kern_subr.c 1.77, uio.h 1.28: Correct several integer underflows/overflows in procfs and linprocfs.
Notes
Notes: svn path=/releng/5.0/; revision=120688
-rw-r--r--UPDATING3
-rw-r--r--sys/conf/newvers.sh2
-rw-r--r--sys/fs/procfs/procfs_dbregs.c18
-rw-r--r--sys/fs/procfs/procfs_fpregs.c18
-rw-r--r--sys/fs/procfs/procfs_regs.c18
-rw-r--r--sys/fs/pseudofs/pseudofs_vnops.c32
-rw-r--r--sys/kern/kern_subr.c23
-rw-r--r--sys/sys/uio.h1
8 files changed, 54 insertions, 61 deletions
diff --git a/UPDATING b/UPDATING
index 536b2bc54d36..480cb6fc451a 100644
--- a/UPDATING
+++ b/UPDATING
@@ -17,6 +17,9 @@ minimal number of processes, if possible, for that patch. For those
updates that don't have an advisory, or to be safe, you can do a full
build and install as described in the COMMON ITEMS section.
+20031003: p17 FreeBSD-SA-03:17.procfs
+ Correct integer underflows/overflows in procfs(5) and linprocfs(5).
+
20030924: p16 FreeBSD-SA-03:14.arp
Updated fix for arplookup bug.
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index 8c31046eda37..a696e7efef2a 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -36,7 +36,7 @@
TYPE="FreeBSD"
REVISION="5.0"
-BRANCH="RELEASE-p16"
+BRANCH="RELEASE-p17"
RELEASE="${REVISION}-${BRANCH}"
VERSION="${TYPE} ${RELEASE}"
diff --git a/sys/fs/procfs/procfs_dbregs.c b/sys/fs/procfs/procfs_dbregs.c
index 442521c6ac2a..78c4038248aa 100644
--- a/sys/fs/procfs/procfs_dbregs.c
+++ b/sys/fs/procfs/procfs_dbregs.c
@@ -65,30 +65,18 @@ procfs_doprocdbregs(PFS_FILL_ARGS)
{
int error;
struct dbreg r;
- char *kv;
- int kl;
PROC_LOCK(p);
if (p_candebug(td, p) != 0) {
PROC_UNLOCK(p);
return (EPERM);
}
- kl = sizeof(r);
- kv = (char *) &r;
-
- kv += uio->uio_offset;
- kl -= uio->uio_offset;
- if (kl > uio->uio_resid)
- kl = uio->uio_resid;
_PHOLD(p);
- if (kl < 0)
- error = EINVAL;
- else
- /* XXXKSE: */
- error = proc_read_dbregs(FIRST_THREAD_IN_PROC(p), &r);
+ /* XXXKSE: */
+ error = proc_read_dbregs(FIRST_THREAD_IN_PROC(p), &r);
if (error == 0)
- error = uiomove(kv, kl, uio);
+ error = uiomove_frombuf(&r, sizeof(r), uio);
if (error == 0 && uio->uio_rw == UIO_WRITE) {
if (!P_SHOULDSTOP(p)) /* XXXKSE should be P_TRACED? */
error = EBUSY;
diff --git a/sys/fs/procfs/procfs_fpregs.c b/sys/fs/procfs/procfs_fpregs.c
index f1401f37345f..abff67de4cad 100644
--- a/sys/fs/procfs/procfs_fpregs.c
+++ b/sys/fs/procfs/procfs_fpregs.c
@@ -59,30 +59,18 @@ procfs_doprocfpregs(PFS_FILL_ARGS)
{
int error;
struct fpreg r;
- char *kv;
- int kl;
PROC_LOCK(p);
if (p_candebug(td, p)) {
PROC_UNLOCK(p);
return (EPERM);
}
- kl = sizeof(r);
- kv = (char *) &r;
-
- kv += uio->uio_offset;
- kl -= uio->uio_offset;
- if (kl > uio->uio_resid)
- kl = uio->uio_resid;
_PHOLD(p);
- if (kl < 0)
- error = EINVAL;
- else
- /* XXXKSE: */
- error = proc_read_fpregs(FIRST_THREAD_IN_PROC(p), &r);
+ /* XXXKSE: */
+ error = proc_read_fpregs(FIRST_THREAD_IN_PROC(p), &r);
if (error == 0)
- error = uiomove(kv, kl, uio);
+ error = uiomove_frombuf(&r, sizeof(r), uio);
if (error == 0 && uio->uio_rw == UIO_WRITE) {
if (!P_SHOULDSTOP(p))
error = EBUSY;
diff --git a/sys/fs/procfs/procfs_regs.c b/sys/fs/procfs/procfs_regs.c
index 6cefe7ed9440..1e6ece4de9fc 100644
--- a/sys/fs/procfs/procfs_regs.c
+++ b/sys/fs/procfs/procfs_regs.c
@@ -59,31 +59,19 @@ procfs_doprocregs(PFS_FILL_ARGS)
{
int error;
struct reg r;
- char *kv;
- int kl;
PROC_LOCK(p);
if (p_candebug(td, p)) {
PROC_UNLOCK(p);
return (EPERM);
}
- kl = sizeof(r);
- kv = (char *) &r;
-
- kv += uio->uio_offset;
- kl -= uio->uio_offset;
- if (kl > uio->uio_resid)
- kl = uio->uio_resid;
_PHOLD(p);
PROC_UNLOCK(p);
- if (kl < 0)
- error = EINVAL;
- else
- /* XXXKSE: */
- error = proc_read_regs(FIRST_THREAD_IN_PROC(p), &r);
+ /* XXXKSE: */
+ error = proc_read_regs(FIRST_THREAD_IN_PROC(p), &r);
if (error == 0)
- error = uiomove(kv, kl, uio);
+ error = uiomove_frombuf(&r, sizeof(r), uio);
PROC_LOCK(p);
if (error == 0 && uio->uio_rw == UIO_WRITE) {
if (!P_SHOULDSTOP(p))
diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c
index b797aeb408f0..f949202a027c 100644
--- a/sys/fs/pseudofs/pseudofs_vnops.c
+++ b/sys/fs/pseudofs/pseudofs_vnops.c
@@ -34,6 +34,7 @@
#include <sys/ctype.h>
#include <sys/dirent.h>
#include <sys/fcntl.h>
+#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mount.h>
#include <sys/mutex.h>
@@ -472,8 +473,8 @@ pfs_read(struct vop_read_args *va)
struct uio *uio = va->a_uio;
struct proc *proc = NULL;
struct sbuf *sb = NULL;
- char *ps;
- int error, xlen;
+ int error;
+ unsigned int buflen, offset, resid;
PFS_TRACE((pn->pn_name));
@@ -508,7 +509,16 @@ pfs_read(struct vop_read_args *va)
PFS_RETURN (error);
}
- sb = sbuf_new(sb, NULL, uio->uio_offset + uio->uio_resid, 0);
+ /* Beaucoup sanity checks so we don't ask for bogus allocation. */
+ if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
+ (offset = uio->uio_offset) != uio->uio_offset ||
+ (resid = uio->uio_resid) != uio->uio_resid ||
+ (buflen = offset + resid) < offset || buflen > INT_MAX) {
+ if (proc != NULL)
+ PRELE(proc);
+ PFS_RETURN (EINVAL);
+ }
+ sb = sbuf_new(sb, NULL, buflen, 0);
if (sb == NULL) {
if (proc != NULL)
PRELE(proc);
@@ -525,12 +535,8 @@ pfs_read(struct vop_read_args *va)
PFS_RETURN (error);
}
- /* XXX we should possibly detect and handle overflows */
sbuf_finish(sb);
- ps = sbuf_data(sb) + uio->uio_offset;
- xlen = sbuf_len(sb) - uio->uio_offset;
- xlen = imin(xlen, uio->uio_resid);
- error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
+ error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
sbuf_delete(sb);
PFS_RETURN (error);
}
@@ -676,9 +682,9 @@ pfs_readlink(struct vop_readlink_args *va)
struct pfs_node *pn = pvd->pvd_pn;
struct uio *uio = va->a_uio;
struct proc *proc = NULL;
- char buf[MAXPATHLEN], *ps;
+ char buf[MAXPATHLEN];
struct sbuf sb;
- int error, xlen;
+ int error;
PFS_TRACE((pn->pn_name));
@@ -708,12 +714,8 @@ pfs_readlink(struct vop_readlink_args *va)
PFS_RETURN (error);
}
- /* XXX we should detect and handle overflows */
sbuf_finish(&sb);
- ps = sbuf_data(&sb) + uio->uio_offset;
- xlen = sbuf_len(&sb) - uio->uio_offset;
- xlen = imin(xlen, uio->uio_resid);
- error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
+ error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
sbuf_delete(&sb);
PFS_RETURN (error);
}
diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c
index 2df1a130a5b2..90cc942b0ce5 100644
--- a/sys/kern/kern_subr.c
+++ b/sys/kern/kern_subr.c
@@ -45,6 +45,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
+#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
@@ -210,6 +211,28 @@ out:
return (error);
}
+/*
+ * Wrapper for uiomove() that validates the arguments against a known-good
+ * kernel buffer. Currently, uiomove accepts a signed (n) argument, which
+ * is almost definitely a bad thing, so we catch that here as well. We
+ * return a runtime failure, but it might be desirable to generate a runtime
+ * assertion failure instead.
+ */
+int
+uiomove_frombuf(void *buf, int buflen, struct uio *uio)
+{
+ unsigned int offset, n;
+
+ if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
+ (offset = uio->uio_offset) != uio->uio_offset)
+ return (EINVAL);
+ if (buflen <= 0 || offset >= buflen)
+ return (0);
+ if ((n = buflen - offset) > INT_MAX)
+ return (EINVAL);
+ return (uiomove((char *)buf + offset, n, uio));
+}
+
#if defined(ENABLE_VFS_IOOPT) || defined(ZERO_COPY_SOCKETS)
/*
* Experimental support for zero-copy I/O
diff --git a/sys/sys/uio.h b/sys/sys/uio.h
index 8e4fd6f6a52c..5edd58130e40 100644
--- a/sys/sys/uio.h
+++ b/sys/sys/uio.h
@@ -99,6 +99,7 @@ struct vm_object;
void uio_yield(void);
int uiomove(caddr_t, int, struct uio *);
+int uiomove_frombuf(void *buf, int buflen, struct uio *uio);
int uiomoveco(caddr_t, int, struct uio *, struct vm_object *, int);
int uioread(int, struct uio *, struct vm_object *, int *);
int copyinfrom(const void *src, void *dst, size_t len, int seg);