AddressSanitizer: Crash [@ bool InflateUTF8ToUTF16] or Assertion failure: mRangeStart <= mPtr, at dist/include/mozilla/RangedPtr.h:52
Categories
(Core :: MFBT, defect)
Tracking
()
People
(Reporter: gkw, Assigned: arai)
References
(Blocks 1 open bug)
Details
(5 keywords, Whiteboard: [jsbugmon:][adv-main66+][adv-esr60.6+])
Crash Data
Attachments
(5 files)
|
2.46 KB,
text/plain
|
Details | |
|
3.74 KB,
text/plain
|
Details | |
|
45.81 KB,
application/octet-stream
|
Details | |
|
9.75 MB,
application/octet-stream
|
Details | |
|
856 bytes,
patch
|
Waldo
:
review+
RyanVM
:
approval-mozilla-beta+
RyanVM
:
approval-mozilla-esr60+
abillings
:
sec-approval+
|
Details | Diff | Splinter Review |
The following testcase crashes on mozilla-central revision 024bef408a88 (build with AddressSanitizer on and --enable-more-deterministic, run with --fuzzing-safe --no-threads --no-baseline --no-ion w134-out.wrapper w134-out.wasm):
The testcase unfortunately is several GB in size so just attaching the stack trace in the hopes that it would suffice.
Backtrace:
AddressSanitizer:DEADLYSIGNAL
==21059==ERROR: AddressSanitizer: SEGV on unknown address 0x7f591259c800 (pc 0x56174bdb0084 bp 0x7ffca75b68d0 sp 0x7ffca75b67c0 T0)
==21059==The signal is caused by a READ memory access.
#0 0x56174bdb0083 in bool InflateUTF8ToUTF16<(OnUTF8Error)2, InflateUTF8StringHelper<(OnUTF8Error)2, JS::TwoByteCharsZ, JS::UTF8Chars>(JSContext*, JS::UTF8Chars, unsigned long*)::{lambda(char16_t)#1}, JS::UTF8Chars>(JSContext*, JS::UTF8Chars, InflateUTF8StringHelper<(OnUTF8Error)2, JS::TwoByteCharsZ, JS::UTF8Chars>(JSContext*, JS::UTF8Chars, unsigned long*)::{lambda(char16_t)#1}) js/src/vm/CharacterEncoding.cpp:292:27
#1 0x56174bdb0083 in JS::TwoByteCharsZ InflateUTF8StringHelper<(OnUTF8Error)2, JS::TwoByteCharsZ, JS::UTF8Chars>(JSContext*, JS::UTF8Chars, unsigned long*) js/src/vm/CharacterEncoding.cpp:436
#2 0x56174bdf1401 in CompileUtf8(JSContext*, JS::ReadOnlyCompileOptions const&, char const*, unsigned long, JS::MutableHandle<JSScript*>) js/src/vm/CompilationAndEvaluation.cpp:78:7
#3 0x56174bdf2137 in JS::CompileUtf8File(JSContext*, JS::ReadOnlyCompileOptions const&, _IO_FILE*, JS::MutableHandle<JSScript*>) js/src/vm/CompilationAndEvaluation.cpp:135:10
#4 0x56174ba6389d in RunFile(JSContext*, char const*, _IO_FILE*, CompileUtf8, bool) js/src/shell/js.cpp:881:12
/snip
For detailed crash information, see attachment.
Setting s-s because this involves ASan.
| Reporter | ||
Comment 1•7 years ago
|
||
| Reporter | ||
Comment 2•7 years ago
|
||
Not sure if this is wasm-specific or if it's related to bug 1523440? :arai/:lth, any thoughts?
| Reporter | ||
Comment 3•7 years ago
|
||
Tested with 64-bit debug shell compiled with --enable-more-deterministic on m-c rev 024bef408a88
| Reporter | ||
Updated•7 years ago
|
| Reporter | ||
Comment 4•7 years ago
|
||
I've tested and I think the patch in bug 1523440 comment 4 does not fix at least the assert.
Comment 5•7 years ago
|
||
What's wasm-specific here? Nothing, from what I can tell.
| Reporter | ||
Comment 6•7 years ago
|
||
Let's try these steps to reproduce:
1) Extract the seed using: tar xvjf seed.tar.bz2
2) Download binaryen v64: wget https://github.com/WebAssembly/binaryen/releases/download/version_64/binaryen-version_64-x86_64-linux.tar.gz
3) Generate the wasm and wrapper files: binaryen-version_64/wasm-opt w134-out.txt-binaryen-v64-seed --translate-to-fuzz --disable-simd --output out.wasm --emit-js-wrapper=wrapper.js
4) Compile: AR=ar sh ./configure --enable-debug --enable-more-deterministic --with-ccache --enable-gczeal --enable-debug-symbols --disable-tests --disable-cranelift
5) Run using the js shell: ./js --fuzzing-safe --no-threads --no-baseline --no-ion wrapper.js out.wasm
Due to the large size, step 3 took 1 - 1.5 hours to run while step 5 takes ~20s. SSDs and a fast machine is recommended.
I could then get it to assert.
| Assignee | ||
Comment 7•7 years ago
|
||
unfortunately, step 3 doesn't finish on my linux VM (has 8GB RAM, but OOM and killed)
if you know the content of memory between src.mStart.mPtr and src.mEnd.mPtr, that will help.
(I could setup another linux box tho, I don't have vacant SSD right now)
| Reporter | ||
Comment 8•7 years ago
|
||
I dug more and realised only the wrapper.js was needed, so I compressed it using tar cvJf and attached it here.
Will try and reduce more but not sure Lithium is being as effective as normal cases.
| Assignee | ||
Comment 9•7 years ago
|
||
Thanks! reproduced locally.
and turns out that it's integer overflow (not specific to WASM).
template <typename T>
class RangedPtr {
...
T& operator[](int aIndex) const {
MOZ_ASSERT(size_t(aIndex > 0 ? aIndex : -aIndex) <= size_t(-1) / sizeof(T));
return *create(mPtr + aIndex);
}
template <OnUTF8Error ErrorAction, typename OutputFn, class InputCharsT>
static bool InflateUTF8ToUTF16(JSContext* cx, const InputCharsT src,
OutputFn dst) {
size_t srclen = src.length();
for (uint32_t i = 0; i < srclen; i++) {
uint32_t v = uint32_t(src[i]);
where i = aIndex = 0x80000000.
Waldo, can I have your opinion how to fix this?
can we have unsigned int variant of RangedPtr::operator[] ?
| Reporter | ||
Comment 10•7 years ago
|
||
Thanks Arai-san!
I checked that it goes back to prior to m-c rev bcacb5692ad9 and hence prior to Jan 2015.
| Reporter | ||
Updated•7 years ago
|
Updated•7 years ago
|
Comment 11•7 years ago
|
||
Comment 12•7 years ago
|
||
I don't think you need a separate variant. Just make this function take ptrdiff_t.
(Now technically this would still be a problem if the array being ranged over occupied more than half of memory and elements were byte-sized, but. ptrdiff_t is what the standard uses for this, and it's really the best we can do.)
| Assignee | ||
Comment 13•7 years ago
|
||
Thanks!
replaced int with ptrdiff_t.
confirmed it doesn't crash with the testcase above, but just hit SyntaxError.
../tmp/wrapper.js:50331649:0 SyntaxError: missing } after catch block
../tmp/wrapper.js:50331648:12 note: { opened at line 50331648, column 12
This patch doesn't contain testcase, given it needs to be 2+ GB and takes 10+ minutes on debug build :P
Updated•7 years ago
|
Updated•7 years ago
|
| Assignee | ||
Comment 14•7 years ago
|
||
Comment on attachment 9041423 [details] [diff] [review]
Use ptrdiff_t instead in RangedPtr.
Security Approval Request
How easily could an exploit be constructed based on the patch?
Technically easy, but not so much in practice.
this requires 2GB+ source code to be downloaded and parsed before hitting it, that should take much time.
Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?
Yes
Which older supported branches are affected by this flaw?
all
If not all supported branches, which bug introduced the flaw?
Do you have backports for the affected branches?
Yes
If not, how different, hard to create, and risky will they be?
How likely is this patch to cause regressions; how much testing does it need?
less likely. It doesn't change the behavior for correct case, and fixes the wrong case (that overflow happened).
This patch doesn't contain testcase given it requires 2GB+ file, but manually testing it with the files in this bug should be sufficient.
| Assignee | ||
Comment 15•7 years ago
|
||
to be clear, the same code had existed before bug 662001, but moved to mfbt at that point.
| Assignee | ||
Updated•7 years ago
|
Comment 16•7 years ago
|
||
sec-approval+ for trunk. We'll want beta and ESR60 patches made and nominated as well.
Updated•7 years ago
|
| Assignee | ||
Comment 17•7 years ago
|
||
Comment on attachment 9041423 [details] [diff] [review]
Use ptrdiff_t instead in RangedPtr.
Beta/Release Uplift Approval Request
Feature/Bug causing the regression
User impact if declined
Possible out-of-bound access in JS parsing, and memory data leak from JavaScript error message.
Is this code covered by automated tests?
No
Has the fix been verified in Nightly?
No
Needs manual test from QE?
Yes
If yes, steps to reproduce
- Download and extract debug build of JS shell
- Download and extract file in comment #8
- Move files from step 1 and 2 in the same directory
- Run
./js --fuzzing-safe --no-threads --no-baseline --no-ion wrapper.js - Wait for several minutes
- Confirm it throws
SyntaxError, instead of crash
List of other uplifts needed
None
Risk to taking this patch
Low
Why is the change risky/not risky? (and alternatives if risky)
It doesn't change the behavior for correct case, and fixes the wrong case (that overflow happened).
String changes made/needed
None
ESR Uplift Approval Request
If this is not a sec:{high,crit} bug, please state case for ESR consideration
it's sec-high
User impact if declined
Possible out-of-bound access in JS parsing, and memory data leak from JavaScript error message.
Fix Landed on Version
not yet, will be 67
Risk to taking this patch
Low
Why is the change risky/not risky? (and alternatives if risky)
It doesn't change the behavior for correct case, and fixes the wrong case (that overflow happened).
String or UUID changes made by this patch
None
| Assignee | ||
Comment 18•7 years ago
|
||
The same patch applies to beta and esr60 branches
| Assignee | ||
Comment 19•7 years ago
|
||
Comment 20•7 years ago
|
||
Updated•7 years ago
|
Updated•7 years ago
|
Comment 21•7 years ago
|
||
Comment 22•7 years ago
|
||
| uplift | ||
Comment 23•7 years ago
|
||
Updated•7 years ago
|
Comment 24•7 years ago
|
||
Comment 25•7 years ago
|
||
| uplift | ||
Updated•7 years ago
|
Comment 26•7 years ago
|
||
Confirming this issue as verified fixed with 60.6.0esr(20190313091946) on Ubuntu 16.04x64.
Updated•7 years ago
|
Updated•6 years ago
|
Updated•6 years ago
|
Description
•