Closed Bug 1437481 Opened 4 years ago Closed 4 years ago

AddressSanitizer: heap-use-after-free [@ JSScript::strict] with READ of size 6 with wasm and async

Categories

(Core :: JavaScript Engine, defect)

x86_64
Linux
defect
Not set
critical

Tracking

()

RESOLVED FIXED
mozilla60
Tracking Status
firefox-esr52 --- unaffected
firefox58 --- unaffected
firefox59 --- unaffected
firefox60 --- fixed

People

(Reporter: decoder, Assigned: bbouvier)

References

(Blocks 1 open bug)

Details

(6 keywords, Whiteboard: [jsbugmon:][Nightly only])

Attachments

(1 file)

The following testcase crashes on mozilla-central revision 2b7d42d527af (build with --enable-posix-nspr-emulation --enable-valgrind --enable-gczeal --disable-tests --disable-profiling --disable-debug --enable-address-sanitizer --disable-jemalloc --enable-optimize=-O2, run with --fuzzing-safe --cpu-count=2):

try { 
  (async function f() {})([], 1);
  const Module = WebAssembly.Module;
  const Instance = WebAssembly.Instance;
  const m1 = new Module(wasmTextToBinary(`(module (func $f) (export "f" $f))`));
  const m2 = new Module(wasmTextToBinary(`(module (import "a" "f") (func $f) (export "g" $f))`));
  var i1 = new Instance(m1);
  var i2 = new Instance(m2, {a:i1.exports});
  var g = i2.exports.g;
  (async function f() {
    var inner = (function testmath() {
      return g.caller;
    })();
  })([], 1);
} catch(exc) {}


Backtrace:

