Open Bug 1444155 Opened 2 years ago Updated 2 months ago

Intermittent Assertion failure: state_ == Idle || state_ == WaitingInterrupted, at mozilla-central/js/src/builtin/AtomicsObject.cpp:844

Categories

(Core :: JavaScript Engine, defect, P3)

defect

Tracking

()

Tracking Status
firefox60 --- affected

People

(Reporter: Alex_Gaynor, Assigned: lth)

References

(Blocks 1 open bug)

Details

(Keywords: oss-fuzz)

Attachments

(2 files)

(I'm not positive if this is security or not, better safe than sorry!)

This bug was found by Google's OSS-Fuzz running their custom internal JS fuzzer.

Please note that they apply a 90-day disclose timeline to all bugs.

This only occurs intermittently for me, I'm running it in a bash loop to get it to happen more regularly; I'd estimate the assertion error happens 1/10 times:

ASAN_OPTIONS=redzone=512:strict_memcmp=0:allow_user_segv_handler=1:allocator_may_return_null=1:handle_sigfpe=1:handle_sigbus=1:detect_stack_use_after_return=0:alloc_dealloc_mismatch=0:print_scariness=1:max_uar_stack_size_log=16:detect_odr_violation=0:handle_sigill=1:coverage=0:use_sigaltstack=1:fast_unwind_on_fatal=1:detect_leaks=0:print_summary=1:handle_abort=1:check_malloc_usable_size=0:detect_container_overflow=1:symbolize=0:handle_segv=1 /out/js --cpu-count=2 --disable-oom-functions --fuzzing-safe --ion-extra-checks clusterfuzz-testcase-minimized-5691504187146240.js


	Script runs for too long, terminating.
	Assertion failure: state_ == Idle || state_ == WaitingInterrupted, at mozilla-central/js/src/builtin/AtomicsObject.cpp:844
	AddressSanitizer:DEADLYSIGNAL
	=================================================================
	==16361==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x0000009bdd00 bp 0x7ffd498b15b0 sp 0x7ffd498b1400 T0)
	==16361==The signal is caused by a WRITE memory access.
	==16361==Hint: address points to the zero page.
	SCARINESS: 10 (null-deref)
	#0 0x9bdcff in js::FutexThread::wait(JSContext*, js::LockGuard<js::Mutex>&, mozilla::Maybe<mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator> > const&) mozilla-central/js/src/builtin/AtomicsObject.cpp:843:5
	#1 0x9b7fac in js::FutexThread::WaitResult AtomicsWait<int>(JSContext*, js::SharedArrayRawBuffer*, unsigned int, int, mozilla::Maybe<mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator> > const&) mozilla-central/js/src/builtin/AtomicsObject.cpp:605:45
	#2 0x9b7fac in js::atomics_wait_impl(JSContext*, js::SharedArrayRawBuffer*, unsigned int, int, mozilla::Maybe<mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator> > const&) mozilla-central/js/src/builtin/AtomicsObject.cpp:623
	#3 0x9b9cf5 in js::atomics_wait(JSContext*, unsigned int, JS::Value*) mozilla-central/js/src/builtin/AtomicsObject.cpp:674:13
	#4 0x924ac5 in js::CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) mozilla-central/js/src/vm/JSContext-inl.h:290:15
	#5 0x924ac5 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) mozilla-central/js/src/vm/Interpreter.cpp:467
	#6 0x90c548 in js::CallFromStack(JSContext*, JS::CallArgs const&) mozilla-central/js/src/vm/Interpreter.cpp:522:12
	#7 0x90c548 in Interpret(JSContext*, js::RunState&) mozilla-central/js/src/vm/Interpreter.cpp:3085
	#8 0x8eda03 in js::RunScript(JSContext*, js::RunState&) mozilla-central/js/src/vm/Interpreter.cpp:417:12
	#9 0x9249cc in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) mozilla-central/js/src/vm/Interpreter.cpp:489:15
	#10 0x926ac7 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) mozilla-central/js/src/vm/Interpreter.cpp:535:10
	#11 0x190f1ef in JS_CallFunctionValue(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) mozilla-central/js/src/jsapi.cpp:2969:12
	#12 0x580f77 in ShellInterruptCallback(JSContext*) mozilla-central/js/src/shell/js.cpp:739:22
	#13 0x20c48aa in InvokeInterruptCallback(JSContext*) mozilla-central/js/src/vm/Runtime.cpp:534:14
	#14 0x20c48aa in JSContext::handleInterrupt() mozilla-central/js/src/vm/Runtime.cpp:613
	#15 0x9bcef4 in js::FutexThread::wait(JSContext*, js::LockGuard<js::Mutex>&, mozilla::Maybe<mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator> > const&) mozilla-central/js/src/builtin/AtomicsObject.cpp:935:26
	#16 0x9b7fac in js::FutexThread::WaitResult AtomicsWait<int>(JSContext*, js::SharedArrayRawBuffer*, unsigned int, int, mozilla::Maybe<mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator> > const&) mozilla-central/js/src/builtin/AtomicsObject.cpp:605:45
	#17 0x9b7fac in js::atomics_wait_impl(JSContext*, js::SharedArrayRawBuffer*, unsigned int, int, mozilla::Maybe<mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator> > const&) mozilla-central/js/src/builtin/AtomicsObject.cpp:623
	#18 0x9b9cf5 in js::atomics_wait(JSContext*, unsigned int, JS::Value*) mozilla-central/js/src/builtin/AtomicsObject.cpp:674:13
	#19 0x924ac5 in js::CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) mozilla-central/js/src/vm/JSContext-inl.h:290:15
	#20 0x924ac5 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) mozilla-central/js/src/vm/Interpreter.cpp:467
	#21 0x90c548 in js::CallFromStack(JSContext*, JS::CallArgs const&) mozilla-central/js/src/vm/Interpreter.cpp:522:12
	#22 0x90c548 in Interpret(JSContext*, js::RunState&) mozilla-central/js/src/vm/Interpreter.cpp:3085
	#23 0x8eda03 in js::RunScript(JSContext*, js::RunState&) mozilla-central/js/src/vm/Interpreter.cpp:417:12
	#24 0x92a363 in js::ExecuteKernel(JSContext*, JS::Handle<JSScript*>, JSObject&, JS::Value const&, js::AbstractFramePtr, JS::Value*) mozilla-central/js/src/vm/Interpreter.cpp:700:15
	#25 0x92b0b6 in js::Execute(JSContext*, JS::Handle<JSScript*>, JSObject&, JS::Value*) mozilla-central/js/src/vm/Interpreter.cpp:732:12
	#26 0x193156f in ExecuteScript(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSScript*>, JS::Value*) mozilla-central/js/src/jsapi.cpp:4729:12
	#27 0x193195f in JS_ExecuteScript(JSContext*, JS::Handle<JSScript*>) mozilla-central/js/src/jsapi.cpp:4762:12
	#28 0x5ee4c4 in RunFile(JSContext*, char const*, _IO_FILE*, bool) mozilla-central/js/src/shell/js.cpp:832:14
	#29 0x5ee4c4 in Process(JSContext*, char const*, bool, FileKind) mozilla-central/js/src/shell/js.cpp:1276
	#30 0x57a851 in ProcessArgs(JSContext*, js::cli::OptionParser*) mozilla-central/js/src/shell/js.cpp:8546:14
	#31 0x57a851 in Shell(JSContext*, js::cli::OptionParser*, char**) mozilla-central/js/src/shell/js.cpp:8934
	#32 0x57a851 in main mozilla-central/js/src/shell/js.cpp:9405
	#33 0x7f6ed668982f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/libc-start.c:291
