Fix some security bugs in the SVR4 emulator:

- Return NULL instead of returning memory outside of the stackgap
  in stackgap_alloc() (FreeBSD-SA-00:42.linux)
- Check for stackgap_alloc() returning NULL in svr4_emul_find(),
  and clean_pipe().
- Avoid integer overflow on large nfds argument in svr4_sys_poll()
- Reject negative nbytes argument in svr4_sys_getdents()
- Don't copy out past the end of the struct componentname
  pathname buffer in svr4_sys_resolvepath()
- Reject out-of-range signal numbers in svr4_sys_sigaction(),
  svr4_sys_signal(), and svr4_sys_kill().
- Don't malloc() user-specified lengths in show_ioc() and
  show_strbuf(), place arbitrary limits instead.
- Range-check lengths in si_listen(), ti_getinfo(), ti_bind(),
  svr4_do_putmsg(), svr4_do_getmsg(), svr4_stream_ti_ioctl().

Some fixes obtain from OpenBSD.
This commit is contained in:
Tim J. Robbins 2003-10-20 10:38:48 +00:00
parent fc9cfabba9
commit 78b73f3e05
6 changed files with 78 additions and 20 deletions

View file

@ -40,6 +40,8 @@ __FBSDID("$FreeBSD$");
#include <sys/poll.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/resource.h>
#include <sys/resourcevar.h>
#include <sys/sysproto.h>
@ -64,6 +66,11 @@ svr4_sys_poll(td, uap)
int idx = 0, cerr;
u_long siz;
mtx_assert(&Giant, MA_OWNED);
if (uap->nfds > td->td_proc->p_rlimit[RLIMIT_NOFILE].rlim_cur &&
uap->nfds > FD_SETSIZE)
return (EINVAL);
pa.fds = uap->fds;
pa.nfds = uap->nfds;
pa.timeout = uap->timeout;

View file

@ -444,6 +444,9 @@ svr4_sys_getdents(td, uap)
u_long *cookiebuf = NULL, *cookie;
int ncookies = 0, *retval = td->td_retval;
if (uap->nbytes < 0)
return (EINVAL);
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
return (error);
@ -1734,6 +1737,7 @@ svr4_sys_resolvepath(td, uap)
{
struct nameidata nd;
int error, *retval = td->td_retval;
unsigned int ncopy;
NDINIT(&nd, LOOKUP, NOFOLLOW | SAVENAME, UIO_USERSPACE,
uap->path, td);
@ -1741,12 +1745,11 @@ svr4_sys_resolvepath(td, uap)
if ((error = namei(&nd)) != 0)
return error;
if ((error = copyout(nd.ni_cnd.cn_pnbuf, uap->buf,
uap->bufsiz)) != 0)
ncopy = min(uap->bufsiz, strlen(nd.ni_cnd.cn_pnbuf) + 1);
if ((error = copyout(nd.ni_cnd.cn_pnbuf, uap->buf, ncopy)) != 0)
goto bad;
*retval = strlen(nd.ni_cnd.cn_pnbuf) < uap->bufsiz ?
strlen(nd.ni_cnd.cn_pnbuf) + 1 : uap->bufsiz;
*retval = ncopy;
bad:
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_vp);

View file

