Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length

2016-02-17 Thread Gerd Hoffmann
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




Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length

2016-02-17 Thread P J P
+-- 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



Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length

2016-02-16 Thread P J P
  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



Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length

2016-02-16 Thread Gerd Hoffmann
> 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




Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length

2016-02-15 Thread Gerd Hoffmann
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 
> | | 
> | | 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 
> | 
> | ...ping!
> 
> Ping...Gerd?

Was offline for a week, will look soonish (have a email backlog to
process now ...)

cheers,
  Gerd




Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length

2016-02-14 Thread P J P
+-- On Tue, 9 Feb 2016, P J P wrote --+
| +-- On Fri, 5 Feb 2016, P J P wrote --+
| | From: Prasad J Pandit 
| | 
| | 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 
| 
| ...ping!

Ping...Gerd?
--
 - P J P
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F



Re: [Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length

2016-02-09 Thread P J P
+-- On Fri, 5 Feb 2016, P J P wrote --+
| From: Prasad J Pandit 
| 
| 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 

...ping!
--
 - P J P
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F



[Qemu-devel] [PATCH] usb: check RNDIS buffer offsets & length

2016-02-05 Thread P J P
From: Prasad J Pandit 

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 
Signed-off-by: Prasad J Pandit 
---
 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, >out_buf[len], s->out_ptr);
-- 
2.5.0