Group: core-security → javascript-core-security
Lars, could you take a look?
Flags: needinfo?(lhansen)
Priority: -- → P1
Alex, I assume this is Linux 32-bit?

From a high level it looks like an interrupt handler executing Atomics.wait(), and the interrupt triggered while we were already waiting.  It looks like we're confused about what state we can be in.  It looks fairly benign, because the default code path in the function with the failing assert will assume that the state_ is Idle anyway, and then we'll just wait some more.

I'll dig into it some more when I have a moment.
Flags: needinfo?(lhansen) → needinfo?(agaynor)
I reproduced this on Linux 64-bit; I believe OSS-Fuzz is also 64-bit.

If there's potential security implications, dropping s-s is fine. I wasn't sure.
Flags: needinfo?(agaynor)
Err, I dropped a word, that should say "if there's _no_ potential security implications".
Group: javascript-core-security
Assignee: nobody → lhansen
New testcase for the same crash.
I've not been able to reproduce this.  Staring at the code, I have a vague notion that it may be possible for the state_ to transition to WaitingNotifiedForInterrupt in response to an interrupt that arrives while we're in the interrupt handler, which is what the second test case provokes.  I remember it was tricky to implement this in the first place.

(Even so this should not be a security issue.)

This is essentially the second test case:

var IA = new Int32Array(new SharedArrayBuffer(12));
IA[0] = 42;

setSharedArrayBuffer(IA.buffer)

// A worker that will dispatch a single wakeup

evalInWorker
(`
var mem = new Int32Array(getSharedArrayBuffer());
sleep(2);
Atomics.wake(mem, 0);
`);

// A slow-script handler that will block if invoked

timeout(2, function () {
    Atomics.wait(IA, 0, 42)
    return true;
})

// This will block indefinitely, then be woken by the worker.
// The worker will probably race with the slow-script handler.
// If the slow-script handler runs then we get a recursive wait.
// That wait will be woken by the worker.

Atomics.wait(IA, 0, 42);
Lars, do we have a specific bug for re-enabling shared-array-buffer? In which case this bug should be blocking it, to ensure that we do not randomly crash when turning it back on.
Flags: needinfo?(lhansen)
Priority: P1 → P3
Well, "randomly" - this is ASAN only.  But I know what you mean.

We do not have a bug for reenabling SAB.  I'll create one.
Flags: needinfo?(lhansen)
Blocks: resab
Flags: needinfo?(lhansen)

Apologies, I wanted to ask if this needs to block re-enabling SharedArrayBuffer? And can this only happen with threaded usage or is this a general problem?

This probably does not need to block resab, I'm considering it low priority to find out what's going on. Importantly the slow-script handler needs to be involved, so if we hit this case it's a buggy script anyway.

No longer blocks: resab
Flags: needinfo?(lhansen)
You need to log in before you can comment on or make changes to this bug.