diff mbox series

[4/6] coverity-model: clean up the models for array allocation functions

Message ID 20210731062741.301102-5-pbonzini@redhat.com (mailing list archive)
State New, archived
Headers show
Series Updates for Coverity modeling file | expand

Commit Message

Paolo Bonzini July 31, 2021, 6:27 a.m. UTC
sz is only used in one place, so replace it with nmemb * size in
that one place.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 scripts/coverity-scan/model.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

Comments

Peter Maydell Aug. 2, 2021, 12:36 p.m. UTC | #1
On Sat, 31 Jul 2021 at 07:31, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> sz is only used in one place, so replace it with nmemb * size in
> that one place.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  scripts/coverity-scan/model.c | 13 +++----------
>  1 file changed, 3 insertions(+), 10 deletions(-)
>
> diff --git a/scripts/coverity-scan/model.c b/scripts/coverity-scan/model.c
> index 1a5f39d2ae..2d384bdd79 100644
> --- a/scripts/coverity-scan/model.c
> +++ b/scripts/coverity-scan/model.c
> @@ -178,13 +178,11 @@ uint8_t replay_get_byte(void)
>
>  void *g_malloc_n(size_t nmemb, size_t size)
>  {
> -    size_t sz;
>      void *ptr;
>
>      __coverity_negative_sink__(nmemb);
>      __coverity_negative_sink__(size);
> -    sz = nmemb * size;
> -    ptr = __coverity_alloc__(sz);
> +    ptr = __coverity_alloc__(nmemb * size);
>      __coverity_mark_as_uninitialized_buffer__(ptr);
>      __coverity_mark_as_afm_allocated__(ptr, AFM_free);
>      return ptr;

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

The real g_malloc_n() returns failure if the multiplication
would overflow; I guess Coverity currently doesn't have any
warnings it generates as a result of assuming overflow
might happen?

thanks
-- PMM
Paolo Bonzini Aug. 2, 2021, 4:20 p.m. UTC | #2
On 02/08/21 14:36, Peter Maydell wrote:
> Reviewed-by: Peter Maydell<peter.maydell@linaro.org>
> 
> The real g_malloc_n() returns failure if the multiplication
> would overflow; I guess Coverity currently doesn't have any
> warnings it generates as a result of assuming overflow
> might happen?

I couldn't find any Coverity-specific way to detect overflow, but making 
nmemb a tainted sink could be an interesting way to ensure that 
untrusted data does not end up causing such a failure.

Likewise, we should try making __bufwrite taint the buffer it is writing 
to; there's already a TODO for that but I never followed up on it.

Paolo
Markus Armbruster Aug. 4, 2021, 8:35 a.m. UTC | #3
Paolo Bonzini <pbonzini@redhat.com> writes:

> On 02/08/21 14:36, Peter Maydell wrote:
>> Reviewed-by: Peter Maydell<peter.maydell@linaro.org>
>> The real g_malloc_n() returns failure if the multiplication
>> would overflow;

Really?  Its documentation:

    This function is similar to g_malloc(), allocating (n_blocks *
    n_block_bytes) bytes, but care is taken to detect possible overflow
    during multiplication.

There's also g_try_malloc_n():

    This function is similar to g_try_malloc(), allocating (n_blocks *
    n_block_bytes) bytes, but care is taken to detect possible overflow
    during multiplication.

I read this as g_malloc_n() can return null only for zero size, and
crashes on error, just like g_malloc_n().  g_try_malloc_n() behaves like
g_try_malloc_n(), i.e. it returns null on failure.

>>                 I guess Coverity currently doesn't have any
>> warnings it generates as a result of assuming overflow
>> might happen?
>
> I couldn't find any Coverity-specific way to detect overflow, but

Does it need one?

Quick peek at Coverity 2012.12 Checker Reference:

    4.188. INTEGER_OVERFLOW
    [...]
    4.188.1. Overview

    Supported Languages: C, C++, Objective-C, Objective-C++

    INTEGER_OVERFLOW finds many cases of integer overflows and
    truncations resulting from arithmetic operations. Some forms of
    integer overflow can cause security vulnerabilities, for example,
    when the overflowed value is used as the argument to an allocation
    function. [...]

    [...]

    Disabled by default: INTEGER_OVERFLOW is disabled by default. To
    enable it, you can use the --enable option to the cov-analyze
    command.

The example that follows shows a memory allocation where the size is
computed like TAINTED * sizeof(MUMBLE), where TAINTED is a "tainted
source", and the allocation's size is a "tainted sink".

Our model for g_malloc_n() uses __coverity_alloc(), which should provide
"tainted sink".

> making nmemb a tainted sink could be an interesting way to ensure that 
> untrusted data does not end up causing such a failure.
>
> Likewise, we should try making __bufwrite taint the buffer it is
> writing to; there's already a TODO for that but I never followed up on
> it.

__bufwrite() tells Coverity that the buf[len] bytes are overwritten with
unspecified data.  I'd expect that to taint the buffer already.
Peter Maydell Aug. 4, 2021, 8:43 a.m. UTC | #4
On Wed, 4 Aug 2021 at 09:35, Markus Armbruster <armbru@redhat.com> wrote:
>
> Paolo Bonzini <pbonzini@redhat.com> writes:
>
> > On 02/08/21 14:36, Peter Maydell wrote:
> >> Reviewed-by: Peter Maydell<peter.maydell@linaro.org>
> >> The real g_malloc_n() returns failure if the multiplication
> >> would overflow;
>
> Really?  Its documentation:
>
>     This function is similar to g_malloc(), allocating (n_blocks *
>     n_block_bytes) bytes, but care is taken to detect possible overflow
>     during multiplication.
>
> There's also g_try_malloc_n():
>
>     This function is similar to g_try_malloc(), allocating (n_blocks *
>     n_block_bytes) bytes, but care is taken to detect possible overflow
>     during multiplication.
>
> I read this as g_malloc_n() can return null only for zero size, and
> crashes on error, just like g_malloc_n().  g_try_malloc_n() behaves like
> g_try_malloc_n(), i.e. it returns null on failure.

Yeah, I misspoke -- I just meant to say "treats multiply overflow
like an allocation failure", not that it returns NULL.

> >>                 I guess Coverity currently doesn't have any
> >> warnings it generates as a result of assuming overflow
> >> might happen?
> >
> > I couldn't find any Coverity-specific way to detect overflow, but
>
> Does it need one?
>
> Quick peek at Coverity 2012.12 Checker Reference:
>
>     4.188. INTEGER_OVERFLOW

> The example that follows shows a memory allocation where the size is
> computed like TAINTED * sizeof(MUMBLE), where TAINTED is a "tainted
> source", and the allocation's size is a "tainted sink".

My point was that we *don't* want Coverity to report INTEGER_OVERFLOW
errors based on the way our g_malloc_n() model is written like this:
  __coverity_alloc__(nmemb * size)
That expression in our model *can* overflow. We know the real g_malloc_n()
cannot overflow, but we don't do anything to tell Coverity that, so it's
possible that (maybe in future) it will report false positives to us
based on analysis that assumes possible overflows in the multiplication.

thanks
-- PMM
diff mbox series

Patch

diff --git a/scripts/coverity-scan/model.c b/scripts/coverity-scan/model.c
index 1a5f39d2ae..2d384bdd79 100644
--- a/scripts/coverity-scan/model.c
+++ b/scripts/coverity-scan/model.c
@@ -178,13 +178,11 @@  uint8_t replay_get_byte(void)
 
 void *g_malloc_n(size_t nmemb, size_t size)
 {
-    size_t sz;
     void *ptr;
 
     __coverity_negative_sink__(nmemb);
     __coverity_negative_sink__(size);
-    sz = nmemb * size;
-    ptr = __coverity_alloc__(sz);
+    ptr = __coverity_alloc__(nmemb * size);
     __coverity_mark_as_uninitialized_buffer__(ptr);
     __coverity_mark_as_afm_allocated__(ptr, AFM_free);
     return ptr;
@@ -192,13 +190,11 @@  void *g_malloc_n(size_t nmemb, size_t size)
 
 void *g_malloc0_n(size_t nmemb, size_t size)
 {
-    size_t sz;
     void *ptr;
 
     __coverity_negative_sink__(nmemb);
     __coverity_negative_sink__(size);
-    sz = nmemb * size;
-    ptr = __coverity_alloc__(sz);
+    ptr = __coverity_alloc__(nmemb * size);
     __coverity_writeall0__(ptr);
     __coverity_mark_as_afm_allocated__(ptr, AFM_free);
     return ptr;
@@ -206,13 +202,10 @@  void *g_malloc0_n(size_t nmemb, size_t size)
 
 void *g_realloc_n(void *ptr, size_t nmemb, size_t size)
 {
-    size_t sz;
-
     __coverity_negative_sink__(nmemb);
     __coverity_negative_sink__(size);
-    sz = nmemb * size;
     __coverity_escape__(ptr);
-    ptr = __coverity_alloc__(sz);
+    ptr = __coverity_alloc__(nmemb * size);
     /*
      * Memory beyond the old size isn't actually initialized.  Can't
      * model that.  See Coverity's realloc() model