summaryrefslogtreecommitdiffstats
path: root/sys/kern/sys_generic.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-09-09 20:59:01 +0000
committerkib <kib@FreeBSD.org>2009-09-09 20:59:01 +0000
commit91e6a5b3cc44fe15d5746c5b0f8d4b970182c656 (patch)
treeecdcb4c945cc32ab7a293d1290a48abdaff024e2 /sys/kern/sys_generic.c
parent2f0e817202fd1926d9261102d1576c28d138e982 (diff)
downloadFreeBSD-src-91e6a5b3cc44fe15d5746c5b0f8d4b970182c656.zip
FreeBSD-src-91e6a5b3cc44fe15d5746c5b0f8d4b970182c656.tar.gz
kern_select(9) copies fd_set in and out of userspace in quantities of
longs. Since 32bit processes longs are 4 bytes, 64bit kernel may copy in or out 4 bytes more then the process expected. Calculate the amount of bytes to copy taking into account size of fd_set for the current process ABI. Diagnosed and tested by: Peter Jeremy <peterjeremy acm org> Reviewed by: jhb MFC after: 1 week
Diffstat (limited to 'sys/kern/sys_generic.c')
-rw-r--r--sys/kern/sys_generic.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index bd0f279..6831fe8 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -774,12 +774,13 @@ select(td, uap)
} else
tvp = NULL;
- return (kern_select(td, uap->nd, uap->in, uap->ou, uap->ex, tvp));
+ return (kern_select(td, uap->nd, uap->in, uap->ou, uap->ex, tvp,
+ NFDBITS));
}
int
kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
- fd_set *fd_ex, struct timeval *tvp)
+ fd_set *fd_ex, struct timeval *tvp, int abi_nfdbits)
{
struct filedesc *fdp;
/*
@@ -792,7 +793,7 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
fd_mask *ibits[3], *obits[3], *selbits, *sbp;
struct timeval atv, rtv, ttv;
int error, timo;
- u_int nbufbytes, ncpbytes, nfdbits;
+ u_int nbufbytes, ncpbytes, ncpubytes, nfdbits;
if (nd < 0)
return (EINVAL);
@@ -806,6 +807,7 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
*/
nfdbits = roundup(nd, NFDBITS);
ncpbytes = nfdbits / NBBY;
+ ncpubytes = roundup(nd, abi_nfdbits) / NBBY;
nbufbytes = 0;
if (fd_in != NULL)
nbufbytes += 2 * ncpbytes;
@@ -832,9 +834,11 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp; \
obits[x] = sbp; \
sbp += ncpbytes / sizeof *sbp; \
- error = copyin(name, ibits[x], ncpbytes); \
+ error = copyin(name, ibits[x], ncpubytes); \
if (error != 0) \
goto done; \
+ bzero((char *)ibits[x] + ncpubytes, \
+ ncpbytes - ncpubytes); \
} \
} while (0)
getbits(fd_in, 0);
@@ -888,7 +892,7 @@ done:
if (error == EWOULDBLOCK)
error = 0;
#define putbits(name, x) \
- if (name && (error2 = copyout(obits[x], name, ncpbytes))) \
+ if (name && (error2 = copyout(obits[x], name, ncpubytes))) \
error = error2;
if (error == 0) {
int error2;
OpenPOWER on IntegriCloud