diff --git a/sys/netgraph/ng_device.c b/sys/netgraph/ng_device.c --- a/sys/netgraph/ng_device.c +++ b/sys/netgraph/ng_device.c @@ -45,6 +45,8 @@ #include #include +#include +#include #include "ng_device.h" /* turn this on for verbose messages */ @@ -506,11 +508,20 @@ ngdread(cdev_t dev, struct uio *uio, int flag) { int ret = 0, amnt; - char buffer[uio->uio_resid+1]; + char *buffer; struct ngd_softc *sc = &ngd_softc; struct ngd_connection * connection = NULL; struct ngd_connection * tmp; + /* Cap the transfer to the queue size to avoid huge allocations and + * to prevent a user-controlled VLA from overflowing the kernel stack. */ + if (uio->uio_resid > NGD_QUEUE_SIZE) + return(EINVAL); + + buffer = kmalloc(NGD_QUEUE_SIZE + 1, M_DEVBUF, M_WAITOK); + if (buffer == NULL) + return(ENOMEM); + #ifdef NGD_DEBUG kprintf("%s()\n", __func__); #endif /* NGD_DEBUG */ @@ -522,6 +533,7 @@ } if(connection == NULL) { kprintf("%s(): connection still NULL, no dev found\n", __func__); + kfree(buffer, M_DEVBUF); return(-1); } @@ -538,10 +550,12 @@ goto error; } + kfree(buffer, M_DEVBUF); return(0); error: kprintf("%s(): uiomove returns error %d\n", __func__, ret); + kfree(buffer, M_DEVBUF); /* do error cleanup here */ return(ret); } @@ -559,12 +573,23 @@ int ret; int error = 0; struct mbuf *m; - char buffer[uio->uio_resid]; + char *buffer; int len = uio->uio_resid; struct ngd_softc *sc =& ngd_softc; struct ngd_connection * connection = NULL; struct ngd_connection * tmp; + /* Bound the transfer to a sane maximum so a user-controlled VLA cannot + * overflow the 16 KB kernel thread stack. */ + if (len <= 0) + return(0); + if ((size_t)len > IP_MAXPACKET) + return(EIO); + + buffer = kmalloc(len, M_DEVBUF, M_WAITOK); + if (buffer == NULL) + return(ENOMEM); + #ifdef NGD_DEBUG kprintf("%s()\n", __func__); #endif /* NGD_DEBUG */ @@ -577,17 +602,17 @@ if(connection == NULL) { kprintf("%s(): connection still NULL, no dev found\n", __func__); + kfree(buffer, M_DEVBUF); return(-1); } - if (len > 0) { - if ((ret = uiomove((caddr_t)buffer, len, uio)) != 0) - goto error; - } else - kprintf("%s(): len <= 0 : supposed to happen?!\n", __func__); + if ((ret = uiomove((caddr_t)buffer, len, uio)) != 0) + goto error; m = m_devget(buffer, len, 0, NULL); + kfree(buffer, M_DEVBUF); + NG_SEND_DATA_ONLY(error, connection->active_hook, m); return(0); @@ -595,6 +620,7 @@ error: /* do error cleanup here */ kprintf("%s(): uiomove returned err: %d\n", __func__, ret); + kfree(buffer, M_DEVBUF); return(ret); }