diff options
Diffstat (limited to 'drivers/usb/usbip/stub_rx.c')
| -rw-r--r-- | drivers/usb/usbip/stub_rx.c | 47 | 
1 files changed, 33 insertions, 14 deletions
| diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 536e037f541f..6c5a59313999 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -211,9 +211,6 @@ static int stub_recv_cmd_unlink(struct stub_device *sdev,  		if (priv->seqnum != pdu->u.cmd_unlink.seqnum)  			continue; -		dev_info(&priv->urb->dev->dev, "unlink urb %p\n", -			 priv->urb); -  		/*  		 * This matched urb is not completed yet (i.e., be in  		 * flight in usb hcd hardware/driver). Now we are @@ -252,8 +249,8 @@ static int stub_recv_cmd_unlink(struct stub_device *sdev,  		ret = usb_unlink_urb(priv->urb);  		if (ret != -EINPROGRESS)  			dev_err(&priv->urb->dev->dev, -				"failed to unlink a urb %p, ret %d\n", -				priv->urb, ret); +				"failed to unlink a urb # %lu, ret %d\n", +				priv->seqnum, ret);  		return 0;  	} @@ -322,23 +319,26 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,  	return priv;  } -static int get_pipe(struct stub_device *sdev, int epnum, int dir) +static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu)  {  	struct usb_device *udev = sdev->udev;  	struct usb_host_endpoint *ep;  	struct usb_endpoint_descriptor *epd = NULL; +	int epnum = pdu->base.ep; +	int dir = pdu->base.direction; + +	if (epnum < 0 || epnum > 15) +		goto err_ret;  	if (dir == USBIP_DIR_IN)  		ep = udev->ep_in[epnum & 0x7f];  	else  		ep = udev->ep_out[epnum & 0x7f]; -	if (!ep) { -		dev_err(&sdev->udev->dev, "no such endpoint?, %d\n", -			epnum); -		BUG(); -	} +	if (!ep) +		goto err_ret;  	epd = &ep->desc; +  	if (usb_endpoint_xfer_control(epd)) {  		if (dir == USBIP_DIR_OUT)  			return usb_sndctrlpipe(udev, epnum); @@ -361,15 +361,31 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir)  	}  	if (usb_endpoint_xfer_isoc(epd)) { +		/* validate packet size and number of packets */ +		unsigned int maxp, packets, bytes; + +		maxp = usb_endpoint_maxp(epd); +		maxp *= usb_endpoint_maxp_mult(epd); +		bytes = pdu->u.cmd_submit.transfer_buffer_length; +		packets = DIV_ROUND_UP(bytes, maxp); + +		if (pdu->u.cmd_submit.number_of_packets < 0 || +		    pdu->u.cmd_submit.number_of_packets > packets) { +			dev_err(&sdev->udev->dev, +				"CMD_SUBMIT: isoc invalid num packets %d\n", +				pdu->u.cmd_submit.number_of_packets); +			return -1; +		}  		if (dir == USBIP_DIR_OUT)  			return usb_sndisocpipe(udev, epnum);  		else  			return usb_rcvisocpipe(udev, epnum);  	} +err_ret:  	/* NOT REACHED */ -	dev_err(&sdev->udev->dev, "get pipe, epnum %d\n", epnum); -	return 0; +	dev_err(&sdev->udev->dev, "CMD_SUBMIT: invalid epnum %d\n", epnum); +	return -1;  }  static void masking_bogus_flags(struct urb *urb) @@ -433,7 +449,10 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,  	struct stub_priv *priv;  	struct usbip_device *ud = &sdev->ud;  	struct usb_device *udev = sdev->udev; -	int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction); +	int pipe = get_pipe(sdev, pdu); + +	if (pipe == -1) +		return;  	priv = stub_priv_alloc(sdev, pdu);  	if (!priv) |