Assertion failure: result.index <= linear->length(), at js/src/vm/TypedArrayObject.cpp:5220 [OOBR]
Categories
(Core :: JavaScript: Standard Library, defect, P1)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox-esr115 | --- | unaffected |
| firefox-esr140 | --- | unaffected |
| firefox144 | --- | unaffected |
| firefox145 | --- | unaffected |
| firefox146 | --- | fixed |
People
(Reporter: sakura, Assigned: anba)
References
(Blocks 1 open bug, Regression)
Details
(4 keywords, Whiteboard: [client-bounty-form])
Attachments
(1 file)
Reproduce
- Clone the Firefox mirror from https://github.com/mozilla-firefox/firefox
- Run build command in the js/src directory of the firefox checkout:
mkdir fuzzbuild_OPT.OBJ && cd fuzzbuild_OPT.OBJ && ../configure --enable-address-sanitizer --disable-jemalloc --enable-debug --enable-optimize --disable-shared-js --enable-application=js --enable-gczeal && make -j64 - Run poc:
fuzzbuild_OPT.OBJ/dist/bin/js poc.js
Test SpiderMonkey commit hash: 75f89f7dee3f30c371af717da54ba8bbf046e5fd
Crash Stack Trace
--------------------------------------------------------------------------------
[1706037] Assertion failure: result.index <= linear->length(), at /home/sakura/gecko-dev/js/src/vm/TypedArrayObject.cpp:5220
#01: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x256e4e2]
#02: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1e01e8f]
#03: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1e01453]
#04: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1e18331]
#05: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1e00353]
#06: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1e04b91]
#07: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1e053cd]
#08: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1fe9eea]
#09: JS_ExecuteScript(JSContext*, JS::Handle<JSScript*>)[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1fea140]
#10: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1d5d6ad]
#11: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1d5ca16]
#12: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1cc2b6a]
#13: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1cb64a8]
#14: ???[/lib/x86_64-linux-gnu/libc.so.6 +0x29d90]
#15: __libc_start_main[/lib/x86_64-linux-gnu/libc.so.6 +0x29e40]
#16: ???[/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js +0x1c76dd9]
#17: ??? (???:???)
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==1706037==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5589a68f44fa bp 0x7ffd013fbca0 sp 0x7ffd013fbb90 T1706037)
==1706037==The signal is caused by a WRITE memory access.
==1706037==Hint: address points to the zero page.
#0 0x5589a68f44fa in MOZ_CrashSequence(void*, long) /home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/include/mozilla/Assertions.h:237:3
#1 0x5589a68f44fa in uint8array_fromBase64(JSContext*, unsigned int, JS::Value*) /home/sakura/gecko-dev/js/src/vm/TypedArrayObject.cpp:5220:3
#2 0x5589a6187e8e in CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::CallReason, JS::CallArgs const&) /home/sakura/gecko-dev/js/src/vm/Interpreter.cpp:490:13
#3 0x5589a6187452 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) /home/sakura/gecko-dev/js/src/vm/Interpreter.cpp:586:12
#4 0x5589a619e330 in js::CallFromStack(JSContext*, JS::CallArgs const&, js::CallReason) /home/sakura/gecko-dev/js/src/vm/Interpreter.cpp:658:10
#5 0x5589a619e330 in js::Interpret(JSContext*, js::RunState&) /home/sakura/gecko-dev/js/src/vm/Interpreter.cpp:3276:16
#6 0x5589a6186352 in js::RunScript(JSContext*, js::RunState&) /home/sakura/gecko-dev/js/src/vm/Interpreter.cpp:460:13
#7 0x5589a618ab90 in js::ExecuteKernel(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, js::AbstractFramePtr, JS::MutableHandle<JS::Value>) /home/sakura/gecko-dev/js/src/vm/Interpreter.cpp:851:13
#8 0x5589a618b3cc in js::Execute(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, JS::MutableHandle<JS::Value>) /home/sakura/gecko-dev/js/src/vm/Interpreter.cpp:884:10
#9 0x5589a636fee9 in ExecuteScript(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSScript*>, JS::MutableHandle<JS::Value>) /home/sakura/gecko-dev/js/src/vm/CompilationAndEvaluation.cpp:548:10
#10 0x5589a637013f in JS_ExecuteScript(JSContext*, JS::Handle<JSScript*>) /home/sakura/gecko-dev/js/src/vm/CompilationAndEvaluation.cpp:572:10
#11 0x5589a60e36ac in RunFile(JSContext*, char const*, _IO_FILE*, CompileUtf8, bool, bool) /home/sakura/gecko-dev/js/src/shell/js.cpp:1315:10
#12 0x5589a60e2a15 in Process(JSContext*, char const*, bool, FileKind) /home/sakura/gecko-dev/js/src/shell/js.cpp:2106:14
#13 0x5589a6048b69 in ProcessArgs(JSContext*, js::cli::OptionParser*) /home/sakura/gecko-dev/js/src/shell/js.cpp:12051:10
#14 0x5589a6048b69 in Shell(JSContext*, js::cli::OptionParser*) /home/sakura/gecko-dev/js/src/shell/js.cpp:12305:12
#15 0x5589a603c4a7 in main /home/sakura/gecko-dev/js/src/shell/js.cpp:12708:12
#16 0x7f4ec2a29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#17 0x7f4ec2a29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#18 0x5589a5ffcdd8 in _start (/home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/bin/js+0x1c76dd8) (BuildId: aa541a5979c2c6bc3b0eca2fc9cd1eb3)
==1706037==Register values:
rax = 0x0000000000000000 rbx = 0x00007f4ec273c200 rcx = 0x0000000000001464 rdx = 0x00007f4ec2c1b723
rdi = 0x00007f4ec2c1ca60 rsi = 0x0000000000000000 rbp = 0x00007ffd013fbca0 rsp = 0x00007ffd013fbb90
r8 = 0x0000000000000000 r9 = 0x0000000000000003 r10 = 0x00005589a86cb070 r11 = 0x0000000000000293
r12 = 0x0000000000000000 r13 = 0x00007ffd013fbbc0 r14 = 0x00007f4ec275a0a8 r15 = 0x0000251e73b62100
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV /home/sakura/gecko-dev/js/src/fuzzbuild_OPT.OBJ/dist/include/mozilla/Assertions.h:237:3 in MOZ_CrashSequence(void*, long)
==1706037==ABORTING
================================================================================
PoC
try {
var v3 = 'No error';
} catch (e) {}
v9 = v3;
try {
Uint8Array.fromBase64(v9);
} catch (e) {}
function fn4() {}
// Flags:
Updated•11 months ago
|
Updated•11 months ago
|
Comment 1•11 months ago
|
||
This assertion looks like it was added recently in bug 1994067, so maybe anba can take a look. Thanks.
| Assignee | ||
Comment 2•11 months ago
|
||
Updated•11 months ago
|
| Reporter | ||
Comment 3•11 months ago
|
||
- The fast-path loop in
FromBase64relies solely onalignedLength = length & ~0x3to decide whether another four-character chunk can be decoded. Once the slow path skips whitespace and executesindex = i,alignedLengthis not reduced, soindexmay move beyond the original string length yet still pass theindex < alignedLengthguard, resulting indecode4Chars(chars + index)being called (js/src/vm/TypedArrayObject.cpp:4755-4816). - The extra
decode4Charsinvocation reads directly fromchars[index + {0,1,2}], which allows an out-of-bounds access past the end of theJSLinearStringbuffer. If the stray bytes happen to form valid base64 digits, the decoded data is copied into the output buffer. - The function returns
Base64Result::Ok(read, …)withreadderived from the incorrectindex, triggeringMOZ_ASSERT(result.index <= linear->length());inUint8Array.fromBase64(js/src/vm/TypedArrayObject.cpp:5215-5221). Release builds omit the assertion, turning the bug into a controllable out-of-bounds read.
// js/src/vm/TypedArrayObject.cpp:4755-4816
size_t alignedLength = length & ~0x3;
while (canAppend(3) && index < alignedLength) {
uint32_t chunk = decode4Chars(chars + index);
if (MOZ_LIKELY(int32_t(chunk) >= 0)) {
decodeChunk(chunk);
index += 4;
continue;
}
CharT part[4];
size_t i = index;
size_t j = 0;
while (i < length && j < 4) {
auto ch = chars[i++];
if (mozilla::IsAsciiWhitespace(ch)) {
continue;
}
part[j++] = ch;
}
if (MOZ_LIKELY(j == 4)) {
uint32_t chunk = decode4Chars(part);
if (MOZ_LIKELY(int32_t(chunk) >= 0)) {
decodeChunk(chunk);
index = i; // index can advance past `length`
continue;
}
}
break;
}
Comment 4•11 months ago
|
||
A bounds-ish assertion doesn't always mean an out of bounds issue, but based on comment 3, it sounds like it could lead to that in this case, so I'll mark this sec-high.
| Assignee | ||
Comment 5•11 months ago
|
||
This can only read up to two characters after the end of the string. And the content of those characters can only be read when they happen to be valid Base64 characters.
Updated•11 months ago
|
Comment 6•11 months ago
|
||
Can you confirm, that this was caused by bug 1995626?
Updated•11 months ago
|
| Assignee | ||
Comment 7•11 months ago
|
||
Yes, it's a regression from bug 1995626.
Comment 9•11 months ago
|
||
Updated•11 months ago
|
Updated•11 months ago
|
Comment 10•11 months ago
|
||
We're lowering the severity to sec-moderate because this is limited to an OOBR, not a write, and of a very limited amount of constrained data that's unlikely to be useful in an attack escalation or data disclosure.
Updated•4 months ago
|
Description
•