==20097==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300001bd36 at pc 0x0000014a89da bp 0x7ffd3ed51380 sp 0x7ffd3ed51378
READ of size 6 at 0x60300001bd36 thread T0
    #0 0x14a89d9 in JSScript::strict() const js/src/jsscript.h:1319:16
    #1 0x14a89d9 in JSFunction::strict() const js/src/jsfun.h:277
    #2 0x14a89d9 in IsSloppyNormalFunction(JSFunction*) js/src/jsfun.cpp:138
    #3 0x1407672 in CallerRestrictions(JSContext*, JS::Handle<JSFunction*>) js/src/jsfun.cpp:248:10
    #4 0x1407672 in CallerGetterImpl(JSContext*, JS::CallArgs const&) js/src/jsfun.cpp:274
    #5 0x14ace2c in bool JS::CallNonGenericMethod<&(IsFunction(JS::Handle<JS::Value>)), &(CallerGetterImpl(JSContext*, JS::CallArgs const&))>(JSContext*, JS::CallArgs const&) js/CallNonGenericMethod.h:100:16
    #6 0x14ace2c in CallerGetter(JSContext*, unsigned int, JS::Value*) js/src/jsfun.cpp:331
    #7 0x84894e in js::CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) js/src/jscntxtinlines.h:291:15
    #8 0x84894e in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) js/src/vm/Interpreter.cpp:473
    #9 0x84a9ed in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) js/src/vm/Interpreter.cpp:541:10
    #10 0x84a9ed in js::CallGetter(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::MutableHandle<JS::Value>) js/src/vm/Interpreter.cpp:656
    #11 0x18d3d77 in CallGetter(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, JS::Handle<js::Shape*>, JS::MutableHandle<JS::Value>) js/src/vm/NativeObject.cpp:2145:16
    #12 0x18d3d77 in bool GetExistingProperty<(js::AllowGC)1>(JSContext*, js::MaybeRooted<JS::Value, (js::AllowGC)1>::HandleType, js::MaybeRooted<js::NativeObject*, (js::AllowGC)1>::HandleType, js::MaybeRooted<js::Shape*, (js::AllowGC)1>::HandleType, js::MaybeRooted<JS::Value, (js::AllowGC)1>::MutableHandleType) js/src/vm/NativeObject.cpp:2198
    #13 0x18d3d77 in bool NativeGetPropertyInline<(js::AllowGC)1>(JSContext*, js::MaybeRooted<js::NativeObject*, (js::AllowGC)1>::HandleType, js::MaybeRooted<JS::Value, (js::AllowGC)1>::HandleType, js::MaybeRooted<jsid, (js::AllowGC)1>::HandleType, IsNameLookup, js::MaybeRooted<JS::Value, (js::AllowGC)1>::MutableHandleType) js/src/vm/NativeObject.cpp:2401
    #14 0x18d3d77 in js::NativeGetProperty(JSContext*, JS::Handle<js::NativeObject*>, JS::Handle<JS::Value>, JS::Handle<jsid>, JS::MutableHandle<JS::Value>) js/src/vm/NativeObject.cpp:2437
    #15 0x853b0f in js::GetProperty(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, JS::Handle<jsid>, JS::MutableHandle<JS::Value>) js/src/vm/NativeObject.h:1630:12
    #16 0x853b0f in js::GetProperty(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, js::PropertyName*, JS::MutableHandle<JS::Value>) js/src/jsobj.h:822
    #17 0x853b0f in js::GetProperty(JSContext*, JS::Handle<JS::Value>, JS::Handle<js::PropertyName*>, JS::MutableHandle<JS::Value>) js/src/vm/Interpreter.cpp:4405
    #18 0x834f43 in GetPropertyOperation(JSContext*, js::InterpreterFrame*, JS::Handle<JSScript*>, unsigned char*, JS::MutableHandle<JS::Value>, JS::MutableHandle<JS::Value>) js/src/vm/Interpreter.cpp:219:12
    #19 0x834f43 in Interpret(JSContext*, js::RunState&) js/src/vm/Interpreter.cpp:2815
    #20 0x818016 in js::RunScript(JSContext*, js::RunState&) js/src/vm/Interpreter.cpp:423:12
    #21 0x848d35 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) js/src/vm/Interpreter.cpp:495:15
    #22 0x849ac2 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) js/src/vm/Interpreter.cpp:541:10
    #23 0x196bf49 in js::CallSelfHostedFunction(JSContext*, JS::Handle<js::PropertyName*>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) js/src/vm/SelfHosting.cpp:1736:12
    #24 0x16d939e in AsyncFunctionResume(JSContext*, JS::Handle<js::PromiseObject*>, JS::Handle<JS::Value>, ResumeKind, JS::Handle<JS::Value>) js/src/vm/AsyncFunction.cpp:191:10
    #25 0x16d82f6 in AsyncFunctionStart(JSContext*, JS::Handle<js::PromiseObject*>, JS::Handle<JS::Value>) js/src/vm/AsyncFunction.cpp:204:12
    #26 0x16d82f6 in WrappedAsyncFunction(JSContext*, unsigned int, JS::Value*) js/src/vm/AsyncFunction.cpp:90
    #27 0x84894e in js::CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) js/src/jscntxtinlines.h:291:15
[...]
    #41 0x463178 in _start (dist/bin/js+0x463178)

