diff options
Diffstat (limited to 'drivers/usb/usbip')
-rw-r--r-- | drivers/usb/usbip/stub_rx.c | 51 | ||||
-rw-r--r-- | drivers/usb/usbip/stub_tx.c | 7 | ||||
-rw-r--r-- | drivers/usb/usbip/usbip_common.h | 1 | ||||
-rw-r--r-- | drivers/usb/usbip/vhci_sysfs.c | 25 |
4 files changed, 65 insertions, 19 deletions
diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 536e037f541f..493ac2928391 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c | |||
@@ -322,23 +322,34 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev, | |||
322 | return priv; | 322 | return priv; |
323 | } | 323 | } |
324 | 324 | ||
325 | static int get_pipe(struct stub_device *sdev, int epnum, int dir) | 325 | static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu) |
326 | { | 326 | { |
327 | struct usb_device *udev = sdev->udev; | 327 | struct usb_device *udev = sdev->udev; |
328 | struct usb_host_endpoint *ep; | 328 | struct usb_host_endpoint *ep; |
329 | struct usb_endpoint_descriptor *epd = NULL; | 329 | struct usb_endpoint_descriptor *epd = NULL; |
330 | int epnum = pdu->base.ep; | ||
331 | int dir = pdu->base.direction; | ||
332 | |||
333 | if (epnum < 0 || epnum > 15) | ||
334 | goto err_ret; | ||
330 | 335 | ||
331 | if (dir == USBIP_DIR_IN) | 336 | if (dir == USBIP_DIR_IN) |
332 | ep = udev->ep_in[epnum & 0x7f]; | 337 | ep = udev->ep_in[epnum & 0x7f]; |
333 | else | 338 | else |
334 | ep = udev->ep_out[epnum & 0x7f]; | 339 | ep = udev->ep_out[epnum & 0x7f]; |
335 | if (!ep) { | 340 | if (!ep) |
336 | dev_err(&sdev->udev->dev, "no such endpoint?, %d\n", | 341 | goto err_ret; |
337 | epnum); | ||
338 | BUG(); | ||
339 | } | ||
340 | 342 | ||
341 | epd = &ep->desc; | 343 | epd = &ep->desc; |
344 | |||
345 | /* validate transfer_buffer_length */ | ||
346 | if (pdu->u.cmd_submit.transfer_buffer_length > INT_MAX) { | ||
347 | dev_err(&sdev->udev->dev, | ||
348 | "CMD_SUBMIT: -EMSGSIZE transfer_buffer_length %d\n", | ||
349 | pdu->u.cmd_submit.transfer_buffer_length); | ||
350 | return -1; | ||
351 | } | ||
352 | |||
342 | if (usb_endpoint_xfer_control(epd)) { | 353 | if (usb_endpoint_xfer_control(epd)) { |
343 | if (dir == USBIP_DIR_OUT) | 354 | if (dir == USBIP_DIR_OUT) |
344 | return usb_sndctrlpipe(udev, epnum); | 355 | return usb_sndctrlpipe(udev, epnum); |
@@ -361,15 +372,31 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir) | |||
361 | } | 372 | } |
362 | 373 | ||
363 | if (usb_endpoint_xfer_isoc(epd)) { | 374 | if (usb_endpoint_xfer_isoc(epd)) { |
375 | /* validate packet size and number of packets */ | ||
376 | unsigned int maxp, packets, bytes; | ||
377 | |||
378 | maxp = usb_endpoint_maxp(epd); | ||
379 | maxp *= usb_endpoint_maxp_mult(epd); | ||
380 | bytes = pdu->u.cmd_submit.transfer_buffer_length; | ||
381 | packets = DIV_ROUND_UP(bytes, maxp); | ||
382 | |||
383 | if (pdu->u.cmd_submit.number_of_packets < 0 || | ||
384 | pdu->u.cmd_submit.number_of_packets > packets) { | ||
385 | dev_err(&sdev->udev->dev, | ||
386 | "CMD_SUBMIT: isoc invalid num packets %d\n", | ||
387 | pdu->u.cmd_submit.number_of_packets); | ||
388 | return -1; | ||
389 | } | ||
364 | if (dir == USBIP_DIR_OUT) | 390 | if (dir == USBIP_DIR_OUT) |
365 | return usb_sndisocpipe(udev, epnum); | 391 | return usb_sndisocpipe(udev, epnum); |
366 | else | 392 | else |
367 | return usb_rcvisocpipe(udev, epnum); | 393 | return usb_rcvisocpipe(udev, epnum); |
368 | } | 394 | } |
369 | 395 | ||
396 | err_ret: | ||
370 | /* NOT REACHED */ | 397 | /* NOT REACHED */ |
371 | dev_err(&sdev->udev->dev, "get pipe, epnum %d\n", epnum); | 398 | dev_err(&sdev->udev->dev, "CMD_SUBMIT: invalid epnum %d\n", epnum); |
372 | return 0; | 399 | return -1; |
373 | } | 400 | } |
374 | 401 | ||
375 | static void masking_bogus_flags(struct urb *urb) | 402 | static void masking_bogus_flags(struct urb *urb) |
@@ -433,7 +460,10 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, | |||
433 | struct stub_priv *priv; | 460 | struct stub_priv *priv; |
434 | struct usbip_device *ud = &sdev->ud; | 461 | struct usbip_device *ud = &sdev->ud; |
435 | struct usb_device *udev = sdev->udev; | 462 | struct usb_device *udev = sdev->udev; |
436 | int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction); | 463 | int pipe = get_pipe(sdev, pdu); |
464 | |||
465 | if (pipe == -1) | ||
466 | return; | ||
437 | 467 | ||
438 | priv = stub_priv_alloc(sdev, pdu); | 468 | priv = stub_priv_alloc(sdev, pdu); |
439 | if (!priv) | 469 | if (!priv) |
@@ -452,7 +482,8 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, | |||
452 | } | 482 | } |
453 | 483 | ||
454 | /* allocate urb transfer buffer, if needed */ | 484 | /* allocate urb transfer buffer, if needed */ |
455 | if (pdu->u.cmd_submit.transfer_buffer_length > 0) { | 485 | if (pdu->u.cmd_submit.transfer_buffer_length > 0 && |
486 | pdu->u.cmd_submit.transfer_buffer_length <= INT_MAX) { | ||
456 | priv->urb->transfer_buffer = | 487 | priv->urb->transfer_buffer = |
457 | kzalloc(pdu->u.cmd_submit.transfer_buffer_length, | 488 | kzalloc(pdu->u.cmd_submit.transfer_buffer_length, |
458 | GFP_KERNEL); | 489 | GFP_KERNEL); |
diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c index b18bce96c212..53172b1f6257 100644 --- a/drivers/usb/usbip/stub_tx.c +++ b/drivers/usb/usbip/stub_tx.c | |||
@@ -167,6 +167,13 @@ static int stub_send_ret_submit(struct stub_device *sdev) | |||
167 | memset(&pdu_header, 0, sizeof(pdu_header)); | 167 | memset(&pdu_header, 0, sizeof(pdu_header)); |
168 | memset(&msg, 0, sizeof(msg)); | 168 | memset(&msg, 0, sizeof(msg)); |
169 | 169 | ||
170 | if (urb->actual_length > 0 && !urb->transfer_buffer) { | ||
171 | dev_err(&sdev->udev->dev, | ||
172 | "urb: actual_length %d transfer_buffer null\n", | ||
173 | urb->actual_length); | ||
174 | return -1; | ||
175 | } | ||
176 | |||
170 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) | 177 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) |
171 | iovnum = 2 + urb->number_of_packets; | 178 | iovnum = 2 + urb->number_of_packets; |
172 | else | 179 | else |
diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index e5de35c8c505..473fb8a87289 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h | |||
@@ -256,6 +256,7 @@ struct usbip_device { | |||
256 | /* lock for status */ | 256 | /* lock for status */ |
257 | spinlock_t lock; | 257 | spinlock_t lock; |
258 | 258 | ||
259 | int sockfd; | ||
259 | struct socket *tcp_socket; | 260 | struct socket *tcp_socket; |
260 | 261 | ||
261 | struct task_struct *tcp_rx; | 262 | struct task_struct *tcp_rx; |
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index e78f7472cac4..091f76b7196d 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c | |||
@@ -17,15 +17,20 @@ | |||
17 | 17 | ||
18 | /* | 18 | /* |
19 | * output example: | 19 | * output example: |
20 | * hub port sta spd dev socket local_busid | 20 | * hub port sta spd dev sockfd local_busid |
21 | * hs 0000 004 000 00000000 c5a7bb80 1-2.3 | 21 | * hs 0000 004 000 00000000 3 1-2.3 |
22 | * ................................................ | 22 | * ................................................ |
23 | * ss 0008 004 000 00000000 d8cee980 2-3.4 | 23 | * ss 0008 004 000 00000000 4 2-3.4 |
24 | * ................................................ | 24 | * ................................................ |
25 | * | 25 | * |
26 | * IP address can be retrieved from a socket pointer address by looking | 26 | * Output includes socket fd instead of socket pointer address to avoid |
27 | * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a | 27 | * leaking kernel memory address in: |
28 | * port number and its peer IP address. | 28 | * /sys/devices/platform/vhci_hcd.0/status and in debug output. |
29 | * The socket pointer address is not used at the moment and it was made | ||
30 | * visible as a convenient way to find IP address from socket pointer | ||
31 | * address by looking up /proc/net/{tcp,tcp6}. As this opens a security | ||
32 | * hole, the change is made to use sockfd instead. | ||
33 | * | ||
29 | */ | 34 | */ |
30 | static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev) | 35 | static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev) |
31 | { | 36 | { |
@@ -39,8 +44,8 @@ static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vd | |||
39 | if (vdev->ud.status == VDEV_ST_USED) { | 44 | if (vdev->ud.status == VDEV_ST_USED) { |
40 | *out += sprintf(*out, "%03u %08x ", | 45 | *out += sprintf(*out, "%03u %08x ", |
41 | vdev->speed, vdev->devid); | 46 | vdev->speed, vdev->devid); |
42 | *out += sprintf(*out, "%16p %s", | 47 | *out += sprintf(*out, "%u %s", |
43 | vdev->ud.tcp_socket, | 48 | vdev->ud.sockfd, |
44 | dev_name(&vdev->udev->dev)); | 49 | dev_name(&vdev->udev->dev)); |
45 | 50 | ||
46 | } else { | 51 | } else { |
@@ -160,7 +165,8 @@ static ssize_t nports_show(struct device *dev, struct device_attribute *attr, | |||
160 | char *s = out; | 165 | char *s = out; |
161 | 166 | ||
162 | /* | 167 | /* |
163 | * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, thus the * 2. | 168 | * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, |
169 | * thus the * 2. | ||
164 | */ | 170 | */ |
165 | out += sprintf(out, "%d\n", VHCI_PORTS * vhci_num_controllers); | 171 | out += sprintf(out, "%d\n", VHCI_PORTS * vhci_num_controllers); |
166 | return out - s; | 172 | return out - s; |
@@ -366,6 +372,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, | |||
366 | 372 | ||
367 | vdev->devid = devid; | 373 | vdev->devid = devid; |
368 | vdev->speed = speed; | 374 | vdev->speed = speed; |
375 | vdev->ud.sockfd = sockfd; | ||
369 | vdev->ud.tcp_socket = socket; | 376 | vdev->ud.tcp_socket = socket; |
370 | vdev->ud.status = VDEV_ST_NOTASSIGNED; | 377 | vdev->ud.status = VDEV_ST_NOTASSIGNED; |
371 | 378 | ||