From: Anton Arapov <aarapov@redhat.com> Subject: To: [RHEL5.1 PATCH] BZ276011: CVE-2007-3513 Locally triggerable memory consumption in usblcd Date: Sat, 08 Sep 2007 21:24:31 +0200 Bugzilla: 276011 Message-Id: <h8d4wtyn80.fsf@pepelac.englab.brq.redhat.com> Changelog: [usb] usblcd: Locally triggerable memory consumption BZ#276011: (tracking bug number) https://bugzilla.redhat.com/show_bug.cgi?id=276011 Description: [from upstream patch] sblcd currently has no way to limit memory consumption by fast writers. This is a security problem, as it allows users with write access to this device to drive the system into oom despiteds resource limits. Upstream status: commit# 5afeb104e7901168b21aad0437fb51dc620dfdd3 Test status: Patch has been tested for compilation an boot. Has not been tested with real HW, because of appropriate HW absence. :) Notice: BZ#247728 - original bug number. == diff -urpN linux-2.6.18.noarch.orig/drivers/usb/misc/usblcd.c linux-2.6.18.noarch/drivers/usb/misc/usblcd.c --- linux-2.6.18.noarch.orig/drivers/usb/misc/usblcd.c 2007-09-06 16:44:13.000000000 +0200 +++ linux-2.6.18.noarch/drivers/usb/misc/usblcd.c 2007-09-06 16:45:02.000000000 +0200 @@ -42,10 +42,14 @@ struct usb_lcd { size_t bulk_in_size; /* the size of the receive buffer */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ - struct kref kref; + struct kref kref; + struct semaphore limit_sem; /* to stop writes at full throttle from + * using up all RAM */ }; #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) +#define USB_LCD_CONCURRENT_WRITES 5 + static struct usb_driver lcd_driver; @@ -183,12 +187,13 @@ static void lcd_write_bulk_callback(stru /* free up our allocated buffer */ usb_buffer_free(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); + up(&dev->limit_sem); } static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos) { struct usb_lcd *dev; - int retval = 0; + int retval = 0, r; struct urb *urb = NULL; char *buf = NULL; @@ -197,11 +202,17 @@ static ssize_t lcd_write(struct file *fi /* verify that we actually have some data to write */ if (count == 0) goto exit; + + r = down_interruptible(&dev->limit_sem); + if (r < 0) + return -EINTR; /* create a urb, and a buffer for it, and copy the data to the urb */ urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; + if (!urb) { + retval = -ENOMEM; + goto err_no_buf; + } buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); if (!buf) { @@ -236,6 +247,8 @@ exit: error: usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); usb_free_urb(urb); +err_no_buf: + up(&dev->limit_sem); return retval; } @@ -274,6 +287,7 @@ static int lcd_probe(struct usb_interfac goto error; } kref_init(&dev->kref); + sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; -- Anton Arapov, <aarapov@redhat.com> Kernel Development, Red Hat GPG Key ID: 0x6FA8C812