[PATCH v2] gmon: Fix allocated buffer overflow (bug 2944)

Carlos O'Donell carlos@redhat.com
Tue Feb 21 21:10:45 GMT 2023


On 2/14/23 00:59, DJ Delorie via Libc-alpha wrote:
> 
> Not getting any feedback from my review-with-questions, I'm posting a
> patch that assumes I'm right about the change I thought Leonid's patch
> needed.  Fight!  ;-)

LGTM. You can keep my Reviewed-by: if you make only the spelling and subject fix.

Please do the following:
- Post a v3 with my Reviewed-by: included.
- Push v3.
- Mark v2 superseded in patchwork.

Thank you!

Reviewed-by: Carlos O'Donell <carlos@redhat.com>


> From f7fddb025720d4e318fe5425f5a3235e73a13282 Mon Sep 17 00:00:00 2001
> From: "Леонид Юрьев (Leonid Yuriev)" <leo@yuriev.ru>
> Date: Sat, 4 Feb 2023 14:41:38 +0300
> Subject: gmon: Fix allocated buffer overflow (bug 2944)

s/bug 2944/bug 29444/g

> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
> 
> The `__monstartup()` allocates a buffer used to store all the data
> accumulated by the monitor.
> 
> The size of this buffer depends on the size of the internal structures
> used and the address range for which the monitor is activated, as well
> as on the maximum density of call instuctions and/or callable functions

s/instuctions/instructions/g

> that could be potentially on a segment of executable code.
> 
> In particular a hash table of arcs is placed at the end of this buffer.
> The size of this hash table is calculated in bytes as
>    p->fromssize = p->textsize / HASHFRACTION;
> 
> but actually should be
>    p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms));

OK. Agreed. The size must be rounded to the size of the arc indices.

> 
> This results in writing beyond the end of the allocated buffer when an
> added arc corresponds to a call near from the end of the monitored
> address range, since `_mcount()` check the incoming caller address for
> monitored range but not the intermediate result hash-like index that
> uses to write into the table.
> 
> It should be noted that when the results are output to `gmon.out`, the
> table is read to the last element calculated from the allocated size in
> bytes, so the arcs stored outside the buffer boundary did not fall into
> `gprof` for analysis. Thus this "feature" help me to found this bug
> during working with https://sourceware.org/bugzilla/show_bug.cgi?id=29438
> 
> Just in case, I will explicitly note that the problem breaks the
> `make test t=gmon/tst-gmon-dso` added for Bug 29438.
> There, the arc of the `f3()` call disappears from the output, since in
> the DSO case, the call to `f3` is located close to the end of the
> monitored range.
> 
> Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
> 
> Another minor error seems a related typo in the calculation of
> `kcountsize`, but since kcounts are smaller than froms, this is
> actually to align the p->froms data.

OK.

> 
> Co-authored-by: DJ Delorie <dj@redhat.com>
> 
> diff --git a/gmon/gmon.c b/gmon/gmon.c
> index dee64803ad..bf76358d5b 100644
> --- a/gmon/gmon.c
> +++ b/gmon/gmon.c
> @@ -132,6 +132,8 @@ __monstartup (u_long lowpc, u_long highpc)
>    p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
>    p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
>    p->textsize = p->highpc - p->lowpc;
> +  /* This looks like a typo, but it's here to align the p->froms
> +     section.  */
>    p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));

OK. Agreed.

>    p->hashfraction = HASHFRACTION;
>    p->log_hashfraction = -1;
> @@ -142,7 +144,7 @@ __monstartup (u_long lowpc, u_long highpc)
>  	 instead of integer division.  Precompute shift amount. */
>        p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
>    }
> -  p->fromssize = p->textsize / HASHFRACTION;
> +  p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms));

OK. Agreed, the size you want is the rounded up size during __monstartup() calculation.
- Eventually we call calloc later in the function to allocate this size.

In other places we compute like this:
268   from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
- So it's expected that the allocations are multiples of sizeof(*p->froms).


>    p->tolimit = p->textsize * ARCDENSITY / 100;
>    if (p->tolimit < MINARCS)
>      p->tolimit = MINARCS;
> 

-- 
Cheers,
Carlos.



More information about the Libc-alpha mailing list