0x60300001bd36 is located 6 bytes inside of 32-byte region [0x60300001bd30,0x60300001bd50)
freed by thread T0 here:
    #0 0x50e6a0 in __interceptor_free compiler-rt/lib/asan/asan_malloc_linux.cc:38
    #1 0x13ba903 in js_free(void*) js/Utility.h:418:5
    #2 0x13ba903 in js::SystemAllocPolicy::free_(void*) js/src/jsalloc.h:47
    #3 0x13ba903 in mozilla::detail::VectorImpl<js::wasm::SymbolicAccess, 0ul, js::SystemAllocPolicy, false>::growTo(mozilla::Vector<js::wasm::SymbolicAccess, 0ul, js::SystemAllocPolicy>&, unsigned long) mozilla/Vector.h:147
    #4 0x13ba903 in mozilla::Vector<js::wasm::SymbolicAccess, 0ul, js::SystemAllocPolicy>::growStorageBy(unsigned long) mozilla/Vector.h:1054
    #5 0x13b7a99 in bool mozilla::Vector<js::wasm::SymbolicAccess, 0ul, js::SystemAllocPolicy>::append<js::wasm::SymbolicAccess&>(js::wasm::SymbolicAccess&) mozilla/Vector.h:1409:9
    #6 0x13b7a99 in js::jit::AssemblerShared::append(js::wasm::SymbolicAccess) js/src/jit/shared/Assembler-shared.h:1001
    #7 0x13b7a99 in js::jit::Assembler::mov(js::wasm::SymbolicAddress, js::jit::Register) js/src/jit/x64/Assembler-x64.h:926
    #8 0x1328814 in js::jit::MacroAssembler::call(js::wasm::SymbolicAddress) js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp:548:5
    #9 0x1e92c0c in GenerateOldTrapExit(js::jit::MacroAssembler&, js::wasm::Trap, js::jit::Label*, js::wasm::CallableOffsets*) js/src/wasm/WasmStubs.cpp:1372:5
    #10 0x1e92c0c in js::wasm::GenerateStubs(js::wasm::ModuleEnvironment const&, mozilla::Vector<js::wasm::FuncImport, 0ul, js::SystemAllocPolicy> const&, mozilla::Vector<js::wasm::FuncExport, 0ul, js::SystemAllocPolicy> const&, js::wasm::CompiledCode*) js/src/wasm/WasmStubs.cpp:1742
    #11 0x1d89345 in js::wasm::ModuleGenerator::finish(js::wasm::ShareableBytes const&) js/src/wasm/WasmGenerator.cpp:961:10
    #12 0x1d62b0a in js::wasm::ModuleGenerator::finishModule(js::wasm::ShareableBytes const&) js/src/wasm/WasmGenerator.cpp:983:37
    #13 0x1d55aa4 in js::wasm::CompileBuffer(js::wasm::CompileArgs const&, js::wasm::ShareableBytes const&, mozilla::UniquePtr<char [], JS::FreePolicy>*) js/src/wasm/WasmCompile.cpp:441:12
    #14 0x1df02be in js::WasmModuleObject::construct(JSContext*, unsigned int, JS::Value*) js/src/wasm/WasmJS.cpp:874:27
    #15 0x84a1a9 in js::CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) js/src/jscntxtinlines.h:291:15
[...]
    #29 0x7fb7f069582f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

