Bug 29444 - gmon memory corruption due wrong calculation of required buffer size
Summary: gmon memory corruption due wrong calculation of required buffer size
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.38
: P2 minor
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-08-03 17:30 UTC by account disabled by myself since useless
Modified: 2023-03-07 04:30 UTC (History)
9 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
siddhesh: security-


Attachments
the patch (1.44 KB, patch)
2022-08-03 17:32 UTC, account disabled by myself since useless
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description account disabled by myself since useless 2022-08-03 17:30:56 UTC
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 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))`.

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 Bug 29438.

Another minor error seems a related typo in the calculation of `kcountsize`.
Comment 1 account disabled by myself since useless 2022-08-03 17:32:57 UTC
Created attachment 14253 [details]
the patch
Comment 2 account disabled by myself since useless 2022-08-03 20:10:42 UTC
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.
Comment 3 account disabled by myself since useless 2023-01-30 12:38:11 UTC
Please review the attached patch and apply. 
It just fixes an allocated buffer overrun issue, i.e. the memory corruption!
Comment 4 Adhemerval Zanella 2023-01-30 16:24:24 UTC
(In reply to Leo Yuriev from comment #3)
> Please review the attached patch and apply. 
> It just fixes an allocated buffer overrun issue, i.e. the memory corruption!

Patch reviews are done through libc-alpha email list, could you please sent the patch following the contribution guidelines [1]?

[1] https://sourceware.org/glibc/wiki/Contribution%20checklist
Comment 5 account disabled by myself since useless 2023-02-04 12:12:34 UTC
https://patchwork.sourceware.org/project/glibc/patch/20230204114138.5436-1-leo@yuriev.ru/
Comment 6 account disabled by myself since useless 2023-02-06 17:43:57 UTC
CVE-ID was requested via submission to VulDB.
Comment 7 account disabled by myself since useless 2023-02-06 19:29:20 UTC
CVE-2023-0687
https://vuldb.com/?id.220246
Comment 8 Ismail Donmez 2023-02-07 08:40:25 UTC
Will the glibc maintainers reject the assigned CVE? I don't see how this is exploitable.
Comment 9 Florian Weimer 2023-02-07 08:41:58 UTC
(In reply to Ismail Donmez from comment #8)
> Will the glibc maintainers reject the assigned CVE? I don't see how this is
> exploitable.

Agreed. I expect us to file a DISPUTE request with MITRE later today.
Comment 10 account disabled by myself since useless 2023-02-07 09:32:10 UTC
(In reply to Florian Weimer from comment #9)
> (In reply to Ismail Donmez from comment #8)
> > Will the glibc maintainers reject the assigned CVE? I don't see how this is
> > exploitable.
> 
> Agreed. I expect us to file a DISPUTE request with MITRE later today.

Yes, it is not exploitable in usual/common cases.

However, this bug can be exploited in rare specific scenarios when monstartup() and moncontrol() are called explicitly to collect statistics from a part of modules compiled with the corresponding options (nonetheless, I cannot disclose information about affected software either show the exploit).

During submission for CVE-ID, I noted about that the bug could be exploited only when gmon activated, but such note is not included into CVE for now.
Comment 11 Siddhesh Poyarekar 2023-02-07 15:00:55 UTC
The only way to induce this buffer overflow is to modify the callgraph of an application that is built with these options(In reply to Leo Yuriev from comment #10)
> (In reply to Florian Weimer from comment #9)
> > (In reply to Ismail Donmez from comment #8)
> > > Will the glibc maintainers reject the assigned CVE? I don't see how this is
> > > exploitable.
> > 
> > Agreed. I expect us to file a DISPUTE request with MITRE later today.
> 
> Yes, it is not exploitable in usual/common cases.
> 
> However, this bug can be exploited in rare specific scenarios when
> monstartup() and moncontrol() are called explicitly to collect statistics
> from a part of modules compiled with the corresponding options (nonetheless,
> I cannot disclose information about affected software either show the
> exploit).

The inputs that induce this buffer overflow are basically addresses of the running application that is built with gmon enabled *and* with the patch for bug 29438, so it's basically trusted input or input that needs an actual security flaw to be compromised or controlled.  The bug needs to be fixed, but there's no security issue here.
Comment 12 account disabled by myself since useless 2023-02-07 15:57:32 UTC
(In reply to Siddhesh Poyarekar from comment #11)
> The inputs that induce this buffer overflow are basically addresses of the
> running application that is built with gmon enabled *and* with the patch for
> bug 29438, so it's basically trusted input or input that needs an actual
> security flaw to be compromised or controlled.  The bug needs to be fixed,
> but there's no security issue here.

The patch for Bug 29438 not needed to exploitation, but gmon must be enabled.
Initially I discovered this issue while working on Bug 29438.
But later it was re-noticed in another environment, where it is exploitable.

Briefly:
1) Prerequirement:
 - a web service users gmon to collect statistics on the performance of its module(s);
 - OR an attacker can enable the collection of such statistics;
2) By manipulating requests, the attacker achieves a function call that is at the end of the monitored addresses and is usually never called. T
3) The attacker continue an attack using memory corruption.

Yes, this is a very specific scenario with a very low probability of exploitation.
However, we reproduced it in a prepared environment.
Comment 13 Siddhesh Poyarekar 2023-02-07 16:01:01 UTC
(In reply to Leo Yuriev from comment #12)
> 2) By manipulating requests, the attacker achieves a function call that is
> at the end of the monitored addresses and is usually never called. T

My point is that this step above needs specific knowledge of the address space *and* control over execution to make this happen.  Without such control, there's no exploitation vector.
Comment 14 account disabled by myself since useless 2023-02-08 11:18:46 UTC
(In reply to Siddhesh Poyarekar from comment #13)
> (In reply to Leo Yuriev from comment #12)
> > 2) By manipulating requests, the attacker achieves a function call that is
> > at the end of the monitored addresses and is usually never called.
> 
> My point is that this step above needs specific knowledge of the address
> space *and* control over execution to make this happen.  Without such
> control, there's no exploitation vector.

There is the effect of a "critical mass" of vulnerabilities - when exploitation is possible only if there is a set of vulnerabilities, but not one or even two.

In my case, it took a couple more vulnerabilities in the application code to exploit this bug. However, without this issue, exploiting is also impossible.

My point is: we cannot assume all use cases and scenarios for a widely used library, therefore a use-after-free, off-by-one, buffer overflow, memory corruption, using/reading uninitialized, race condition, etc... in a such library is always a CVE.
No options.
Comment 15 Siddhesh Poyarekar 2023-02-08 11:51:07 UTC
(In reply to Leo Yuriev from comment #14)
> There is the effect of a "critical mass" of vulnerabilities - when
> exploitation is possible only if there is a set of vulnerabilities, but not
> one or even two.
> 
> In my case, it took a couple more vulnerabilities in the application code to
> exploit this bug. However, without this issue, exploiting is also impossible.

Please explain how, remember that the input has to be *untrusted* for it to be considered a security issue.

> My point is: we cannot assume all use cases and scenarios for a widely used
> library, therefore a use-after-free, off-by-one, buffer overflow, memory
> corruption, using/reading uninitialized, race condition, etc... in a such
> library is always a CVE.
> No options.

You're free to consider every memory or synchronization bug in libraries you use as a security issue and deal with it as such.  In the glibc project we have well defined rules as to what we consider security issues:

https://sourceware.org/glibc/wiki/Security%20Process
Comment 16 account disabled by myself since useless 2023-02-08 12:03:36 UTC
Sorry, but I don't have time for useless discuss.
Comment 17 Siddhesh Poyarekar 2023-02-08 13:00:47 UTC
Keeping the bug open since we obviously want to fix it.
Comment 18 Salvatore Bonaccorso 2023-02-09 22:05:33 UTC
Florian,

Regarding the DISPUTE (or reject?) for the CVE as mentioned in https://sourceware.org/bugzilla/show_bug.cgi?id=29444#c9 : 

Schould the request actually go to VulDB instead of MITRE, as
VulDB was the assigning CNA?

Regards,
Salvatore
Comment 19 Siddhesh Poyarekar 2023-02-09 22:27:21 UTC
I already submitted the rejection request to Mitre.  VulDB has a login barrier to even view the CVE, so I didn't bother with it.  If Mitre refuses to handle it I'll retry with vuldb.
Comment 20 account disabled by myself since useless 2023-02-23 07:36:27 UTC
Fixed by commit 801af9fafd4689337ebf27260aa115335a0cb2bc
https://sourceware.org/git/?p=glibc.git;a=commit;h=801af9fafd4689337ebf27260aa115335a0cb2bc

Thanks to DJ Delorie <dj@redhat.com>.

Please close as FIXED.
Comment 21 dj@redhat.com 2023-02-23 18:13:28 UTC
Fixed in rawhide.
Comment 22 lin zhuorong 2023-03-04 10:44:05 UTC
(In reply to account disabled by myself since useless from comment #20)
> Fixed by commit 801af9fafd4689337ebf27260aa115335a0cb2bc
> https://sourceware.org/git/?p=glibc.git;a=commit;
> h=801af9fafd4689337ebf27260aa115335a0cb2bc
> 
> Thanks to DJ Delorie <dj@redhat.com>.
> 
> Please close as FIXED.

This fix calls ROUNDUP to address memory alignment and does not limit the buffer size to the specified range.
Comment 23 dj@redhat.com 2023-03-07 04:30:23 UTC
Could you be more specific?  (In reply to lin zhuorong from comment #22)
> This fix calls ROUNDUP to address memory alignment and does not limit the
> buffer size to the specified range.

Could you be more specific?  The fix increases the buffer size enough to prevent a partial record from being written past the end of the allocated buffer.  The memory alignment was already in there.  Which range should the buffer size be limited to?