USB: usblcd doesn't limit memory consumption during write

usblcd 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 despite resource limits.
Here's the fix taken from the modern skeleton driver.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by Oliver Neukum and committed by Greg Kroah-Hartman 5afeb104 fc0f8fc9

+18 -4
+18 -4
drivers/usb/misc/usblcd.c
··· 42 size_t bulk_in_size; /* the size of the receive buffer */ 43 __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ 44 __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ 45 - struct kref kref; 46 }; 47 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) 48 49 static struct usb_driver lcd_driver; 50 static DEFINE_MUTEX(usb_lcd_open_mutex); ··· 190 /* free up our allocated buffer */ 191 usb_buffer_free(urb->dev, urb->transfer_buffer_length, 192 urb->transfer_buffer, urb->transfer_dma); 193 } 194 195 static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos) 196 { 197 struct usb_lcd *dev; 198 - int retval = 0; 199 struct urb *urb = NULL; 200 char *buf = NULL; 201 ··· 206 if (count == 0) 207 goto exit; 208 209 /* create a urb, and a buffer for it, and copy the data to the urb */ 210 urb = usb_alloc_urb(0, GFP_KERNEL); 211 - if (!urb) 212 - return -ENOMEM; 213 214 buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); 215 if (!buf) { ··· 250 error: 251 usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); 252 usb_free_urb(urb); 253 return retval; 254 } 255 ··· 290 goto error; 291 } 292 kref_init(&dev->kref); 293 294 dev->udev = usb_get_dev(interface_to_usbdev(interface)); 295 dev->interface = interface;
··· 42 size_t bulk_in_size; /* the size of the receive buffer */ 43 __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ 44 __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ 45 + struct kref kref; 46 + struct semaphore limit_sem; /* to stop writes at full throttle from 47 + * using up all RAM */ 48 }; 49 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) 50 + 51 + #define USB_LCD_CONCURRENT_WRITES 5 52 53 static struct usb_driver lcd_driver; 54 static DEFINE_MUTEX(usb_lcd_open_mutex); ··· 186 /* free up our allocated buffer */ 187 usb_buffer_free(urb->dev, urb->transfer_buffer_length, 188 urb->transfer_buffer, urb->transfer_dma); 189 + up(&dev->limit_sem); 190 } 191 192 static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos) 193 { 194 struct usb_lcd *dev; 195 + int retval = 0, r; 196 struct urb *urb = NULL; 197 char *buf = NULL; 198 ··· 201 if (count == 0) 202 goto exit; 203 204 + r = down_interruptible(&dev->limit_sem); 205 + if (r < 0) 206 + return -EINTR; 207 + 208 /* create a urb, and a buffer for it, and copy the data to the urb */ 209 urb = usb_alloc_urb(0, GFP_KERNEL); 210 + if (!urb) { 211 + retval = -ENOMEM; 212 + goto err_no_buf; 213 + } 214 215 buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); 216 if (!buf) { ··· 239 error: 240 usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); 241 usb_free_urb(urb); 242 + err_no_buf: 243 + up(&dev->limit_sem); 244 return retval; 245 } 246 ··· 277 goto error; 278 } 279 kref_init(&dev->kref); 280 + sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); 281 282 dev->udev = usb_get_dev(interface_to_usbdev(interface)); 283 dev->interface = interface;