Logic error and overflow in nsSegmentedBuffer causes underallocation and write beyond bounds (latent)
Categories
(Core :: XPCOM, defect, P3)
Tracking
()
People
(Reporter: mozillabugs, Assigned: nika)
Details
(Keywords: csectype-intoverflow, reporter-external, sec-moderate, Whiteboard: [adv-main113+r])
Attachments
(3 files, 1 obsolete file)
22.40 KB,
application/x-javascript
|
Details | |
3.61 KB,
application/x-javascript
|
Details | |
Bug 1820359 - Move precise max length limits from `nsSegmentedBuffer` to callers, r=#xpcom-reviewers
48 bytes,
text/x-phabricator-request
|
Details | Review |
nsSegmentedBuffer::AppendNewSegment()
(xpcom/io/nsSegmentedBuffer.cpp
) incorrectly checks its current size against its maximum allowed size, and nsSegmentedBuffer::GetSize()
uses 32 bit math. The first bug allows an oversized allocation to occur, which then invokes the second bug, causing overflow in nsSegmentedBuffer::GetSize()
. If other code were to trust nsSegmentedBuffer::GetSize()
to return the correct size by using its return value to allocate memory, then were to copy out the object's contents by calling nsSegmentedBuffer::GetSegment()
in a loop, it would write beyond bounds if the object contained > 0xffffffff
bytes of data.
I believe that this bug currently cannot be reached because searchfox says that nsSegmentedBuffer::AppendNewSegment()
is the only caller of nsSegmentedBuffer::GetSize()
.
The bugs are on line 24 of the .cpp file (which incorrectly tests against the object's current size instead of the requested new size) and on line 59 of the .h file (nsSegmentedBuffer::GetSize()
), which incorrectly uses 32-bit math.
(.cpp)
------
23: char* nsSegmentedBuffer::AppendNewSegment() {
24: if (GetSize() >= mMaxSize) {
25: return nullptr;
26: }
27: ...
54: char* seg = (char*)malloc(mSegmentSize);
55: if (!seg) {
56: return nullptr;
57: }
58: mSegmentArray[mLastSegmentIndex] = seg;
59: mLastSegmentIndex = ModSegArraySize(mLastSegmentIndex + 1);
60: return seg;
61: }
(.h)
------
59: inline uint32_t GetSize() { return GetSegmentCount() * mSegmentSize; }
Attached is a POC that shows the oversized allocation and subsequent overflow. Use the POC thusly:
-
Start with a built version of FF, not an installed one, because you will need to replace some JS files to create the chrome necessary to invoke
nsSegmentedBuffer::AppendNewSegment()
. -
Copy
toolbar.js
intodist/bin/browser/chrome/devtools/modules/devtools/client/netmonitor/src/components/toolsbar.js
. -
Copy
har-menu-utils.js
intodist/bin/browser/chrome/devtools/modules/devtools/client/netmonitor/src/har/har-menu-utils.js
. -
Start FF and open "tools/browser tools/web developer tools".
-
Click the "network settings" star icon, then wait a minute or so. (This step helps avoid spurious breakpoints). Now attach a debugger to FF.
-
Set a BP at the beginning of
nsSegmentednsSegmentedBuffer::AppendNewSegment()
and another onnsPipe::nsPipe()
on theMOZ_ALWAYS_SUCCEEDS
statement. -
Click the "network settings" star icon and select "netmonitor.context.exerciseabug".
-
When the BP in
nsPipe::nsPipe()
fires, examine argumentsaSegmentSize
andaSegmentCount
. If they are not0x80000000
and3
, respectively, proceed until you get those argument values. -
Doctor
mMaxAdvanceBufferSegmentCount
from1
to3
. This makes it possible to invoke the bug using this POC. -
Record the value of
&this->mBuffer
for later use. Proceed. -
When the BP on
nsSegmentedBuffer::AppendNewSegment()
fires, proceed untilthis
matches the address you recorded in step 10. When that happens, step over the call toGetSize()
and note what it returns. On the first BP, it should be0
. Note that this isn't really what line 24 should be checking for! It should instead be checking whether the current size, plus the size of the new segment, would exceedmMaxSize
. Proceed. -
You'll get another BP on
nsSegmentedBuffer::AppendNewSegment()
with a matchingthis
pointer. Again step overGetSize()
and notice that it returns0x80000000
. Notice also thatmSegmentSize
is0x80000000
. Proceed. -
You'll get a third BP on
nsSegmentedBuffer::AppendNewSegment()
with a matchingthis
pointer. Again step overGetSize()
and notice that it returns0
(!), and that theif
statement does not cause line 25 to be executed. This is becauseGetSize()
overflowed because it uses 32-bit math.
Reporter | ||
Comment 1•2 years ago
|
||
Updated•2 years ago
|
Updated•2 years ago
|
Updated•2 years ago
|
Comment 2•2 years ago
|
||
The severity field is not set for this bug.
:nika, could you have a look please?
For more information, please visit auto_nag documentation.
Assignee | ||
Comment 3•2 years ago
|
||
Previously this would be checked at the byte count level, which could
end up being less precise.
Updated•2 years ago
|
Assignee | ||
Updated•2 years ago
|
Assignee | ||
Updated•2 years ago
|
Comment 4•2 years ago
|
||
Landed: https://hg.mozilla.org/integration/autoland/rev/fd2a3531261bad2a4de38828e6499e7a8cd7081c
Backed out for causing remote failures in browser_navigationEvents.js:
https://hg.mozilla.org/integration/autoland/rev/9ce119b474d9e5b847417099211c20547d7ddd1c
Push with failure: https://treeherder.mozilla.org/jobs?repo=autoland&group_state=expanded&selectedTaskRun=MvZuyXG5SbugIsCaBAPgJQ.0&resultStatus=success%2Ctestfailed%2Cbusted%2Cexception&searchStr=linux%2C18.04%2Cx64%2Cwebrender%2Cdebug%2Cmochitests%2Ctest-linux1804-64-qr%2Fdebug-mochitest-remote%2Cremote&revision=fd2a3531261bad2a4de38828e6499e7a8cd7081c
Failure log: https://treeherder.mozilla.org/logviewer?job_id=409660337&repo=autoland
TEST-UNEXPECTED-FAIL | remote/cdp/test/browser/network/browser_navigationEvents.js | Received expected number of events - Got 3, expected 10
Followed by more failure lines.
Comment 5•2 years ago
|
||
Also puppeteer failures stem from this change: https://treeherder.mozilla.org/logviewer?job_id=409662642&repo=autoland&lineNumber=1903
TEST-UNEXPECTED-FAIL | Page.click should click the button (click.spec.js) | expected PASS
Assignee | ||
Comment 6•2 years ago
|
||
This means that the size limits are more accurately applied, as they can
operate on sub-segment precision.
Updated•2 years ago
|
Assignee | ||
Updated•2 years ago
|
Comment 7•2 years ago
|
||
Move precise max length limits from nsSegmentedBuffer
to callers, r=xpcom-reviewers,mccr8
https://hg.mozilla.org/integration/autoland/rev/9891ea31c16bb68c22388842ac007a7a7707754b
https://hg.mozilla.org/mozilla-central/rev/9891ea31c16b
Updated•2 years ago
|
Comment 8•2 years ago
|
||
The patch landed in nightly and beta is affected.
:nika, is this bug important enough to require an uplift?
- If yes, please nominate the patch for beta approval.
- If no, please set
status-firefox112
towontfix
.
For more information, please visit auto_nag documentation.
Assignee | ||
Comment 9•2 years ago
|
||
No, this bug doesn't need to be uplifted. This is unexploitable with the current implementation.
Updated•2 years ago
|
Updated•2 years ago
|
Updated•2 years ago
|
Updated•2 years ago
|
Updated•2 years ago
|
Updated•1 year ago
|
Updated•8 months ago
|
Description
•