diff options
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r-- | drivers/usb/core/devio.c | 43 |
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 */ |
137 | static unsigned usbfs_memory_mb = 16; | 137 | static u32 usbfs_memory_mb = 16; |
138 | module_param(usbfs_memory_mb, uint, 0644); | 138 | module_param(usbfs_memory_mb, uint, 0644); |
139 | MODULE_PARM_DESC(usbfs_memory_mb, | 139 | MODULE_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 */ | 142 | static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */ |
143 | #define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) | ||
144 | |||
145 | static 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 */ |
148 | static int usbfs_increase_memory_usage(unsigned amount) | 145 | static 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 */ |
170 | static void usbfs_decrease_memory_usage(unsigned amount) | 163 | static 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 | ||
175 | static int connected(struct usb_dev_state *ps) | 168 | static 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)) { |