diff mbox series

[v2,1/3] megasas: use unsigned type for reply_queue_head and check index

Message ID 20200513192540.1583887-2-ppandit@redhat.com (mailing list archive)
State New, archived
Headers show
Series Megasas: fix OOB access and NULL dereference issues | expand

Commit Message

Prasad Pandit May 13, 2020, 7:25 p.m. UTC
From: Prasad J Pandit <pjp@fedoraproject.org>

A guest user may set 'reply_queue_head' field of MegasasState to
a negative value. Later in 'megasas_lookup_frame' it is used to
index into s->frames[] array. Use unsigned type to avoid OOB
access issue.

Also check that 'index' value stays within s->frames[] bounds
through the while() loop in 'megasas_lookup_frame' to avoid OOB
access.

Reported-by: Ren Ding <rding@gatech.edu>
Reported-by: Hanqing Zhao <hanqing@gatech.edu>
Reported-by: Alexander Bulekov <alxndr@bu.edu>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
 hw/scsi/megasas.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Update v1 -> v2: fix OOB access when index > MEGASAS_MAX_FRAMES(=2048)
 -> https://lists.gnu.org/archive/html/qemu-devel/2020-05/msg03131.html

Comments

Alexander Bulekov May 13, 2020, 8:31 p.m. UTC | #1
Hi Prasad,
On 200514 0055, P J P wrote:
> From: Prasad J Pandit <pjp@fedoraproject.org>
> 
> A guest user may set 'reply_queue_head' field of MegasasState to
> a negative value. Later in 'megasas_lookup_frame' it is used to
> index into s->frames[] array. Use unsigned type to avoid OOB
> access issue.
> 
> Also check that 'index' value stays within s->frames[] bounds
> through the while() loop in 'megasas_lookup_frame' to avoid OOB
> access.
> 
> Reported-by: Ren Ding <rding@gatech.edu>
> Reported-by: Hanqing Zhao <hanqing@gatech.edu>
> Reported-by: Alexander Bulekov <alxndr@bu.edu>
> Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
> ---

Acked-by: Alexander Bulekov <alxndr@bu.edu>

I applied these patches and could not reproduce the heap-overflow, or
LP1878259

Thanks
-Alex

>  hw/scsi/megasas.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> Update v1 -> v2: fix OOB access when index > MEGASAS_MAX_FRAMES(=2048)
>  -> https://lists.gnu.org/archive/html/qemu-devel/2020-05/msg03131.html
> 
> diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
> index af18c88b65..6ce598cd69 100644
> --- a/hw/scsi/megasas.c
> +++ b/hw/scsi/megasas.c
> @@ -112,7 +112,7 @@ typedef struct MegasasState {
>      uint64_t reply_queue_pa;
>      void *reply_queue;
>      int reply_queue_len;
> -    int reply_queue_head;
> +    uint16_t reply_queue_head;
>      int reply_queue_tail;
>      uint64_t consumer_pa;
>      uint64_t producer_pa;
> @@ -445,7 +445,7 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s,
>  
>      index = s->reply_queue_head;
>  
> -    while (num < s->fw_cmds) {
> +    while (num < s->fw_cmds && index < MEGASAS_MAX_FRAMES) {
>          if (s->frames[index].pa && s->frames[index].pa == frame) {
>              cmd = &s->frames[index];
>              break;
> -- 
> 2.25.4
>
Darren Kenny May 14, 2020, 1:19 p.m. UTC | #2
Hi Prasad,

On Thursday, 2020-05-14 at 00:55:38 +0530, P J P wrote:
> From: Prasad J Pandit <pjp@fedoraproject.org>
>
> A guest user may set 'reply_queue_head' field of MegasasState to
> a negative value. Later in 'megasas_lookup_frame' it is used to
> index into s->frames[] array. Use unsigned type to avoid OOB
> access issue.
>
> Also check that 'index' value stays within s->frames[] bounds
> through the while() loop in 'megasas_lookup_frame' to avoid OOB
> access.
>
> Reported-by: Ren Ding <rding@gatech.edu>
> Reported-by: Hanqing Zhao <hanqing@gatech.edu>
> Reported-by: Alexander Bulekov <alxndr@bu.edu>
> Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
> ---
>  hw/scsi/megasas.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> Update v1 -> v2: fix OOB access when index > MEGASAS_MAX_FRAMES(=2048)
>  -> https://lists.gnu.org/archive/html/qemu-devel/2020-05/msg03131.html
>
> diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
> index af18c88b65..6ce598cd69 100644
> --- a/hw/scsi/megasas.c
> +++ b/hw/scsi/megasas.c
> @@ -112,7 +112,7 @@ typedef struct MegasasState {
>      uint64_t reply_queue_pa;
>      void *reply_queue;
>      int reply_queue_len;
> -    int reply_queue_head;
> +    uint16_t reply_queue_head;
>      int reply_queue_tail;
>      uint64_t consumer_pa;
>      uint64_t producer_pa;
> @@ -445,7 +445,7 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s,
>  
>      index = s->reply_queue_head;

While it is probably unlikely that it would cause an integer underflow
here, for consistency, index probably should also be declared as
unsigned, but from what I can tell it is still an 'int'.

Thanks,

Darren.

>  
> -    while (num < s->fw_cmds) {
> +    while (num < s->fw_cmds && index < MEGASAS_MAX_FRAMES) {
>          if (s->frames[index].pa && s->frames[index].pa == frame) {
>              cmd = &s->frames[index];
>              break;
> -- 
> 2.25.4
Prasad Pandit May 14, 2020, 4:10 p.m. UTC | #3
Hello Darren,

+-- On Thu, 14 May 2020, Darren Kenny wrote --+
| > Update v1 -> v2: fix OOB access when index > MEGASAS_MAX_FRAMES(=2048)
| >  -> https://lists.gnu.org/archive/html/qemu-devel/2020-05/msg03131.html
| >
| > diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
| > -    int reply_queue_head;
| > +    uint16_t reply_queue_head;
| > @@ -445,7 +445,7 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s,
| >  
| >      index = s->reply_queue_head;
| 
| While it is probably unlikely that it would cause an integer underflow
| here,

Yes, integer overflow is unlikely going from uint16_t -> to -> int type.

  s->reply_queue_head = ldl_le_pci_dma(pcid, s->producer_pa);
  s->reply_queue_head %= MEGASAS_MAX_FRAMES;

Also here 's->reply_queue_head' is restricted between 0...MEGASAS_MAX_FRAMES=2048

| -    while (num < s->fw_cmds) {
| +    while (num < s->fw_cmds && index < MEGASAS_MAX_FRAMES) {

And this patch would help keep 'index' within the same 0..MEGASAS_MAX_FRAMES 
range.

| for consistency, index probably should also be declared as unsigned, but 
| from what I can tell it is still an 'int'.

It did cross my mind, but it's generally advised to keep these fixes to 
minimum possible changes and specific to the issue they fix. Index being a 
local variable, changing it to an unsigned type wouldn't help much to fix the 
issue or otherwise I think.

Thank you.
--
Prasad J Pandit / Red Hat Product Security Team
8685 545E B54C 486B C6EB 271E E285 8B5A F050 DE8D
diff mbox series

Patch

diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index af18c88b65..6ce598cd69 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -112,7 +112,7 @@  typedef struct MegasasState {
     uint64_t reply_queue_pa;
     void *reply_queue;
     int reply_queue_len;
-    int reply_queue_head;
+    uint16_t reply_queue_head;
     int reply_queue_tail;
     uint64_t consumer_pa;
     uint64_t producer_pa;
@@ -445,7 +445,7 @@  static MegasasCmd *megasas_lookup_frame(MegasasState *s,
 
     index = s->reply_queue_head;
 
-    while (num < s->fw_cmds) {
+    while (num < s->fw_cmds && index < MEGASAS_MAX_FRAMES) {
         if (s->frames[index].pa && s->frames[index].pa == frame) {
             cmd = &s->frames[index];
             break;