NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/48308: User can crash machine using a USB webcam
The following reply was made to PR kern/48308; it has been noted by GNATS.
From: Mihai Chelaru <mihai.chelaru%ngnetworks.ro@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc: dtyson%anduin.org.uk@localhost
Subject: Re: kern/48308: User can crash machine using a USB webcam
Date: Mon, 04 Nov 2013 21:42:39 +0200
This is a multi-part message in MIME format.
--------------090805000104090603000906
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Hi,
Probably it works in 6.1 because release kernels are not compiled with
options DIAGNOSTIC, so they don't trigger that assert. I use the
attached patch for some time without any problems. It should fix your
issue too.
--
Mihai
--------------090805000104090603000906
Content-Type: text/plain; charset=us-ascii;
name="usb_mem.c.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="usb_mem.c.diff"
Index: sys/dev/usb/usb_mem.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usb_mem.c,v
retrieving revision 1.63
diff -u -p -r1.63 usb_mem.c
--- sys/dev/usb/usb_mem.c 15 Sep 2013 15:47:27 -0000 1.63
+++ sys/dev/usb/usb_mem.c 4 Nov 2013 19:23:44 -0000
@@ -44,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: usb_mem.c,v
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
+#include <sys/pool.h>
#include <sys/queue.h>
#include <sys/device.h> /* for usbdivar.h */
#include <sys/bus.h>
@@ -81,6 +82,8 @@ struct usb_frag_dma {
LIST_ENTRY(usb_frag_dma) next;
};
+pool_cache_t dma_block_pool, dma_sseg_pool;
+
Static usbd_status usb_block_allocmem(bus_dma_tag_t, size_t, size_t,
usb_dma_block_t **, bool);
Static void usb_block_freemem(usb_dma_block_t *);
@@ -108,6 +111,21 @@ usb_mem_init(void)
{
mutex_init(&usb_blk_lock, MUTEX_DEFAULT, IPL_NONE);
+
+ dma_block_pool = pool_cache_init(sizeof(usb_dma_block_t), 0, 0, 0,
+ "udmablock", NULL, IPL_VM, NULL, NULL, NULL);
+ if (dma_block_pool == NULL)
+ panic("dma_block_pool");
+ pool_cache_sethiwat(dma_block_pool, 50);
+ pool_cache_setlowat(dma_block_pool, 20);
+
+ dma_sseg_pool = pool_cache_init(sizeof(bus_dma_segment_t), 0, 0, 0,
+ "udmasseg", NULL, IPL_VM, NULL, NULL, NULL);
+ if (dma_sseg_pool == NULL)
+ panic("dma_sseg_pool");
+ pool_cache_sethiwat(dma_sseg_pool, 50);
+ pool_cache_setlowat(dma_sseg_pool, 20);
+
return 0;
}
@@ -151,17 +169,11 @@ usb_block_allocmem(bus_dma_tag_t tag, si
}
}
-#ifdef DIAGNOSTIC
- if (cpu_intr_p()) {
- printf("usb_block_allocmem: in interrupt context, failed\n");
- return (USBD_NOMEM);
- }
-#endif
-
DPRINTFN(6, ("usb_block_allocmem: no free\n"));
- b = kmem_zalloc(sizeof *b, KM_SLEEP);
+ b = pool_cache_get(dma_block_pool, PR_WAITOK);
if (b == NULL)
return (USBD_NOMEM);
+ memset(b, 0, sizeof *b);
b->tag = tag;
b->size = size;
@@ -173,11 +185,15 @@ usb_block_allocmem(bus_dma_tag_t tag, si
else
b->nsegs = (size + (PAGE_SIZE-1)) / PAGE_SIZE;
- b->segs = kmem_alloc(b->nsegs * sizeof(*b->segs), KM_SLEEP);
+ if (b->nsegs == 1)
+ b->segs = pool_cache_get(dma_sseg_pool, PR_WAITOK);
+ else
+ b->segs = kmem_intr_alloc(b->nsegs *sizeof(*b->segs), KM_SLEEP);
if (b->segs == NULL) {
- kmem_free(b, sizeof *b);
+ pool_cache_put(dma_block_pool, b);
return USBD_NOMEM;
}
+ memset(b->segs, 0, b->nsegs * sizeof(*b->segs));
b->nsegs_alloc = b->nsegs;
error = bus_dmamem_alloc(tag, b->size, align, 0,
@@ -215,8 +231,11 @@ usb_block_allocmem(bus_dma_tag_t tag, si
free1:
bus_dmamem_free(tag, b->segs, b->nsegs);
free0:
- kmem_free(b->segs, b->nsegs_alloc * sizeof(*b->segs));
- kmem_free(b, sizeof *b);
+ if (__predict_true(b->nsegs_alloc == 1))
+ pool_cache_put(dma_sseg_pool, b->segs);
+ else
+ kmem_intr_free(b->segs, b->nsegs_alloc * sizeof(*b->segs));
+ pool_cache_put(dma_block_pool, b);
return (USBD_NOMEM);
}
@@ -234,8 +253,11 @@ usb_block_real_freemem(usb_dma_block_t *
bus_dmamap_destroy(b->tag, b->map);
bus_dmamem_unmap(b->tag, b->kaddr, b->size);
bus_dmamem_free(b->tag, b->segs, b->nsegs);
- kmem_free(b->segs, b->nsegs_alloc * sizeof(*b->segs));
- kmem_free(b, sizeof *b);
+ if (__predict_true(b->nsegs_alloc == 1))
+ pool_cache_put(dma_sseg_pool, b->segs);
+ else
+ kmem_intr_free(b->segs, b->nsegs_alloc * sizeof(*b->segs));
+ pool_cache_put(dma_block_pool, b);
}
#endif
@@ -322,7 +344,7 @@ usb_allocmem_flags(usbd_bus_handle bus,
if (f == NULL) {
DPRINTFN(1, ("usb_allocmem: adding fragments\n"));
err = usb_block_allocmem(tag, USB_MEM_BLOCK, USB_MEM_SMALL, &b,
- false);
+ 0);
if (err) {
mutex_exit(&usb_blk_lock);
return (err);
@@ -438,21 +460,22 @@ usb_reserve_allocm(struct usb_dma_reserv
if (rs->vaddr == 0 || size > USB_MEM_RESERVE)
return USBD_NOMEM;
- dma->block = kmem_zalloc(sizeof *dma->block, KM_SLEEP);
+ dma->block = pool_cache_get(dma_block_pool, PR_WAITOK);
if (dma->block == NULL) {
aprint_error_dev(rs->dv, "%s: failed allocating dma block",
__func__);
goto out0;
}
+ memset(dma->block, 0, sizeof(*dma->block));
- dma->block->nsegs = 1;
- dma->block->segs = kmem_alloc(dma->block->nsegs *
- sizeof(*dma->block->segs), KM_SLEEP);
+ dma->block->nsegs = dma->block->nsegs_alloc = 1;
+ dma->block->segs = pool_cache_get(dma_sseg_pool, PR_WAITOK);
if (dma->block->segs == NULL) {
aprint_error_dev(rs->dv, "%s: failed allocating 1 dma segment",
__func__);
goto out1;
}
+ memset(dma->block->segs, 0, sizeof(*dma->block->segs)); /* nsegs = 1 */
error = extent_alloc(rs->extent, size, PAGE_SIZE, 0,
EX_NOWAIT, &start);
@@ -475,10 +498,9 @@ usb_reserve_allocm(struct usb_dma_reserv
return USBD_NORMAL_COMPLETION;
out2:
- kmem_free(dma->block->segs, dma->block->nsegs *
- sizeof(*dma->block->segs));
+ pool_cache_put(dma_sseg_pool, dma->block->segs);
out1:
- kmem_free(dma->block, sizeof *dma->block);
+ pool_cache_put(dma_block_pool, dma->block);
out0:
return USBD_NOMEM;
}
@@ -489,9 +511,12 @@ usb_reserve_freem(struct usb_dma_reserve
extent_free(rs->extent,
(u_long)(rs->paddr + dma->offs), dma->block->size, 0);
- kmem_free(dma->block->segs, dma->block->nsegs *
- sizeof(*dma->block->segs));
- kmem_free(dma->block, sizeof *dma->block);
+ if (__predict_true(dma->block->nsegs_alloc == 1))
+ pool_cache_put(dma_sseg_pool, dma->block->segs);
+ else
+ kmem_intr_free(dma->block->segs, dma->block->nsegs *
+ sizeof(*dma->block->segs));
+ pool_cache_put(dma_block_pool, dma->block);
}
int
--------------090805000104090603000906--
Home |
Main Index |
Thread Index |
Old Index