@ -269,6 +269,9 @@ svr4_sys_sigaction(td, uap)
struct sigaction *nbsap;
int error;
if (uap->signum < 0 || uap->signum >= SVR4_NSIG)
return (EINVAL);
DPRINTF(("@@@ svr4_sys_sigaction(%d, %d, %d)\n", td->td_proc->p_pid,
uap->signum,
SVR4_SVR42BSD_SIG(uap->signum)));
@ -337,9 +340,14 @@ svr4_sys_signal(td, uap)
p = td->td_proc;
DPRINTF(("@@@ svr4_sys_signal(%d)\n", p->p_pid));
signum = SVR4_SVR42BSD_SIG(SVR4_SIGNO(uap->signum));
if (signum <= 0 || signum > SVR4_NSIG)
signum = SVR4_SIGNO(uap->signum);
if (signum < 0 || signum >= SVR4_NSIG) {
if (SVR4_SIGCALL(uap->signum) == SVR4_SIGNAL_MASK ||
SVR4_SIGCALL(uap->signum) == SVR4_SIGDEFER_MASK)
td->td_retval[0] = (int)SVR4_SIG_ERR;
return (EINVAL);
}
signum = SVR4_SVR42BSD_SIG(signum);
switch (SVR4_SIGCALL(uap->signum)) {
case SVR4_SIGDEFER_MASK:
@ -509,6 +517,8 @@ svr4_sys_kill(td, uap)
{
struct kill_args ka;
if (uap->signum < 0 || uap->signum >= SVR4_NSIG)
return (EINVAL);
ka.pid = uap->pid;
ka.signum = SVR4_SVR42BSD_SIG(uap->signum);
return kill(td, &ka);

View file

@ -406,22 +406,32 @@ show_ioc(str, ioc)
const char *str;
struct svr4_strioctl *ioc;
{
u_char *ptr = (u_char *) malloc(ioc->len, M_TEMP, M_WAITOK);
u_char *ptr = NULL;
int len;
int error;
len = ioc->len;
if (len > 1024)
len = 1024;
if (len > 0) {
ptr = (u_char *) malloc(len, M_TEMP, M_WAITOK);
if ((error = copyin(ioc->buf, ptr, len)) != 0) {
free((char *) ptr, M_TEMP);
return error;
}
}
uprintf("%s cmd = %ld, timeout = %d, len = %d, buf = %p { ",
str, ioc->cmd, ioc->timeout, ioc->len, ioc->buf);
if ((error = copyin(ioc->buf, ptr, ioc->len)) != 0) {
free((char *) ptr, M_TEMP);
return error;
}
bufprint(ptr, ioc->len);
if (ptr != NULL)
bufprint(ptr, len);
uprintf("}\n");
free((char *) ptr, M_TEMP);
if (ptr != NULL)
free((char *) ptr, M_TEMP);
return 0;
}
@ -435,6 +445,9 @@ show_strbuf(str)
int maxlen = str->maxlen;
int len = str->len;
if (maxlen > 8192)
maxlen = 8192;
if (maxlen < 0)
maxlen = 0;
@ -521,7 +534,8 @@ clean_pipe(td, path)
size_t l = strlen(path) + 1;
void *tpath;
tpath = stackgap_alloc(&sg, l);
if ((tpath = stackgap_alloc(&sg, l)) == NULL)
return ENAMETOOLONG;
la.ub = stackgap_alloc(&sg, sizeof(struct stat));
if ((error = copyout(path, tpath, l)) != 0)
@ -760,6 +774,9 @@ si_listen(fp, fd, ioc, td)
if (st == NULL)
return EINVAL;
if (ioc->len < 0 || ioc->len > sizeof(lst))
return EINVAL;
if ((error = copyin(ioc->buf, &lst, ioc->len)) != 0)
return error;
@ -961,6 +978,9 @@ ti_getinfo(fp, fd, ioc, td)
memset(&info, 0, sizeof(info));
if (ioc->len < 0 || ioc->len > sizeof(info))
return EINVAL;
if ((error = copyin(ioc->buf, &info, ioc->len)) != 0)
return error;
@ -1009,6 +1029,9 @@ ti_bind(fp, fd, ioc, td)
return EINVAL;
}
if (ioc->len < 0 || ioc->len > sizeof(bnd))
return EINVAL;
if ((error = copyin(ioc->buf, &bnd, ioc->len)) != 0)
return error;
@ -1137,7 +1160,7 @@ svr4_stream_ti_ioctl(fp, td, retval, fd, cmd, dat)
struct sockaddr_in sain;
struct sockaddr_un saun;
struct svr4_strmcmd sc;
int sasize;
int sasize, oldsasize;
caddr_t sg;
int *lenp;
@ -1225,11 +1248,16 @@ svr4_stream_ti_ioctl(fp, td, retval, fd, cmd, dat)
return error;
}
oldsasize = sasize;
if ((error = copyin(lenp, &sasize, sizeof(*lenp))) != 0) {
DPRINTF(("ti_ioctl: error copying in socket size\n"));
return error;
}
if (sasize < 0 || sasize > oldsasize)
return EINVAL;
switch (st->s_family) {
case AF_INET:
sockaddr_to_netaddr_in(&sc, &sain);
@ -1794,7 +1822,7 @@ svr4_do_putmsg(td, uap, fp)
return EINVAL;
}
if (ctl.len > sizeof(sc)) {
if (ctl.len < 0 || ctl.len > sizeof(sc)) {
DPRINTF(("putmsg: Bad control size %d != %d\n", ctl.len,
sizeof(struct svr4_strmcmd)));
return EINVAL;
@ -1962,6 +1990,8 @@ svr4_do_getmsg(td, uap, fp)
if (uap->ctl != NULL) {
if ((error = copyin(uap->ctl, &ctl, sizeof(ctl))) != 0)
return error;
if (ctl.len < 0)
return EINVAL;
}
else {
ctl.len = -1;
@ -2147,6 +2177,9 @@ svr4_do_getmsg(td, uap, fp)
if (ctl.maxlen > 36 && ctl.len < 36)
ctl.len = 36;
if (ctl.len > sizeof(sc))
ctl.len = sizeof(sc);
if ((error = copyin(ctl.buf, &sc, ctl.len)) != 0)
return error;

View file

@ -364,8 +364,10 @@ svr4_emul_find(td, sgp, prefix, path, pbuf, cflag)
*pbuf = buf;
else {
sz = &ptr[len] - buf;
*pbuf = stackgap_alloc(sgp, sz + 1);
error = copyout(buf, *pbuf, sz);
if ((*pbuf = stackgap_alloc(sgp, sz + 1)) != NULL)
error = copyout(buf, *pbuf, sz);
else
error = ENAMETOOLONG;
free(buf, M_TEMP);
}

View file

@ -63,7 +63,10 @@ stackgap_alloc(sgp, sz)
size_t sz;
{
void *p = (void *) *sgp;
*sgp += ALIGN(sz);
sz = ALIGN(sz);
if (*sgp + sz > (caddr_t)(PS_STRINGS - szsigcode))
return NULL;
*sgp += sz;
return p;
}