diff options
author | Johan Hovold <johan@kernel.org> | 2017-01-31 11:17:28 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-14 08:00:18 -0400 |
commit | 9ca3010675025a512db998b1421ad0b60963c790 (patch) | |
tree | fa16a66d8bab1dd6bf62e24ce08f9048ecfac9f2 | |
parent | 84443215cf54861f3013253817afaf156efb1453 (diff) |
USB: serial: digi_acceleport: fix incomplete rx sanity check
commit 1b0aed2b1600f6e5c7b9acfbd610a4e351ef5232 upstream.
Make sure the received data has the required headers before parsing it.
Also drop the redundant urb-status check, which has already been handled
by the caller.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/serial/digi_acceleport.c | 38 |
1 files changed, 23 insertions, 15 deletions
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 30bf0f5db82d..7ab3235febfc 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c | |||
@@ -1398,25 +1398,30 @@ static int digi_read_inb_callback(struct urb *urb) | |||
1398 | { | 1398 | { |
1399 | struct usb_serial_port *port = urb->context; | 1399 | struct usb_serial_port *port = urb->context; |
1400 | struct digi_port *priv = usb_get_serial_port_data(port); | 1400 | struct digi_port *priv = usb_get_serial_port_data(port); |
1401 | int opcode = ((unsigned char *)urb->transfer_buffer)[0]; | 1401 | unsigned char *buf = urb->transfer_buffer; |
1402 | int len = ((unsigned char *)urb->transfer_buffer)[1]; | 1402 | int opcode; |
1403 | int port_status = ((unsigned char *)urb->transfer_buffer)[2]; | 1403 | int len; |
1404 | unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3; | 1404 | int port_status; |
1405 | unsigned char *data; | ||
1405 | int flag, throttled; | 1406 | int flag, throttled; |
1406 | int status = urb->status; | ||
1407 | |||
1408 | /* do not process callbacks on closed ports */ | ||
1409 | /* but do continue the read chain */ | ||
1410 | if (urb->status == -ENOENT) | ||
1411 | return 0; | ||
1412 | 1407 | ||
1413 | /* short/multiple packet check */ | 1408 | /* short/multiple packet check */ |
1409 | if (urb->actual_length < 2) { | ||
1410 | dev_warn(&port->dev, "short packet received\n"); | ||
1411 | return -1; | ||
1412 | } | ||
1413 | |||
1414 | opcode = buf[0]; | ||
1415 | len = buf[1]; | ||
1416 | |||
1414 | if (urb->actual_length != len + 2) { | 1417 | if (urb->actual_length != len + 2) { |
1415 | dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, " | 1418 | dev_err(&port->dev, "malformed packet received: port=%d, opcode=%d, len=%d, actual_length=%u\n", |
1416 | "status=%d, port=%d, opcode=%d, len=%d, " | 1419 | priv->dp_port_num, opcode, len, urb->actual_length); |
1417 | "actual_length=%d, status=%d\n", __func__, status, | 1420 | return -1; |
1418 | priv->dp_port_num, opcode, len, urb->actual_length, | 1421 | } |
1419 | port_status); | 1422 | |
1423 | if (opcode == DIGI_CMD_RECEIVE_DATA && len < 1) { | ||
1424 | dev_err(&port->dev, "malformed data packet received\n"); | ||
1420 | return -1; | 1425 | return -1; |
1421 | } | 1426 | } |
1422 | 1427 | ||
@@ -1430,6 +1435,9 @@ static int digi_read_inb_callback(struct urb *urb) | |||
1430 | 1435 | ||
1431 | /* receive data */ | 1436 | /* receive data */ |
1432 | if (opcode == DIGI_CMD_RECEIVE_DATA) { | 1437 | if (opcode == DIGI_CMD_RECEIVE_DATA) { |
1438 | port_status = buf[2]; | ||
1439 | data = &buf[3]; | ||
1440 | |||
1433 | /* get flag from port_status */ | 1441 | /* get flag from port_status */ |
1434 | flag = 0; | 1442 | flag = 0; |
1435 | 1443 | ||