previously allocated by thread T0 here:
    #0 0x50e9e8 in __interceptor_malloc /srv/repos/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:52
    #1 0x13ba843 in js_malloc(unsigned long) js/Utility.h:387:12
    #2 0x13ba843 in js::wasm::SymbolicAccess* js_pod_malloc<js::wasm::SymbolicAccess>(unsigned long) js/Utility.h:577
    #3 0x13ba843 in js::wasm::SymbolicAccess* js::SystemAllocPolicy::maybe_pod_malloc<js::wasm::SymbolicAccess>(unsigned long) js/src/jsalloc.h:37
    #4 0x13ba843 in js::wasm::SymbolicAccess* js::SystemAllocPolicy::pod_malloc<js::wasm::SymbolicAccess>(unsigned long) js/src/jsalloc.h:42
    #5 0x13ba843 in mozilla::detail::VectorImpl<js::wasm::SymbolicAccess, 0ul, js::SystemAllocPolicy, false>::growTo(mozilla::Vector<js::wasm::SymbolicAccess, 0ul, js::SystemAllocPolicy>&, unsigned long) mozilla/Vector.h:137
    #6 0x13ba843 in mozilla::Vector<js::wasm::SymbolicAccess, 0ul, js::SystemAllocPolicy>::growStorageBy(unsigned long) mozilla/Vector.h:1054
    #7 0x13b7a99 in bool mozilla::Vector<js::wasm::SymbolicAccess, 0ul, js::SystemAllocPolicy>::append<js::wasm::SymbolicAccess&>(js::wasm::SymbolicAccess&) mozilla/Vector.h:1409:9
    #8 0x13b7a99 in js::jit::AssemblerShared::append(js::wasm::SymbolicAccess) js/src/jit/shared/Assembler-shared.h:1001
    #9 0x13b7a99 in js::jit::Assembler::mov(js::wasm::SymbolicAddress, js::jit::Register) js/src/jit/x64/Assembler-x64.h:926
    #10 0x1328814 in js::jit::MacroAssembler::call(js::wasm::SymbolicAddress) js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp:548:5
    #11 0x1e92c0c in GenerateOldTrapExit(js::jit::MacroAssembler&, js::wasm::Trap, js::jit::Label*, js::wasm::CallableOffsets*) js/src/wasm/WasmStubs.cpp:1372:5
    #12 0x1e92c0c in js::wasm::GenerateStubs(js::wasm::ModuleEnvironment const&, mozilla::Vector<js::wasm::FuncImport, 0ul, js::SystemAllocPolicy> const&, mozilla::Vector<js::wasm::FuncExport, 0ul, js::SystemAllocPolicy> const&, js::wasm::CompiledCode*) js/src/wasm/WasmStubs.cpp:1742
    #13 0x1d89345 in js::wasm::ModuleGenerator::finish(js::wasm::ShareableBytes const&) js/src/wasm/WasmGenerator.cpp:961:10
    #14 0x1d62b0a in js::wasm::ModuleGenerator::finishModule(js::wasm::ShareableBytes const&) js/src/wasm/WasmGenerator.cpp:983:37
    #15 0x1d55aa4 in js::wasm::CompileBuffer(js::wasm::CompileArgs const&, js::wasm::ShareableBytes const&, mozilla::UniquePtr<char [], JS::FreePolicy>*) js/src/wasm/WasmCompile.cpp:441:12
    #16 0x1df02be in js::WasmModuleObject::construct(JSContext*, unsigned int, JS::Value*) js/src/wasm/WasmJS.cpp:874:27
    #17 0x84a1a9 in js::CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) js/src/jscntxtinlines.h:291:15
[...]
    #31 0x7fb7f069582f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-use-after-free js/src/jsscript.h:1319:16 in JSScript::strict() const
Shadow bytes around the buggy address:
  0x0c067fffb790: 00 fa fa fa 00 00 00 00 fa fa fd fd fd fd fa fa
=>0x0c067fffb7a0: 00 00 00 00 fa fa[fd]fd fd fd fa fa fd fd fd fd
  0x0c067fffb7b0: fa fa fd fd fd fd fa fa fd fd fd fa fa fa fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Heap left redzone:       fa
  Freed heap region:       fd


Marking s-s and sec-critical due to use-after-free.
Flags: needinfo?(bbouvier)
Attached patch builtin.patchSplinter Review
Nightly only. It triggers a better assertion without an ASAN build: fun->isInterpreted(), which wasm functions aren't: https://searchfox.org/mozilla-central/source/js/src/jsfun.cpp#137

It's rather silly, I missed one call to JSFunction::isBuiltinNative(). I checked and it makes sense that JSFunction::isBuiltin() returns true for wasm functions (as it did before the patches in bug 1319203).

Sorry to make these testing functions more complicated :/ Fortunately, it's nicely blackboxed and there shouldn't be any other issues like this.
Assignee: nobody → bbouvier
Status: NEW → ASSIGNED
Flags: needinfo?(bbouvier)
Attachment #8950179 - Flags: review?(jdemooij)
Comment on attachment 8950179 [details] [diff] [review]
builtin.patch

Review of attachment 8950179 [details] [diff] [review]:
-----------------------------------------------------------------

Makes sense.
Attachment #8950179 - Flags: review?(jdemooij) → review+
Whiteboard: [jsbugmon:update,bisect] → [jsbugmon:bisect]
JSBugMon: Cannot process bug: Unable to automatically reproduce, please track manually.
Whiteboard: [jsbugmon:bisect] → [jsbugmon:]
Keywords: csectype-uaf
Whiteboard: [jsbugmon:] → [jsbugmon:][Nightly only]
https://hg.mozilla.org/mozilla-central/rev/7cc1ab26945b
Status: ASSIGNED → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla60
Duplicate of this bug: 1437536
Group: javascript-core-security → core-security-release
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.