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_hcd.c | 1 | ||||
| -rw-r--r-- | drivers/usb/usbip/vhci_sysfs.c | 25 | 
5 files changed, 65 insertions, 20 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,  	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; + +	/* validate transfer_buffer_length */ +	if (pdu->u.cmd_submit.transfer_buffer_length > INT_MAX) { +		dev_err(&sdev->udev->dev, +			"CMD_SUBMIT: -EMSGSIZE transfer_buffer_length %d\n", +			pdu->u.cmd_submit.transfer_buffer_length); +		return -1; +	} +  	if (usb_endpoint_xfer_control(epd)) {  		if (dir == USBIP_DIR_OUT)  			return usb_sndctrlpipe(udev, epnum); @@ -361,15 +372,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 +460,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) @@ -452,7 +482,8 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,  	}  	/* allocate urb transfer buffer, if needed */ -	if (pdu->u.cmd_submit.transfer_buffer_length > 0) { +	if (pdu->u.cmd_submit.transfer_buffer_length > 0 && +	    pdu->u.cmd_submit.transfer_buffer_length <= INT_MAX) {  		priv->urb->transfer_buffer =  			kzalloc(pdu->u.cmd_submit.transfer_buffer_length,  				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)  		memset(&pdu_header, 0, sizeof(pdu_header));  		memset(&msg, 0, sizeof(msg)); +		if (urb->actual_length > 0 && !urb->transfer_buffer) { +			dev_err(&sdev->udev->dev, +				"urb: actual_length %d transfer_buffer null\n", +				urb->actual_length); +			return -1; +		} +  		if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)  			iovnum = 2 + urb->number_of_packets;  		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 {  	/* lock for status */  	spinlock_t lock; +	int sockfd;  	struct socket *tcp_socket;  	struct task_struct *tcp_rx; diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 713e94170963..6b3278c4b72a 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1098,7 +1098,6 @@ static int hcd_name_to_id(const char *name)  static int vhci_setup(struct usb_hcd *hcd)  {  	struct vhci *vhci = *((void **)dev_get_platdata(hcd->self.controller)); -	hcd->self.sg_tablesize = ~0;  	if (usb_hcd_is_primary_hcd(hcd)) {  		vhci->vhci_hcd_hs = hcd_to_vhci_hcd(hcd);  		vhci->vhci_hcd_hs->vhci = vhci; 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 @@  /*   * output example: - * hub port sta spd dev      socket           local_busid - * hs  0000 004 000 00000000         c5a7bb80 1-2.3 + * hub port sta spd dev       sockfd    local_busid + * hs  0000 004 000 00000000  3         1-2.3   * ................................................ - * ss  0008 004 000 00000000         d8cee980 2-3.4 + * ss  0008 004 000 00000000  4         2-3.4   * ................................................   * - * IP address can be retrieved from a socket pointer address by looking - * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a - * port number and its peer IP address. + * Output includes socket fd instead of socket pointer address to avoid + * leaking kernel memory address in: + *	/sys/devices/platform/vhci_hcd.0/status and in debug output. + * The socket pointer address is not used at the moment and it was made + * visible as a convenient way to find IP address from socket pointer + * address by looking up /proc/net/{tcp,tcp6}. As this opens a security + * hole, the change is made to use sockfd instead. + *   */  static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev)  { @@ -39,8 +44,8 @@ static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vd  	if (vdev->ud.status == VDEV_ST_USED) {  		*out += sprintf(*out, "%03u %08x ",  				      vdev->speed, vdev->devid); -		*out += sprintf(*out, "%16p %s", -				      vdev->ud.tcp_socket, +		*out += sprintf(*out, "%u %s", +				      vdev->ud.sockfd,  				      dev_name(&vdev->udev->dev));  	} else { @@ -160,7 +165,8 @@ static ssize_t nports_show(struct device *dev, struct device_attribute *attr,  	char *s = out;  	/* -	 * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, thus the * 2. +	 * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, +	 * thus the * 2.  	 */  	out += sprintf(out, "%d\n", VHCI_PORTS * vhci_num_controllers);  	return out - s; @@ -366,6 +372,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,  	vdev->devid         = devid;  	vdev->speed         = speed; +	vdev->ud.sockfd     = sockfd;  	vdev->ud.tcp_socket = socket;  	vdev->ud.status     = VDEV_ST_NOTASSIGNED; |