summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-05-17 08:27:18 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-05-17 08:27:18 +0000
commit178e33f536396c7a8cca18deeef31e0df0eea617 (patch)
tree5c583c82a6e8781d4abacd5f86a103ddbee1028b /sys/dev/usb
parente20653f06796e01992bd7852ba9cafa45368671a (diff)
Plug some gaping holes in the v4l2 ioctl interfaces that would leak kernel
memory to a local user. Found by Patrick Keshisian. Fix a potential integer overflow issue in related code while I'm there. ok mglocker@, deraadt@
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/uvideo.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c
index c6bf640a80c..c083bc33169 100644
--- a/sys/dev/usb/uvideo.c
+++ b/sys/dev/usb/uvideo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.c,v 1.184 2016/03/19 12:04:15 natano Exp $ */
+/* $OpenBSD: uvideo.c,v 1.185 2016/05/17 08:27:17 kettenis Exp $ */
/*
* Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
@@ -31,6 +31,7 @@
#include <sys/poll.h>
#include <sys/timeout.h>
#include <sys/kthread.h>
+#include <sys/stdint.h>
#include <uvm/uvm_extern.h>
@@ -74,6 +75,7 @@ struct uvideo_softc {
struct uvideo_mmap sc_mmap[UVIDEO_MAX_BUFFERS];
uint8_t *sc_mmap_buffer;
+ size_t sc_mmap_buffer_size;
q_mmap sc_mmap_q;
int sc_mmap_count;
int sc_mmap_cur;
@@ -1685,8 +1687,9 @@ uvideo_vs_free_frame(struct uvideo_softc *sc)
}
if (sc->sc_mmap_buffer != NULL) {
- free(sc->sc_mmap_buffer, M_DEVBUF, 0);
+ free(sc->sc_mmap_buffer, M_DEVBUF, sc->sc_mmap_buffer_size);
sc->sc_mmap_buffer = NULL;
+ sc->sc_mmap_buffer_size = 0;
}
while (!SIMPLEQ_EMPTY(&sc->sc_mmap_q))
@@ -3171,13 +3174,20 @@ uvideo_reqbufs(void *v, struct v4l2_requestbuffers *rb)
/* allocate the total mmap buffer */
buf_size = UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize);
+ if (buf_size >= SIZE_MAX / UVIDEO_MAX_BUFFERS) {
+ printf("%s: video frame size too large!\n", DEVNAME(sc));
+ sc->sc_mmap_count = 0;
+ return (EINVAL);
+ }
buf_size_total = sc->sc_mmap_count * buf_size;
buf_size_total = round_page(buf_size_total); /* page align buffer */
sc->sc_mmap_buffer = malloc(buf_size_total, M_DEVBUF, M_NOWAIT);
if (sc->sc_mmap_buffer == NULL) {
printf("%s: can't allocate mmap buffer!\n", DEVNAME(sc));
+ sc->sc_mmap_count = 0;
return (EINVAL);
}
+ sc->sc_mmap_buffer_size = buf_size_total;
DPRINTF(1, "%s: allocated %d bytes mmap buffer\n",
DEVNAME(sc), buf_size_total);
@@ -3216,7 +3226,8 @@ uvideo_querybuf(void *v, struct v4l2_buffer *qb)
struct uvideo_softc *sc = v;
if (qb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- qb->memory != V4L2_MEMORY_MMAP)
+ qb->memory != V4L2_MEMORY_MMAP ||
+ qb->index >= sc->sc_mmap_count)
return (EINVAL);
bcopy(&sc->sc_mmap[qb->index].v4l2_buf, qb,
@@ -3236,6 +3247,11 @@ uvideo_qbuf(void *v, struct v4l2_buffer *qb)
{
struct uvideo_softc *sc = v;
+ if (qb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ qb->memory != V4L2_MEMORY_MMAP ||
+ qb->index >= sc->sc_mmap_count)
+ return (EINVAL);
+
sc->sc_mmap[qb->index].v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
sc->sc_mmap[qb->index].v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
sc->sc_mmap[qb->index].v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
@@ -3253,6 +3269,10 @@ uvideo_dqbuf(void *v, struct v4l2_buffer *dqb)
struct uvideo_mmap *mmap;
int error;
+ if (dqb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ dqb->memory != V4L2_MEMORY_MMAP)
+ return (EINVAL);
+
if (SIMPLEQ_EMPTY(&sc->sc_mmap_q)) {
/* mmap queue is empty, block until first frame is queued */
error = tsleep(sc, 0, "vid_mmap", 10 * hz);
@@ -3570,6 +3590,9 @@ uvideo_mappage(void *v, off_t off, int prot)
struct uvideo_softc *sc = v;
caddr_t p;
+ if (off >= sc->sc_mmap_buffer_size)
+ return NULL;
+
if (!sc->sc_mmap_flag)
sc->sc_mmap_flag = 1;