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