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
This commit is contained in:
parent
8f63187ec1
commit
b55ef216fe
@ -589,7 +589,8 @@ freebsd32_select(struct thread *td, struct freebsd32_select_args *uap)
|
||||
* XXX big-endian needs to convert the fd_sets too.
|
||||
* XXX Do pointers need PTRIN()?
|
||||
*/
|
||||
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,
|
||||
sizeof(int32_t) * 8));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -522,7 +522,7 @@ linux_select(struct thread *td, struct linux_select_args *args)
|
||||
tvp = NULL;
|
||||
|
||||
error = kern_select(td, args->nfds, args->readfds, args->writefds,
|
||||
args->exceptfds, tvp);
|
||||
args->exceptfds, tvp, sizeof(l_int) * 8);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(select))
|
||||
|
@ -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 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
|
||||
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;
|
||||
|
@ -170,7 +170,7 @@ int kern_sched_rr_get_interval(struct thread *td, pid_t pid,
|
||||
int kern_semctl(struct thread *td, int semid, int semnum, int cmd,
|
||||
union semun *arg, register_t *rval);
|
||||
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);
|
||||
int kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
struct uio *hdr_uio, struct uio *trl_uio, int compat);
|
||||
int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
|
||||
|
Loading…
Reference in New Issue
Block a user