aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/devio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r--drivers/usb/core/devio.c43
1 files changed, 16 insertions, 27 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 4016dae7433b..52747b6ac89a 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -134,42 +134,35 @@ enum snoop_when {
134#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) 134#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
135 135
136/* Limit on the total amount of memory we can allocate for transfers */ 136/* Limit on the total amount of memory we can allocate for transfers */
137static unsigned usbfs_memory_mb = 16; 137static u32 usbfs_memory_mb = 16;
138module_param(usbfs_memory_mb, uint, 0644); 138module_param(usbfs_memory_mb, uint, 0644);
139MODULE_PARM_DESC(usbfs_memory_mb, 139MODULE_PARM_DESC(usbfs_memory_mb,
140 "maximum MB allowed for usbfs buffers (0 = no limit)"); 140 "maximum MB allowed for usbfs buffers (0 = no limit)");
141 141
142/* Hard limit, necessary to avoid arithmetic overflow */ 142static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */
143#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000)
144
145static atomic_t usbfs_memory_usage; /* Total memory currently allocated */
146 143
147/* Check whether it's okay to allocate more memory for a transfer */ 144/* Check whether it's okay to allocate more memory for a transfer */
148static int usbfs_increase_memory_usage(unsigned amount) 145static int usbfs_increase_memory_usage(u64 amount)
149{ 146{
150 unsigned lim; 147 u64 lim;
151 148
152 /*
153 * Convert usbfs_memory_mb to bytes, avoiding overflows.
154 * 0 means use the hard limit (effectively unlimited).
155 */
156 lim = ACCESS_ONCE(usbfs_memory_mb); 149 lim = ACCESS_ONCE(usbfs_memory_mb);
157 if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) 150 lim <<= 20;
158 lim = USBFS_XFER_MAX;
159 else
160 lim <<= 20;
161 151
162 atomic_add(amount, &usbfs_memory_usage); 152 atomic64_add(amount, &usbfs_memory_usage);
163 if (atomic_read(&usbfs_memory_usage) <= lim) 153
164 return 0; 154 if (lim > 0 && atomic64_read(&usbfs_memory_usage) > lim) {
165 atomic_sub(amount, &usbfs_memory_usage); 155 atomic64_sub(amount, &usbfs_memory_usage);
166 return -ENOMEM; 156 return -ENOMEM;
157 }
158
159 return 0;
167} 160}
168 161
169/* Memory for a transfer is being deallocated */ 162/* Memory for a transfer is being deallocated */
170static void usbfs_decrease_memory_usage(unsigned amount) 163static void usbfs_decrease_memory_usage(u64 amount)
171{ 164{
172 atomic_sub(amount, &usbfs_memory_usage); 165 atomic64_sub(amount, &usbfs_memory_usage);
173} 166}
174 167
175static int connected(struct usb_dev_state *ps) 168static int connected(struct usb_dev_state *ps)
@@ -1191,7 +1184,7 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg)
1191 if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) 1184 if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
1192 return -EINVAL; 1185 return -EINVAL;
1193 len1 = bulk.len; 1186 len1 = bulk.len;
1194 if (len1 >= USBFS_XFER_MAX) 1187 if (len1 >= (INT_MAX - sizeof(struct urb)))
1195 return -EINVAL; 1188 return -EINVAL;
1196 ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); 1189 ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
1197 if (ret) 1190 if (ret)
@@ -1584,10 +1577,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
1584 return -EINVAL; 1577 return -EINVAL;
1585 } 1578 }
1586 1579
1587 if (uurb->buffer_length >= USBFS_XFER_MAX) {
1588 ret = -EINVAL;
1589 goto error;
1590 }
1591 if (uurb->buffer_length > 0 && 1580 if (uurb->buffer_length > 0 &&
1592 !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, 1581 !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
1593 uurb->buffer, uurb->buffer_length)) { 1582 uurb->buffer, uurb->buffer_length)) {