lkml.org 
[lkml]   [2018]   [Jan]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 51/74] usbip: fix stub_rx: harden CMD_SUBMIT path to handle malicious input
    Date
    4.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Shuah Khan <shuahkh@osg.samsung.com>

    commit c6688ef9f29762e65bce325ef4acd6c675806366 upstream.

    Harden CMD_SUBMIT path to handle malicious input that could trigger
    large memory allocations. Add checks to validate transfer_buffer_length
    and number_of_packets to protect against bad input requesting for
    unbounded memory allocations. Validate early in get_pipe() and return
    failure.

    Reported-by: Secunia Research <vuln@secunia.com>
    Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>


    ---
    drivers/usb/usbip/stub_rx.c | 30 +++++++++++++++++++++++++++---
    1 file changed, 27 insertions(+), 3 deletions(-)

    --- a/drivers/usb/usbip/stub_rx.c
    +++ b/drivers/usb/usbip/stub_rx.c
    @@ -338,11 +338,13 @@ static struct stub_priv *stub_priv_alloc
    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;
    @@ -355,6 +357,7 @@ static int get_pipe(struct stub_device *
    goto err_ret;

    epd = &ep->desc;
    +
    if (usb_endpoint_xfer_control(epd)) {
    if (dir == USBIP_DIR_OUT)
    return usb_sndctrlpipe(udev, epnum);
    @@ -377,6 +380,27 @@ static int get_pipe(struct stub_device *
    }

    if (usb_endpoint_xfer_isoc(epd)) {
    + /* validate packet size and number of packets */
    + unsigned int maxp, packets, bytes;
    +
    +#define USB_EP_MAXP_MULT_SHIFT 11
    +#define USB_EP_MAXP_MULT_MASK (3 << USB_EP_MAXP_MULT_SHIFT)
    +#define USB_EP_MAXP_MULT(m) \
    + (((m) & USB_EP_MAXP_MULT_MASK) >> USB_EP_MAXP_MULT_SHIFT)
    +
    + maxp = usb_endpoint_maxp(epd);
    + maxp *= (USB_EP_MAXP_MULT(
    + __le16_to_cpu(epd->wMaxPacketSize)) + 1);
    + 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
    @@ -385,7 +409,7 @@ static int get_pipe(struct stub_device *

    err_ret:
    /* NOT REACHED */
    - dev_err(&sdev->udev->dev, "get pipe() invalid epnum %d\n", epnum);
    + dev_err(&sdev->udev->dev, "CMD_SUBMIT: invalid epnum %d\n", epnum);
    return -1;
    }

    @@ -450,7 +474,7 @@ static void stub_recv_cmd_submit(struct
    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;

    \
     
     \ /
      Last update: 2018-01-29 22:10    [W:4.229 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site