* [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length
@ 2016-02-05 10:54 P J P
2016-02-09 11:01 ` P J P
2016-02-16 14:33 ` Gerd Hoffmann
0 siblings, 2 replies; 8+ messages in thread
From: P J P @ 2016-02-05 10:54 UTC (permalink / raw)
To: Qemu Developers; +Cc: Qinghao Tang, Gerd Hoffmann, Prasad J Pandit
From: Prasad J Pandit <pjp@fedoraproject.org>
When processing remote NDIS control message packets, the USB Net
device emulator uses a fixed length(4096) data buffer. The incoming
informationBufferOffset & Length combination could cross that range.
Check control message buffer offsets and length to avoid it.
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/usb/core.c | 25 ++++++++++++++++---------
hw/usb/dev-network.c | 9 ++++++---
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/hw/usb/core.c b/hw/usb/core.c
index d0025db..9d90ec7 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -128,9 +128,16 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
}
usb_packet_copy(p, s->setup_buf, p->iov.size);
+ s->setup_index = 0;
p->actual_length = 0;
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
- s->setup_index = 0;
+ if (s->setup_len > sizeof(s->data_buf)) {
+ fprintf(stderr,
+ "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
+ s->setup_len, sizeof(s->data_buf));
+ p->status = USB_RET_STALL;
+ return;
+ }
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
@@ -151,13 +158,6 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
}
s->setup_state = SETUP_STATE_DATA;
} else {
- if (s->setup_len > sizeof(s->data_buf)) {
- fprintf(stderr,
- "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
- s->setup_len, sizeof(s->data_buf));
- p->status = USB_RET_STALL;
- return;
- }
if (s->setup_len == 0)
s->setup_state = SETUP_STATE_ACK;
else
@@ -172,11 +172,18 @@ static void do_token_in(USBDevice *s, USBPacket *p)
int request, value, index;
assert(p->ep->nr == 0);
+ if (s->setup_len > sizeof(s->data_buf)) {
+ fprintf(stderr,
+ "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
+ s->setup_len, sizeof(s->data_buf));
+ p->status = USB_RET_STALL;
+ return;
+ }
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
-
+
switch(s->setup_state) {
case SETUP_STATE_ACK:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index 7800cee..ba3c7a7 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -914,8 +914,9 @@ static int rndis_query_response(USBNetState *s,
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
buflen = le32_to_cpu(buf->InformationBufferLength);
- if (bufoffs + buflen > length)
+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
return USB_RET_STALL;
+ }
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
bufoffs + (uint8_t *) buf, buflen, infobuf,
@@ -960,8 +961,9 @@ static int rndis_set_response(USBNetState *s,
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
buflen = le32_to_cpu(buf->InformationBufferLength);
- if (bufoffs + buflen > length)
+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
return USB_RET_STALL;
+ }
ret = ndis_set(s, le32_to_cpu(buf->OID),
bufoffs + (uint8_t *) buf, buflen);
@@ -1211,8 +1213,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
uint32_t size = le32_to_cpu(msg->DataLength);
- if (offs + size <= len)
+ if (offs < len && size < len && offs + size <= len) {
qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size);
+ }
}
s->out_ptr -= len;
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
--
2.5.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length
2016-02-05 10:54 [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length P J P
@ 2016-02-09 11:01 ` P J P
2016-02-15 4:26 ` P J P
2016-02-16 14:33 ` Gerd Hoffmann
1 sibling, 1 reply; 8+ messages in thread
From: P J P @ 2016-02-09 11:01 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: Qinghao Tang, Qemu Developers
+-- On Fri, 5 Feb 2016, P J P wrote --+
| From: Prasad J Pandit <pjp@fedoraproject.org>
|
| When processing remote NDIS control message packets, the USB Net
| device emulator uses a fixed length(4096) data buffer. The incoming
| informationBufferOffset & Length combination could cross that range.
| Check control message buffer offsets and length to avoid it.
|
| Reported-by: Qinghao Tang <luodalongde@gmail.com>
...ping!
--
- P J P
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length
2016-02-09 11:01 ` P J P
@ 2016-02-15 4:26 ` P J P
2016-02-15 9:41 ` Gerd Hoffmann
0 siblings, 1 reply; 8+ messages in thread
From: P J P @ 2016-02-15 4:26 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: Qinghao Tang, Qemu Developers
+-- On Tue, 9 Feb 2016, P J P wrote --+
| +-- On Fri, 5 Feb 2016, P J P wrote --+
| | From: Prasad J Pandit <pjp@fedoraproject.org>
| |
| | When processing remote NDIS control message packets, the USB Net
| | device emulator uses a fixed length(4096) data buffer. The incoming
| | informationBufferOffset & Length combination could cross that range.
| | Check control message buffer offsets and length to avoid it.
| |
| | Reported-by: Qinghao Tang <luodalongde@gmail.com>
|
| ...ping!
Ping...Gerd?
--
- P J P
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length
2016-02-15 4:26 ` P J P
@ 2016-02-15 9:41 ` Gerd Hoffmann
0 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2016-02-15 9:41 UTC (permalink / raw)
To: P J P; +Cc: Qinghao Tang, Qemu Developers
On Mo, 2016-02-15 at 09:56 +0530, P J P wrote:
> +-- On Tue, 9 Feb 2016, P J P wrote --+
> | +-- On Fri, 5 Feb 2016, P J P wrote --+
> | | From: Prasad J Pandit <pjp@fedoraproject.org>
> | |
> | | When processing remote NDIS control message packets, the USB Net
> | | device emulator uses a fixed length(4096) data buffer. The incoming
> | | informationBufferOffset & Length combination could cross that range.
> | | Check control message buffer offsets and length to avoid it.
> | |
> | | Reported-by: Qinghao Tang <luodalongde@gmail.com>
> |
> | ...ping!
>
> Ping...Gerd?
Was offline for a week, will look soonish (have a email backlog to
process now ...)
cheers,
Gerd
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length
2016-02-05 10:54 [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length P J P
2016-02-09 11:01 ` P J P
@ 2016-02-16 14:33 ` Gerd Hoffmann
2016-02-16 19:00 ` P J P
2016-02-17 8:25 ` P J P
1 sibling, 2 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2016-02-16 14:33 UTC (permalink / raw)
To: P J P; +Cc: Qinghao Tang, Qemu Developers, Prasad J Pandit
> diff --git a/hw/usb/core.c b/hw/usb/core.c
> index d0025db..9d90ec7 100644
> --- a/hw/usb/core.c
> +++ b/hw/usb/core.c
> @@ -128,9 +128,16 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
> }
>
> usb_packet_copy(p, s->setup_buf, p->iov.size);
> + s->setup_index = 0;
> p->actual_length = 0;
> s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
> - s->setup_index = 0;
> + if (s->setup_len > sizeof(s->data_buf)) {
> + fprintf(stderr,
> + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
> + s->setup_len, sizeof(s->data_buf));
> + p->status = USB_RET_STALL;
> + return;
> + }
>
> request = (s->setup_buf[0] << 8) | s->setup_buf[1];
> value = (s->setup_buf[3] << 8) | s->setup_buf[2];
> @@ -151,13 +158,6 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
> }
> s->setup_state = SETUP_STATE_DATA;
> } else {
> - if (s->setup_len > sizeof(s->data_buf)) {
> - fprintf(stderr,
> - "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
> - s->setup_len, sizeof(s->data_buf));
> - p->status = USB_RET_STALL;
> - return;
> - }
> if (s->setup_len == 0)
> s->setup_state = SETUP_STATE_ACK;
> else
Moves up the check so it is done for every control xfer. Good.
> @@ -172,11 +172,18 @@ static void do_token_in(USBDevice *s, USBPacket *p)
> int request, value, index;
>
> assert(p->ep->nr == 0);
> + if (s->setup_len > sizeof(s->data_buf)) {
> + fprintf(stderr,
> + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
> + s->setup_len, sizeof(s->data_buf));
> + p->status = USB_RET_STALL;
> + return;
> + }
Why this is needed? All control transfers go through do_token_setup
first, so with the check moved in do_token_setup we should never ever
trigger it here ...
> - if (bufoffs + buflen > length)
> + if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
> return USB_RET_STALL;
> + }
What is this? Not mentioned in the commit message. Looks like integer
overflow prevention to me (if correct: separate patch with proper commit
message please).
thanks,
Gerd
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length
2016-02-16 14:33 ` Gerd Hoffmann
@ 2016-02-16 19:00 ` P J P
2016-02-17 8:25 ` P J P
1 sibling, 0 replies; 8+ messages in thread
From: P J P @ 2016-02-16 19:00 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: Qinghao Tang, Qemu Developers
Hello Gerd,
+-- On Tue, 16 Feb 2016, Gerd Hoffmann wrote --+
| Moves up the check so it is done for every control xfer. Good.
...
| Why this is needed? All control transfers go through do_token_setup
| first, so with the check moved in do_token_setup we should never ever
| trigger it here ...
I see, okay.
| > - if (bufoffs + buflen > length)
| > + if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
| > return USB_RET_STALL;
| > + }
|
| What is this? Not mentioned in the commit message. Looks like integer
| overflow prevention to me (if correct: separate patch with proper commit
| message please).
That's right. I've sent separate revised patches for the above two changes.
Thank you.
--
Prasad J Pandit / Red Hat Product Security Team
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length
2016-02-16 14:33 ` Gerd Hoffmann
2016-02-16 19:00 ` P J P
@ 2016-02-17 8:25 ` P J P
2016-02-17 14:46 ` Gerd Hoffmann
1 sibling, 1 reply; 8+ messages in thread
From: P J P @ 2016-02-17 8:25 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: Qinghao Tang, Qemu Developers
+-- On Tue, 16 Feb 2016, Gerd Hoffmann wrote --+
| > @@ -172,11 +172,18 @@ static void do_token_in(USBDevice *s, USBPacket *p)
| > assert(p->ep->nr == 0);
| > + if (s->setup_len > sizeof(s->data_buf)) {
| > + fprintf(stderr,
| > + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
| > + s->setup_len, sizeof(s->data_buf));
| > + p->status = USB_RET_STALL;
| > + return;
| > + }
|
| Why this is needed? All control transfers go through do_token_setup
| first, so with the check moved in do_token_setup we should never ever
| trigger it here ...
usb_handle_packet
-> usb_process_one
-> do_token_in
Is it possible for a guest to call do_token_in, without calling
do_token_setup first? Most drivers seem to have their own 'usb_packet_setup'
routine. (to confirm)
Thank you.
--
Prasad J Pandit / Red Hat Product Security Team
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length
2016-02-17 8:25 ` P J P
@ 2016-02-17 14:46 ` Gerd Hoffmann
0 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2016-02-17 14:46 UTC (permalink / raw)
To: P J P; +Cc: Qinghao Tang, Qemu Developers
On Mi, 2016-02-17 at 13:55 +0530, P J P wrote:
> +-- On Tue, 16 Feb 2016, Gerd Hoffmann wrote --+
> | > @@ -172,11 +172,18 @@ static void do_token_in(USBDevice *s, USBPacket *p)
> | > assert(p->ep->nr == 0);
> | > + if (s->setup_len > sizeof(s->data_buf)) {
> | > + fprintf(stderr,
> | > + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
> | > + s->setup_len, sizeof(s->data_buf));
> | > + p->status = USB_RET_STALL;
> | > + return;
> | > + }
> |
> | Why this is needed? All control transfers go through do_token_setup
> | first, so with the check moved in do_token_setup we should never ever
> | trigger it here ...
>
> usb_handle_packet
> -> usb_process_one
> -> do_token_in
>
> Is it possible for a guest to call do_token_in, without calling
> do_token_setup first?
For anything interesting to happen in do_token_in() setup_state must be
set to either ACK or DATA, and for that to be the case do_token_setup()
must run first. I don't think the guest can trick qemu to go straight
to do_token_in().
Also s->setup_len is set in do_token_setup() only, verifying it once
(after setting it from guest-supplied data) should be enough.
cheers,
Gerd
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2016-02-17 14:46 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-05 10:54 [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length P J P
2016-02-09 11:01 ` P J P
2016-02-15 4:26 ` P J P
2016-02-15 9:41 ` Gerd Hoffmann
2016-02-16 14:33 ` Gerd Hoffmann
2016-02-16 19:00 ` P J P
2016-02-17 8:25 ` P J P
2016-02-17 14:46 ` Gerd Hoffmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).