* [Qemu-devel] [PATCH 1/3] usb-ccid: better bulk_out error handling
2017-02-16 13:13 [Qemu-devel] [PATCH 0/3] usb-ccid: improve sanity checks Gerd Hoffmann
@ 2017-02-16 13:13 ` Gerd Hoffmann
2017-02-16 13:13 ` [Qemu-devel] [PATCH 2/3] usb-ccid: move header size check Gerd Hoffmann
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2017-02-16 13:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Add err goto label where we can jump to from all error conditions.
STALL request on all errors. Reset position on all errors.
Normal request processing is not in a else branch any more, so this code
is reintended, there are no code changes in that part of the code
though.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/dev-smartcard-reader.c | 116 ++++++++++++++++++++++--------------------
1 file changed, 61 insertions(+), 55 deletions(-)
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 1325ea1..badcfcb 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1001,8 +1001,7 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
CCID_Header *ccid_header;
if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
- p->status = USB_RET_STALL;
- return;
+ goto err;
}
ccid_header = (CCID_Header *)s->bulk_out_data;
usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
@@ -1017,64 +1016,71 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
DPRINTF(s, 1,
"%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n",
__func__);
- } else {
- DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__,
- ccid_header->bMessageType,
- ccid_message_type_to_str(ccid_header->bMessageType));
- switch (ccid_header->bMessageType) {
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus:
- ccid_write_slot_status(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn:
- DPRINTF(s, 1, "%s: PowerOn: %d\n", __func__,
+ goto err;
+ }
+
+ DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__,
+ ccid_header->bMessageType,
+ ccid_message_type_to_str(ccid_header->bMessageType));
+ switch (ccid_header->bMessageType) {
+ case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus:
+ ccid_write_slot_status(s, ccid_header);
+ break;
+ case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn:
+ DPRINTF(s, 1, "%s: PowerOn: %d\n", __func__,
((CCID_IccPowerOn *)(ccid_header))->bPowerSelect);
- s->powered = true;
- if (!ccid_card_inserted(s)) {
- ccid_report_error_failed(s, ERROR_ICC_MUTE);
- }
- /* atr is written regardless of error. */
- ccid_write_data_block_atr(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff:
- ccid_reset_error_status(s);
- s->powered = false;
- ccid_write_slot_status(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock:
- ccid_on_apdu_from_guest(s, (CCID_XferBlock *)s->bulk_out_data);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters:
- ccid_reset_error_status(s);
- ccid_set_parameters(s, ccid_header);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters:
- ccid_reset_error_status(s);
- ccid_reset_parameters(s);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters:
- ccid_reset_error_status(s);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical:
- ccid_report_error_failed(s, 0);
- ccid_write_slot_status(s, ccid_header);
- break;
- default:
- DPRINTF(s, 1,
+ s->powered = true;
+ if (!ccid_card_inserted(s)) {
+ ccid_report_error_failed(s, ERROR_ICC_MUTE);
+ }
+ /* atr is written regardless of error. */
+ ccid_write_data_block_atr(s, ccid_header);
+ break;
+ case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff:
+ ccid_reset_error_status(s);
+ s->powered = false;
+ ccid_write_slot_status(s, ccid_header);
+ break;
+ case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock:
+ ccid_on_apdu_from_guest(s, (CCID_XferBlock *)s->bulk_out_data);
+ break;
+ case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters:
+ ccid_reset_error_status(s);
+ ccid_set_parameters(s, ccid_header);
+ ccid_write_parameters(s, ccid_header);
+ break;
+ case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters:
+ ccid_reset_error_status(s);
+ ccid_reset_parameters(s);
+ ccid_write_parameters(s, ccid_header);
+ break;
+ case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters:
+ ccid_reset_error_status(s);
+ ccid_write_parameters(s, ccid_header);
+ break;
+ case CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical:
+ ccid_report_error_failed(s, 0);
+ ccid_write_slot_status(s, ccid_header);
+ break;
+ default:
+ DPRINTF(s, 1,
"handle_data: ERROR: unhandled message type %Xh\n",
ccid_header->bMessageType);
- /*
- * The caller is expecting the device to respond, tell it we
- * don't support the operation.
- */
- ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
- ccid_write_slot_status(s, ccid_header);
- break;
- }
+ /*
+ * The caller is expecting the device to respond, tell it we
+ * don't support the operation.
+ */
+ ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
+ ccid_write_slot_status(s, ccid_header);
+ break;
}
s->bulk_out_pos = 0;
+ return;
+
+err:
+ p->status = USB_RET_STALL;
+ s->bulk_out_pos = 0;
+ return;
}
static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 2/3] usb-ccid: move header size check
2017-02-16 13:13 [Qemu-devel] [PATCH 0/3] usb-ccid: improve sanity checks Gerd Hoffmann
2017-02-16 13:13 ` [Qemu-devel] [PATCH 1/3] usb-ccid: better bulk_out error handling Gerd Hoffmann
@ 2017-02-16 13:13 ` Gerd Hoffmann
2017-02-16 13:13 ` [Qemu-devel] [PATCH 3/3] usb-ccid: add check message size checks Gerd Hoffmann
2017-02-17 10:26 ` [Qemu-devel] [PATCH 0/3] usb-ccid: improve sanity checks Marc-André Lureau
3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2017-02-16 13:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Move up header size check, so we can use header fields in sanity checks
(in followup patches). Also reword the debug message.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/dev-smartcard-reader.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index badcfcb..1acc1fb 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1003,21 +1003,20 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
goto err;
}
- ccid_header = (CCID_Header *)s->bulk_out_data;
usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
s->bulk_out_pos += p->iov.size;
+ if (s->bulk_out_pos < 10) {
+ DPRINTF(s, 1, "%s: header incomplete\n", __func__);
+ goto err;
+ }
+
+ ccid_header = (CCID_Header *)s->bulk_out_data;
if (p->iov.size == CCID_MAX_PACKET_SIZE) {
DPRINTF(s, D_VERBOSE,
"usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
p->iov.size, ccid_header->dwLength);
return;
}
- if (s->bulk_out_pos < 10) {
- DPRINTF(s, 1,
- "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n",
- __func__);
- goto err;
- }
DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__,
ccid_header->bMessageType,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 3/3] usb-ccid: add check message size checks
2017-02-16 13:13 [Qemu-devel] [PATCH 0/3] usb-ccid: improve sanity checks Gerd Hoffmann
2017-02-16 13:13 ` [Qemu-devel] [PATCH 1/3] usb-ccid: better bulk_out error handling Gerd Hoffmann
2017-02-16 13:13 ` [Qemu-devel] [PATCH 2/3] usb-ccid: move header size check Gerd Hoffmann
@ 2017-02-16 13:13 ` Gerd Hoffmann
2017-02-17 10:26 ` [Qemu-devel] [PATCH 0/3] usb-ccid: improve sanity checks Marc-André Lureau
3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2017-02-16 13:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Check message size too when figuring whenever we should expect more data.
Fix debug message to show useful data, p->iov.size is fixed anyway if we
land there, print how much we got meanwhile instead.
Also check announced message size against actual message size. That
is a more general fix for CVE-2017-5898 than commit "c7dfbf3 usb: ccid:
check ccid apdu length".
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/dev-smartcard-reader.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 1acc1fb..7cd4ed0 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1011,12 +1011,19 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
}
ccid_header = (CCID_Header *)s->bulk_out_data;
- if (p->iov.size == CCID_MAX_PACKET_SIZE) {
+ if ((s->bulk_out_pos - 10 < ccid_header->dwLength) &&
+ (p->iov.size == CCID_MAX_PACKET_SIZE)) {
DPRINTF(s, D_VERBOSE,
- "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
- p->iov.size, ccid_header->dwLength);
+ "usb-ccid: bulk_in: expecting more packets (%d/%d)\n",
+ s->bulk_out_pos - 10, ccid_header->dwLength);
return;
}
+ if (s->bulk_out_pos - 10 != ccid_header->dwLength) {
+ DPRINTF(s, 1,
+ "usb-ccid: bulk_in: message size mismatch (got %d, expected %d)\n",
+ s->bulk_out_pos - 10, ccid_header->dwLength);
+ goto err;
+ }
DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__,
ccid_header->bMessageType,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread