[Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions

Lidong Chen posted 1 patch 5 years ago
Test docker-mingw@fedora passed
Test docker-clang@ubuntu passed
Test checkpatch passed
Test asan passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/1554750276-19230-1-git-send-email-lidong.chen@oracle.com
Maintainers: "Philippe Mathieu-Daudé" <f4bug@amsat.org>
There is a newer version of this series
hw/sd/sd.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
[Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Lidong Chen 5 years ago
Due to an off-by-one error, the assert statements allow an
out-of-bounds array access.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
---
 hw/sd/sd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index aaab15f..818f86c 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
     if (state == sd_inactive_state) {
         return "inactive";
     }
-    assert(state <= ARRAY_SIZE(state_name));
+    assert(state < ARRAY_SIZE(state_name));
     return state_name[state];
 }
 
@@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
     if (rsp == sd_r1b) {
         rsp = sd_r1;
     }
-    assert(rsp <= ARRAY_SIZE(response_name));
+    assert(rsp < ARRAY_SIZE(response_name));
     return response_name[rsp];
 }
 
-- 
1.8.3.1


Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Marc-André Lureau 5 years ago
On Mon, Apr 8, 2019 at 9:51 PM Lidong Chen <lidong.chen@oracle.com> wrote:
>
> Due to an off-by-one error, the assert statements allow an
> out-of-bounds array access.
>
> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

> ---
>  hw/sd/sd.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index aaab15f..818f86c 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
>      if (state == sd_inactive_state) {
>          return "inactive";
>      }
> -    assert(state <= ARRAY_SIZE(state_name));
> +    assert(state < ARRAY_SIZE(state_name));
>      return state_name[state];
>  }
>
> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>      if (rsp == sd_r1b) {
>          rsp = sd_r1;
>      }
> -    assert(rsp <= ARRAY_SIZE(response_name));
> +    assert(rsp < ARRAY_SIZE(response_name));
>      return response_name[rsp];
>  }
>
> --
> 1.8.3.1
>
>


-- 
Marc-André Lureau

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Philippe Mathieu-Daudé 5 years ago
Hi Lidong

On 4/8/19 9:04 PM, Lidong Chen wrote:
> Due to an off-by-one error, the assert statements allow an
> out-of-bounds array access.

... which can't happen. Thus harmless for 4.0.

I suppose this is a static analysis warning and you didn't triggered it
while tracing.

Thanks for cleaning this :)

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
> ---
>  hw/sd/sd.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index aaab15f..818f86c 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
>      if (state == sd_inactive_state) {
>          return "inactive";
>      }
> -    assert(state <= ARRAY_SIZE(state_name));
> +    assert(state < ARRAY_SIZE(state_name));
>      return state_name[state];
>  }
>  
> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>      if (rsp == sd_r1b) {
>          rsp = sd_r1;
>      }
> -    assert(rsp <= ARRAY_SIZE(response_name));
> +    assert(rsp < ARRAY_SIZE(response_name));
>      return response_name[rsp];
>  }
>  
> 

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Lidong Chen 5 years ago
Hi Philippe,

On 4/8/2019 2:27 PM, Philippe Mathieu-Daudé wrote:
> Hi Lidong
>
> On 4/8/19 9:04 PM, Lidong Chen wrote:
>> Due to an off-by-one error, the assert statements allow an
>> out-of-bounds array access.
> ... which can't happen. Thus harmless for 4.0.
>
> I suppose this is a static analysis warning and you didn't triggered it
> while tracing.

Right, it was found by the static analysis.  Thank you for your review.

Regards,

Lidong


>
> Thanks for cleaning this :)
>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>
>> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
>> ---
>>   hw/sd/sd.c | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
>> index aaab15f..818f86c 100644
>> --- a/hw/sd/sd.c
>> +++ b/hw/sd/sd.c
>> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
>>       if (state == sd_inactive_state) {
>>           return "inactive";
>>       }
>> -    assert(state <= ARRAY_SIZE(state_name));
>> +    assert(state < ARRAY_SIZE(state_name));
>>       return state_name[state];
>>   }
>>   
>> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>>       if (rsp == sd_r1b) {
>>           rsp = sd_r1;
>>       }
>> -    assert(rsp <= ARRAY_SIZE(response_name));
>> +    assert(rsp < ARRAY_SIZE(response_name));
>>       return response_name[rsp];
>>   }
>>   
>>

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Li Qiang 5 years ago
Lidong Chen <lidong.chen@oracle.com> 于2019年4月9日周二 上午3:51写道:

> Due to an off-by-one error, the assert statements allow an
> out-of-bounds array access.
>
> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
>

Reviewed-by: Li Qiang <liq3ea@gmail.com>


> ---
>  hw/sd/sd.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index aaab15f..818f86c 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates
> state)
>      if (state == sd_inactive_state) {
>          return "inactive";
>      }
> -    assert(state <= ARRAY_SIZE(state_name));
> +    assert(state < ARRAY_SIZE(state_name));
>      return state_name[state];
>  }
>
> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>      if (rsp == sd_r1b) {
>          rsp = sd_r1;
>      }
> -    assert(rsp <= ARRAY_SIZE(response_name));
> +    assert(rsp < ARRAY_SIZE(response_name));
>      return response_name[rsp];
>  }
>
> --
> 1.8.3.1
>
>
>
Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Markus Armbruster 5 years ago
Lidong Chen <lidong.chen@oracle.com> writes:

> Due to an off-by-one error, the assert statements allow an
> out-of-bounds array access.
>
> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
> ---
>  hw/sd/sd.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index aaab15f..818f86c 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
>      if (state == sd_inactive_state) {
>          return "inactive";
>      }
> -    assert(state <= ARRAY_SIZE(state_name));
> +    assert(state < ARRAY_SIZE(state_name));
>      return state_name[state];
>  }
>  
> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>      if (rsp == sd_r1b) {
>          rsp = sd_r1;
>      }
> -    assert(rsp <= ARRAY_SIZE(response_name));
> +    assert(rsp < ARRAY_SIZE(response_name));
>      return response_name[rsp];
>  }

This is the second fix for this bug pattern in a fortnight.  Where's
one, there are more:

$ git-grep '<= ARRAY_SIZE'
hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));
target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));

Lidong Chen, would you like to have a look at these?

Cc'ing maintainers to help with further investigation.

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Aleksandar Markovic 5 years ago
>
> Lidong Chen <lidong.chen@oracle.com> writes:
>
> > Due to an off-by-one error, the assert statements allow an
> > out-of-bounds array access.
> >
> > Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
> > ---
> >  hw/sd/sd.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> > index aaab15f..818f86c 100644
> > --- a/hw/sd/sd.c
> > +++ b/hw/sd/sd.c
> > @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
> >      if (state == sd_inactive_state) {
> >          return "inactive";
> >      }
> > -    assert(state <= ARRAY_SIZE(state_name));
> > +    assert(state < ARRAY_SIZE(state_name));
> >      return state_name[state];
> >  }
> >
> > @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
> >      if (rsp == sd_r1b) {
> >          rsp = sd_r1;
> >      }
> > -    assert(rsp <= ARRAY_SIZE(response_name));
> > +    assert(rsp < ARRAY_SIZE(response_name));
> >      return response_name[rsp];
> >  }
>
> This is the second fix for this bug pattern in a fortnight.  Where's
> one, there are more:
>
> $ git-grep '<= ARRAY_SIZE'
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
> hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
> hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
> hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
> hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));

> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {

The last four items are OK as they are. The variable multiple_regs is, in fact,
an array of 9 int constants:

static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };

ARRAY_SIZE (multiple_regs) will always be equal to 9.

The variable base_reglist (that is checked to be > 0 and <=9) is used
in succeeding lines like this:

        for (i = 0; i < base_reglist; i++) {
            do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
                  GETPC());
            addr += 4;
        }

Therefore, the array multiple_regs will always be accessed within its bounds.

> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
> tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
> util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
> util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));
>
> Lidong Chen, would you like to have a look at these?
>
> Cc'ing maintainers to help with further investigation.
>

Thank you for bringing this to our attention, Markus. And thanks to Lidong too.

Aleksandar

P. S. Shouldn't perhaps our macro ARRAY_SIZE() be renamed to
NUMBER_OF_ELEMENTS()?

________________________________________
From: Markus Armbruster <armbru@redhat.com>
Sent: Tuesday, April 9, 2019 7:51:51 AM
To: Lidong Chen
Cc: qemu-devel@nongnu.org; darren.kenny@oracle.com; f4bug@amsat.org; Peter Maydell; Jason Wang; Andrzej Zaborowski; Gerd Hoffmann; Aurelien Jarno; Aleksandar Markovic; Aleksandar Rikalo; David Gibson; Richard Henderson; Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions

Lidong Chen <lidong.chen@oracle.com> writes:

> Due to an off-by-one error, the assert statements allow an
> out-of-bounds array access.
>
> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
> ---
>  hw/sd/sd.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index aaab15f..818f86c 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
>      if (state == sd_inactive_state) {
>          return "inactive";
>      }
> -    assert(state <= ARRAY_SIZE(state_name));
> +    assert(state < ARRAY_SIZE(state_name));
>      return state_name[state];
>  }
>
> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>      if (rsp == sd_r1b) {
>          rsp = sd_r1;
>      }
> -    assert(rsp <= ARRAY_SIZE(response_name));
> +    assert(rsp < ARRAY_SIZE(response_name));
>      return response_name[rsp];
>  }

This is the second fix for this bug pattern in a fortnight.  Where's
one, there are more:

$ git-grep '<= ARRAY_SIZE'
hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));
target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));

Lidong Chen, would you like to have a look at these?

Cc'ing maintainers to help with further investigation.

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Philippe Mathieu-Daudé 5 years ago
On 4/9/19 10:59 AM, Aleksandar Markovic wrote:
>>
>> Lidong Chen <lidong.chen@oracle.com> writes:
>>
>>> Due to an off-by-one error, the assert statements allow an
>>> out-of-bounds array access.
>>>
>>> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
>>> ---
>>>  hw/sd/sd.c | 4 ++--
>>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
>>> index aaab15f..818f86c 100644
>>> --- a/hw/sd/sd.c
>>> +++ b/hw/sd/sd.c
>>> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
>>>      if (state == sd_inactive_state) {
>>>          return "inactive";
>>>      }
>>> -    assert(state <= ARRAY_SIZE(state_name));
>>> +    assert(state < ARRAY_SIZE(state_name));
>>>      return state_name[state];
>>>  }
>>>
>>> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>>>      if (rsp == sd_r1b) {
>>>          rsp = sd_r1;
>>>      }
>>> -    assert(rsp <= ARRAY_SIZE(response_name));
>>> +    assert(rsp < ARRAY_SIZE(response_name));
>>>      return response_name[rsp];
>>>  }
>>
>> This is the second fix for this bug pattern in a fortnight.  Where's
>> one, there are more:
>>
>> $ git-grep '<= ARRAY_SIZE'
>> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
>> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
>> hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
>> hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
>> hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
>> hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
>> hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
>> hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
>> hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));
> 
>> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
>> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
>> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
>> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> 
> The last four items are OK as they are. The variable multiple_regs is, in fact,
> an array of 9 int constants:
> 
> static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
> 
> ARRAY_SIZE (multiple_regs) will always be equal to 9.
> 
> The variable base_reglist (that is checked to be > 0 and <=9) is used
> in succeeding lines like this:
> 
>         for (i = 0; i < base_reglist; i++) {
>             do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
>                   GETPC());
>             addr += 4;
>         }
> 
> Therefore, the array multiple_regs will always be accessed within its bounds.
> 
>> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
>> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
>> target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
>> tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
>> util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
>> util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));
>>
>> Lidong Chen, would you like to have a look at these?
>>
>> Cc'ing maintainers to help with further investigation.
>>
> 
> Thank you for bringing this to our attention, Markus. And thanks to Lidong too.
> 
> Aleksandar
> 
> P. S. Shouldn't perhaps our macro ARRAY_SIZE() be renamed to
> NUMBER_OF_ELEMENTS()?

I remember this post from Daniel where he suggests sticking to GLib
G_N_ELEMENTS() (which looks similar to your suggestion):
https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg02676.html

$ git grep G_N_ELEMENTS|wc -l
125
$ git grep ARRAY_SIZE|wc -l
939

Now it is not obvious to me to understand which GLib API we are
encouraged to use and which ones we shouldn't.

> ________________________________________
> From: Markus Armbruster <armbru@redhat.com>
> Sent: Tuesday, April 9, 2019 7:51:51 AM
> To: Lidong Chen
> Cc: qemu-devel@nongnu.org; darren.kenny@oracle.com; f4bug@amsat.org; Peter Maydell; Jason Wang; Andrzej Zaborowski; Gerd Hoffmann; Aurelien Jarno; Aleksandar Markovic; Aleksandar Rikalo; David Gibson; Richard Henderson; Paolo Bonzini
> Subject: Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
> 
> Lidong Chen <lidong.chen@oracle.com> writes:
> 
>> Due to an off-by-one error, the assert statements allow an
>> out-of-bounds array access.
>>
>> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
>> ---
>>  hw/sd/sd.c | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
>> index aaab15f..818f86c 100644
>> --- a/hw/sd/sd.c
>> +++ b/hw/sd/sd.c
>> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
>>      if (state == sd_inactive_state) {
>>          return "inactive";
>>      }
>> -    assert(state <= ARRAY_SIZE(state_name));
>> +    assert(state < ARRAY_SIZE(state_name));
>>      return state_name[state];
>>  }
>>
>> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>>      if (rsp == sd_r1b) {
>>          rsp = sd_r1;
>>      }
>> -    assert(rsp <= ARRAY_SIZE(response_name));
>> +    assert(rsp < ARRAY_SIZE(response_name));
>>      return response_name[rsp];
>>  }
> 
> This is the second fix for this bug pattern in a fortnight.  Where's
> one, there are more:
> 
> $ git-grep '<= ARRAY_SIZE'
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
> hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
> hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
> hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
> hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
> tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
> util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
> util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));
> 
> Lidong Chen, would you like to have a look at these?
> 
> Cc'ing maintainers to help with further investigation.
> 

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Daniel P. Berrangé 5 years ago
On Tue, Apr 09, 2019 at 11:37:44AM +0200, Philippe Mathieu-Daudé wrote:
> On 4/9/19 10:59 AM, Aleksandar Markovic wrote:
> >>
> >> Lidong Chen <lidong.chen@oracle.com> writes:
> >>
> >>> Due to an off-by-one error, the assert statements allow an
> >>> out-of-bounds array access.
> >>>
> >>> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
> >>> ---
> >>>  hw/sd/sd.c | 4 ++--
> >>>  1 file changed, 2 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> >>> index aaab15f..818f86c 100644
> >>> --- a/hw/sd/sd.c
> >>> +++ b/hw/sd/sd.c
> >>> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
> >>>      if (state == sd_inactive_state) {
> >>>          return "inactive";
> >>>      }
> >>> -    assert(state <= ARRAY_SIZE(state_name));
> >>> +    assert(state < ARRAY_SIZE(state_name));
> >>>      return state_name[state];
> >>>  }
> >>>
> >>> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
> >>>      if (rsp == sd_r1b) {
> >>>          rsp = sd_r1;
> >>>      }
> >>> -    assert(rsp <= ARRAY_SIZE(response_name));
> >>> +    assert(rsp < ARRAY_SIZE(response_name));
> >>>      return response_name[rsp];
> >>>  }
> >>
> >> This is the second fix for this bug pattern in a fortnight.  Where's
> >> one, there are more:
> >>
> >> $ git-grep '<= ARRAY_SIZE'
> >> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> >> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> >> hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
> >> hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
> >> hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
> >> hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
> >> hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
> >> hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
> >> hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));
> > 
> >> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> >> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> >> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> >> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> > 
> > The last four items are OK as they are. The variable multiple_regs is, in fact,
> > an array of 9 int constants:
> > 
> > static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
> > 
> > ARRAY_SIZE (multiple_regs) will always be equal to 9.
> > 
> > The variable base_reglist (that is checked to be > 0 and <=9) is used
> > in succeeding lines like this:
> > 
> >         for (i = 0; i < base_reglist; i++) {
> >             do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
> >                   GETPC());
> >             addr += 4;
> >         }
> > 
> > Therefore, the array multiple_regs will always be accessed within its bounds.
> > 
> >> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> >> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> >> target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
> >> tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
> >> util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
> >> util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));
> >>
> >> Lidong Chen, would you like to have a look at these?
> >>
> >> Cc'ing maintainers to help with further investigation.
> >>
> > 
> > Thank you for bringing this to our attention, Markus. And thanks to Lidong too.
> > 
> > Aleksandar
> > 
> > P. S. Shouldn't perhaps our macro ARRAY_SIZE() be renamed to
> > NUMBER_OF_ELEMENTS()?
> 
> I remember this post from Daniel where he suggests sticking to GLib
> G_N_ELEMENTS() (which looks similar to your suggestion):
> https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg02676.html
> 
> $ git grep G_N_ELEMENTS|wc -l
> 125
> $ git grep ARRAY_SIZE|wc -l
> 939
> 
> Now it is not obvious to me to understand which GLib API we are
> encouraged to use and which ones we shouldn't.

We have a bunch of duplication that is essentially a historical
artifact from before we used GLib in QEMU. IMHO, if GLib provides
something that is equivalent with no functional downside that
matters to QEMU, then there's no reason to keep QEMU's duplicate.

IOW, I would always prefer GLib unless there's a compelling reason
not to in order to minimize what we maintain ourselves


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Markus Armbruster 5 years ago
Daniel P. Berrangé <berrange@redhat.com> writes:

> On Tue, Apr 09, 2019 at 11:37:44AM +0200, Philippe Mathieu-Daudé wrote:
[...]
>> I remember this post from Daniel where he suggests sticking to GLib
>> G_N_ELEMENTS() (which looks similar to your suggestion):
>> https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg02676.html
>> 
>> $ git grep G_N_ELEMENTS|wc -l
>> 125
>> $ git grep ARRAY_SIZE|wc -l
>> 939
>> 
>> Now it is not obvious to me to understand which GLib API we are
>> encouraged to use and which ones we shouldn't.
>
> We have a bunch of duplication that is essentially a historical
> artifact from before we used GLib in QEMU. IMHO, if GLib provides
> something that is equivalent with no functional downside that
> matters to QEMU, then there's no reason to keep QEMU's duplicate.
>
> IOW, I would always prefer GLib unless there's a compelling reason
> not to in order to minimize what we maintain ourselves

Without a tree-wide sweep, we won't ever stop maintaining ARRAY_SIZE().

As long as we maintain it anyway, I'd prefer it over G_N_ELEMENTS()
myself, because I consider latter name in poor taste: elements of
*what*?

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Daniel P. Berrangé 5 years ago
On Thu, Apr 11, 2019 at 02:20:27PM +0200, Markus Armbruster wrote:
> Daniel P. Berrangé <berrange@redhat.com> writes:
> 
> > On Tue, Apr 09, 2019 at 11:37:44AM +0200, Philippe Mathieu-Daudé wrote:
> [...]
> >> I remember this post from Daniel where he suggests sticking to GLib
> >> G_N_ELEMENTS() (which looks similar to your suggestion):
> >> https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg02676.html
> >> 
> >> $ git grep G_N_ELEMENTS|wc -l
> >> 125
> >> $ git grep ARRAY_SIZE|wc -l
> >> 939
> >> 
> >> Now it is not obvious to me to understand which GLib API we are
> >> encouraged to use and which ones we shouldn't.
> >
> > We have a bunch of duplication that is essentially a historical
> > artifact from before we used GLib in QEMU. IMHO, if GLib provides
> > something that is equivalent with no functional downside that
> > matters to QEMU, then there's no reason to keep QEMU's duplicate.
> >
> > IOW, I would always prefer GLib unless there's a compelling reason
> > not to in order to minimize what we maintain ourselves
> 
> Without a tree-wide sweep, we won't ever stop maintaining ARRAY_SIZE().

In this case it is a pretty trivial search & replace to do. The main
hard bit would be syncing with various maintainer trees. Global cleanups
are more work if you need to feed patches in via several different trees,
as opposed to one tree-wide series.

> As long as we maintain it anyway, I'd prefer it over G_N_ELEMENTS()
> myself, because I consider latter name in poor taste: elements of
> *what*?

elements of the variable that you are passing into the macro.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Markus Armbruster 5 years ago
Daniel P. Berrangé <berrange@redhat.com> writes:

> On Thu, Apr 11, 2019 at 02:20:27PM +0200, Markus Armbruster wrote:
>> Daniel P. Berrangé <berrange@redhat.com> writes:
>> 
>> > On Tue, Apr 09, 2019 at 11:37:44AM +0200, Philippe Mathieu-Daudé wrote:
>> [...]
>> >> I remember this post from Daniel where he suggests sticking to GLib
>> >> G_N_ELEMENTS() (which looks similar to your suggestion):
>> >> https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg02676.html
>> >> 
>> >> $ git grep G_N_ELEMENTS|wc -l
>> >> 125
>> >> $ git grep ARRAY_SIZE|wc -l
>> >> 939
>> >> 
>> >> Now it is not obvious to me to understand which GLib API we are
>> >> encouraged to use and which ones we shouldn't.
>> >
>> > We have a bunch of duplication that is essentially a historical
>> > artifact from before we used GLib in QEMU. IMHO, if GLib provides
>> > something that is equivalent with no functional downside that
>> > matters to QEMU, then there's no reason to keep QEMU's duplicate.
>> >
>> > IOW, I would always prefer GLib unless there's a compelling reason
>> > not to in order to minimize what we maintain ourselves
>> 
>> Without a tree-wide sweep, we won't ever stop maintaining ARRAY_SIZE().
>
> In this case it is a pretty trivial search & replace to do. The main
> hard bit would be syncing with various maintainer trees. Global cleanups
> are more work if you need to feed patches in via several different trees,
> as opposed to one tree-wide series.

Yes, it's a hassle.  I doubt it's worthwhile.  Anyway, unless somebody
does this work, ARRAY_SIZE() will surely stay.

>> As long as we maintain it anyway, I'd prefer it over G_N_ELEMENTS()
>> myself, because I consider latter name in poor taste: elements of
>> *what*?
>
> elements of the variable that you are passing into the macro.

I pass a GSList * variable.

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Aleksandar Markovic 5 years ago
Markus wrote:

> This is the second fix for this bug pattern in a fortnight.  Where's
> one, there are more:
> 
> $ git-grep '<= ARRAY_SIZE'
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
> hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
> hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
> hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
> hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
> tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
> util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
> util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));

There could be even more:

$ git grep '> ARRAY_SIZE'
hw/display/ssd0323.c:    if (s->cmd_len > ARRAY_SIZE(s->cmd_data)) {
hw/display/vmware_vga.c:                || SVGA_BITMAP_SIZE(x, y) > ARRAY_SIZE(cursor.mask)
hw/display/vmware_vga.c:                    > ARRAY_SIZE(cursor.image)) {
hw/dma/xlnx-zdma.c:        len = src_size > ARRAY_SIZE(s->buf) ? ARRAY_SIZE(s->buf) : src_size;
hw/net/stellaris_enet.c:    if (s->np > ARRAY_SIZE(s->rx)) {
hw/net/stellaris_enet.c:        if (s->rx[i].len > ARRAY_SIZE(s->rx[i].data)) {
hw/net/stellaris_enet.c:    if (s->rx_fifo_offset > ARRAY_SIZE(s->rx[0].data) - 4) {
hw/net/stellaris_enet.c:    if (s->tx_fifo_len > ARRAY_SIZE(s->tx_fifo)) {
hw/scsi/mptsas.c:    ((s)->name##_head > ARRAY_SIZE((s)->name) ||         \
hw/scsi/mptsas.c:     (s)->name##_tail > ARRAY_SIZE((s)->name))
hw/scsi/mptsas.c:        s->doorbell_cnt > ARRAY_SIZE(s->doorbell_msg) ||
hw/scsi/mptsas.c:        s->doorbell_reply_size > ARRAY_SIZE(s->doorbell_reply) ||
hw/sd/ssi-sd.c:        (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) {
hw/usb/dev-mtp.c:            if (cmd.argc > ARRAY_SIZE(cmd.argv)) {
linux-user/syscall.c:    if (nargs[num] > ARRAY_SIZE(a)) {
target/sh4/translate.c:    if (max_insns > ARRAY_SIZE(insns)) {

CC-ing additional maintainers.

Aleksandar
Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Peter Maydell 5 years ago
On Tue, 9 Apr 2019 at 06:51, Markus Armbruster <armbru@redhat.com> wrote:
> $ git-grep '<= ARRAY_SIZE'

Almost all of these are OK because they're the pattern of
checking a loop upper bound before doing a loop.

> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));

These are OK -- we're checking that the upper bound of
a loop (i = 0; i < aprmax; i++) is not greater than the worst
possible upper bound imposed by the array size.

> hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {

This is OK, because we're checking that we can
store to the 4 entries starting at s->tx_fifo[s->tx_fifo_len].

> hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);

These are OK beacuse they're checking the number of bytes
held in the array, not an index.

> hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
> hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));

These are bugs, as Philippe says.

> hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));

This is another check of a loop upper bound, so it's OK.

> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {

OK, as Aleksandar has said.

> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));

Loop upper bound check, OK.

> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));

Ditto.

> target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));

Ditto.

> tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));

This is doing a check after a series of "op->args[pi++]" actions,
so the sense of the test is correct and the question is just
whether it would be better to do the assert before every
array access (which would be pretty expensive and in any
case wouldn't affect production systems where tcg_debug_assert()
is a no-op.)

> util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));

This one seems to be doing an incorrect check, because
we are about to do accesses to poll_fds[n_poll_fds + i]
for i in [0, w->num), so the assert should be checking
"n_poll_fds + w->num <= ARRAY_SIZE(poll_fds)" I think.

> util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));

Loop upper bound check, OK.

thanks
-- PMM

Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Liam Merwick 5 years ago
On 09/04/2019 06:51, Markus Armbruster wrote:
> Lidong Chen <lidong.chen@oracle.com> writes:
>
>> Due to an off-by-one error, the assert statements allow an
>> out-of-bounds array access.
>>
>> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>


Reviewed-by: Liam Merwick <liam.merwick@oracle.com>


>> ---
>>   hw/sd/sd.c | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
>> index aaab15f..818f86c 100644
>> --- a/hw/sd/sd.c
>> +++ b/hw/sd/sd.c
>> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum SDCardStates state)
>>       if (state == sd_inactive_state) {
>>           return "inactive";
>>       }
>> -    assert(state <= ARRAY_SIZE(state_name));
>> +    assert(state < ARRAY_SIZE(state_name));
>>       return state_name[state];
>>   }
>>   
>> @@ -165,7 +165,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
>>       if (rsp == sd_r1b) {
>>           rsp = sd_r1;
>>       }
>> -    assert(rsp <= ARRAY_SIZE(response_name));
>> +    assert(rsp < ARRAY_SIZE(response_name));
>>       return response_name[rsp];
>>   }
> This is the second fix for this bug pattern in a fortnight.  Where's
> one, there are more:


As Lidong mentioned, an internal static analysis tool (Parfait) was used 
to catch these. Not every arch/board is compiled but I had eyeballed the 
code of most interest to me and they seemed fine (e.g. for array 
accesses, the subsequent loops used a less-than check)

However, this WIN32 code in util/main-loop.c seems wrong.

425     g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
426
427     for (i = 0; i < w->num; i++) {
428         poll_fds[n_poll_fds + i].fd = (DWORD_PTR)w->events[i];
429         poll_fds[n_poll_fds + i].events = G_IO_IN;
430     }

Seems like this should be:

g_assert(n_poll_fds + w->num <= ARRAY_SIZE(poll_fds));

Otherwise, the rest seem fine.

Regards,

Liam


>
> $ git-grep '<= ARRAY_SIZE'
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
> hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) {
> hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
> hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
> hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
> hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
> hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
> target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
> tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
> util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
> util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));
>
> Lidong Chen, would you like to have a look at these?
>
> Cc'ing maintainers to help with further investigation.
>


Re: [Qemu-devel] [PATCH] sd: Fix out-of-bounds assertions
Posted by Lidong Chen 5 years ago
Hi,

Thank you all for the reviews and comments! Since the fixes in sd.c have 
gone through the review, I can fix the issue in util/main-loop.c 
(mentioned in the reviews of Peter and Liam) in a separate patch.

Thanks,

Lidong

On 4/9/2019 3:39 AM, Liam Merwick wrote:
> On 09/04/2019 06:51, Markus Armbruster wrote:
>> Lidong Chen <lidong.chen@oracle.com> writes:
>>
>>> Due to an off-by-one error, the assert statements allow an
>>> out-of-bounds array access.
>>>
>>> Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
>
>
> Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
>
>
>>> ---
>>>   hw/sd/sd.c | 4 ++--
>>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
>>> index aaab15f..818f86c 100644
>>> --- a/hw/sd/sd.c
>>> +++ b/hw/sd/sd.c
>>> @@ -144,7 +144,7 @@ static const char *sd_state_name(enum 
>>> SDCardStates state)
>>>       if (state == sd_inactive_state) {
>>>           return "inactive";
>>>       }
>>> -    assert(state <= ARRAY_SIZE(state_name));
>>> +    assert(state < ARRAY_SIZE(state_name));
>>>       return state_name[state];
>>>   }
>>>   @@ -165,7 +165,7 @@ static const char 
>>> *sd_response_name(sd_rsp_type_t rsp)
>>>       if (rsp == sd_r1b) {
>>>           rsp = sd_r1;
>>>       }
>>> -    assert(rsp <= ARRAY_SIZE(response_name));
>>> +    assert(rsp < ARRAY_SIZE(response_name));
>>>       return response_name[rsp];
>>>   }
>> This is the second fix for this bug pattern in a fortnight. Where's
>> one, there are more:
>
>
> As Lidong mentioned, an internal static analysis tool (Parfait) was 
> used to catch these. Not every arch/board is compiled but I had 
> eyeballed the code of most interest to me and they seemed fine (e.g. 
> for array accesses, the subsequent loops used a less-than check)
>
> However, this WIN32 code in util/main-loop.c seems wrong.
>
> 425     g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
> 426
> 427     for (i = 0; i < w->num; i++) {
> 428         poll_fds[n_poll_fds + i].fd = (DWORD_PTR)w->events[i];
> 429         poll_fds[n_poll_fds + i].events = G_IO_IN;
> 430     }
>
> Seems like this should be:
>
> g_assert(n_poll_fds + w->num <= ARRAY_SIZE(poll_fds));
>
> Otherwise, the rest seem fine.
>
> Regards,
>
> Liam
>
>
>>
>> $ git-grep '<= ARRAY_SIZE'
>> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= 
>> ARRAY_SIZE(cs->ich_apr[0]));
>> hw/intc/arm_gicv3_cpuif.c:    assert(aprmax <= 
>> ARRAY_SIZE(cs->ich_apr[0]));
>> hw/net/stellaris_enet.c:        if (s->tx_fifo_len + 4 <= 
>> ARRAY_SIZE(s->tx_fifo)) {
>> hw/sd/pxa2xx_mmci.c:        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
>> hw/sd/pxa2xx_mmci.c:        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
>> hw/sd/pxa2xx_mmci.c:        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
>> hw/sd/sd.c:    assert(state <= ARRAY_SIZE(state_name));
>> hw/sd/sd.c:    assert(rsp <= ARRAY_SIZE(response_name));
>> hw/usb/hcd-xhci.c:    assert(n <= ARRAY_SIZE(tmp));
>> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= 
>> ARRAY_SIZE (multiple_regs)) {
>> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= 
>> ARRAY_SIZE (multiple_regs)) {
>> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= 
>> ARRAY_SIZE (multiple_regs)) {
>> target/mips/op_helper.c:    if (base_reglist > 0 && base_reglist <= 
>> ARRAY_SIZE (multiple_regs)) {
>> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
>> target/ppc/kvm.c:           <= ARRAY_SIZE(hw_debug_points));
>> target/ppc/kvm.c:    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= 
>> ARRAY_SIZE(dbg->arch.bp));
>> tcg/tcg.c:    tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
>> util/main-loop.c:    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
>> util/module.c:    assert(n_dirs <= ARRAY_SIZE(dirs));
>>
>> Lidong Chen, would you like to have a look at these?
>>
>> Cc'ing maintainers to help with further investigation.
>>
>