Samsung / escargot

Escargot is a lightweight JavaScript engine designed specifically for resource-constrained environments.
GNU Lesser General Public License v2.1
261 stars 43 forks source link

Null pointer dereference in Escargot::EnumerateObject::checkLastEnumerateKey #1336

Closed Ye0nny closed 4 months ago

Ye0nny commented 5 months ago

Escargot

Build Steps

cmake -DCMAKE_CXX_FLAGS=-fsanitize=address -DESCARGOT_MODE=debug -DESCARGOT_OUTPUT=shell -GNinja

Describe the bug Null pointer dereference

Test case

testcase

```javascript ( function func0 ( ) { for ( let var0 in this ) { class e { method ( ) { return 1 ; } } class t extends e { method (... e ) { } async method ( ) { } } if ( - " number " in this ) continue ; gc ( ) ; new t ( 1 ) ; } with ( 0 ) { try { return 32 ; } finally { " " ; } } } ) ( ) ; ```

// poc.js
( function func0 ( ) {
        for ( let var0 in this ) {
                class e { }
                if ( - " number " in this ) continue ;
        }
        with ( 0 ) { }
} ) ( ) ;

Execution steps & Output

$ ./escargot poc.js
AddressSanitizer:DEADLYSIGNAL
=================================================================
==2072273==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x55f0259cc9dc bp 0x7ffdcd218600 sp 0x7ffdcd2185e0 T0)
==2072273==The signal is caused by a READ memory access.
==2072273==Hint: address points to the zero page.
    #0 0x55f0259cc9db in Escargot::EnumerateObject::checkLastEnumerateKey(Escargot::ExecutionState&) src/runtime/EnumerateObject.cpp:30
    #1 0x55f0255bb9ff in Escargot::InterpreterSlowPath::checkLastEnumerateKey(Escargot::ExecutionState&, Escargot::CheckLastEnumerateKey*, unsigned char*, unsigned long&, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:4258
    #2 0x55f0255961d1 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1306
    #3 0x55f0255b632c in Escargot::InterpreterSlowPath::blockOperation(Escargot::ExecutionState*&, Escargot::BlockOperation*, unsigned long&, Escargot::ByteCodeBlock*, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:3883
    #4 0x55f0255972e9 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1496
    #5 0x55f0255b632c in Escargot::InterpreterSlowPath::blockOperation(Escargot::ExecutionState*&, Escargot::BlockOperation*, unsigned long&, Escargot::ByteCodeBlock*, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:3883
    #6 0x55f0255972e9 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1496
    #7 0x55f0255b632c in Escargot::InterpreterSlowPath::blockOperation(Escargot::ExecutionState*&, Escargot::BlockOperation*, unsigned long&, Escargot::ByteCodeBlock*, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:3883
    #8 0x55f0255972e9 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1496
    #9 0x55f0255b632c in Escargot::InterpreterSlowPath::blockOperation(Escargot::ExecutionState*&, Escargot::BlockOperation*, unsigned long&, Escargot::ByteCodeBlock*, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:3883
    #10 0x55f0255972e9 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1496
    #11 0x55f0255b632c in Escargot::InterpreterSlowPath::blockOperation(Escargot::ExecutionState*&, Escargot::BlockOperation*, unsigned long&, Escargot::ByteCodeBlock*, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:3883
    #12 0x55f0255972e9 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1496
    #13 0x55f025b47a29 in Escargot::Value Escargot::FunctionObjectProcessCallGenerator::processCall<Escargot::ScriptFunctionObject, false, false, false, Escargot::FunctionObjectThisValueBinder, Escargot::FunctionObjectNewTargetBinder, Escargot::FunctionObjectReturnValueBinder>(Escargot::ExecutionState&, Escargot::ScriptFunctionObject*, Escargot::Value const&, unsigned long, Escargot::Value*, Escargot::Object*) src/runtime/FunctionObjectInlines.h:221
    #14 0x55f025b45f40 in Escargot::ScriptFunctionObject::call(Escargot::ExecutionState&, Escargot::Value const&, unsigned long, Escargot::Value*) src/runtime/ScriptFunctionObject.cpp:108
    #15 0x55f025592871 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:767
    #16 0x55f02575b1bb in Escargot::Script::execute(Escargot::ExecutionState&, bool, bool) src/parser/Script.cpp:499
    #17 0x55f02534dc62 in Escargot::ScriptRef::execute(Escargot::ExecutionStateRef*) src/api/EscargotPublic.cpp:4715
    #18 0x55f025bef03c in operator() src/shell/Shell.cpp:790
    #19 0x55f025bef067 in _FUN src/shell/Shell.cpp:791
    #20 0x55f025bf8d3d in decltype (((forward<Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*)>)({parm#1}))((forward<Escargot::ExecutionStateRef*&>)({parm#3}), (forward<Escargot::ScriptRef*&>)({parm#3}))) Escargot::EvaluatorUtil::ApplyTupleIntoArgumentsOfVariadicTemplateFunction<0ul>::apply<Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&, Escargot::ExecutionStateRef*&, Escargot::ScriptRef*&>(Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&, Escargot::ExecutionStateRef*&, Escargot::ScriptRef*&) src/api/EscargotPublic.h:521
    #21 0x55f025bf8349 in decltype (Escargot::EvaluatorUtil::ApplyTupleIntoArgumentsOfVariadicTemplateFunction<0ul>::apply((forward<Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*)>)({parm#1}), (forward<std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&>)({parm#2}), (get<(1ul)-(1)>)((forward<std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&>)({parm#2})), (forward<Escargot::ScriptRef*&>)({parm#3}))) Escargot::EvaluatorUtil::ApplyTupleIntoArgumentsOfVariadicTemplateFunction<1ul>::apply<Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&, Escargot::ScriptRef*&>(Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&, Escargot::ScriptRef*&) src/api/EscargotPublic.h:510
    #22 0x55f025bf77a9 in decltype (Escargot::EvaluatorUtil::ApplyTupleIntoArgumentsOfVariadicTemplateFunction<1ul>::apply((forward<Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*)>)({parm#1}), (forward<std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&>)({parm#2}), (get<(2ul)-(1)>)((forward<std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&>)({parm#2})))) Escargot::EvaluatorUtil::ApplyTupleIntoArgumentsOfVariadicTemplateFunction<2ul>::apply<Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&>(Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&) src/api/EscargotPublic.h:510
    #23 0x55f025bf685c in decltype (Escargot::EvaluatorUtil::ApplyTupleIntoArgumentsOfVariadicTemplateFunction<std::tuple_size<std::decay<std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&>::type>::value>::apply((forward<Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*)>)({parm#1}), (forward<std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&>)({parm#2}))) Escargot::EvaluatorUtil::applyTupleIntoArgumentsOfVariadicTemplateFunction<Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&>(Escargot::ValueRef* (*&)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), std::tuple<Escargot::ExecutionStateRef*, Escargot::ScriptRef*>&) src/api/EscargotPublic.h:531
    #24 0x55f025bf4e70 in Escargot::Evaluator::executeImpl<Escargot::ContextRef, Escargot::ScriptRef*>(Escargot::ContextRef*, Escargot::ValueRef* (*)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), Escargot::ScriptRef*)::{lambda(Escargot::ExecutionStateRef*, void*, void*)#1}::operator()(Escargot::ExecutionStateRef*, void*, void*) const src/api/EscargotPublic.h:612
    #25 0x55f025bf4efe in Escargot::Evaluator::executeImpl<Escargot::ContextRef, Escargot::ScriptRef*>(Escargot::ContextRef*, Escargot::ValueRef* (*)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), Escargot::ScriptRef*)::{lambda(Escargot::ExecutionStateRef*, void*, void*)#1}::_FUN(Escargot::ExecutionStateRef*, void*, void*) src/api/EscargotPublic.h:606
    #26 0x55f025349de0 in operator() src/api/EscargotPublic.cpp:1087
    #27 0x55f025349e1a in _FUN src/api/EscargotPublic.cpp:1088
    #28 0x55f025b2fdd4 in Escargot::SandBox::run(Escargot::Value (*)(Escargot::ExecutionState&, void*), void*) src/runtime/SandBox.cpp:111
    #29 0x55f02534a079 in Escargot::Evaluator::executeFunction(Escargot::ContextRef*, Escargot::ValueRef* (*)(Escargot::ExecutionStateRef*, void*, void*), void*, void*) src/api/EscargotPublic.cpp:1089
    #30 0x55f025bf5100 in Escargot::Evaluator::EvaluatorResult Escargot::Evaluator::executeImpl<Escargot::ContextRef, Escargot::ScriptRef*>(Escargot::ContextRef*, Escargot::ValueRef* (*)(Escargot::ExecutionStateRef*, Escargot::ScriptRef*), Escargot::ScriptRef*) src/api/EscargotPublic.h:614
    #31 0x55f025bf369a in execute<Escargot::ScriptRef*, evalScript(Escargot::ContextRef*, Escargot::StringRef*, Escargot::StringRef*, bool, bool)::<lambda(Escargot::ExecutionStateRef*, Escargot::ScriptRef*)> > src/api/EscargotPublic.h:585
    #32 0x55f025bef838 in evalScript src/shell/Shell.cpp:792
    #33 0x55f025bf22db in main src/shell/Shell.cpp:1143
    #34 0x7f7991ff5082 in __libc_start_main ../csu/libc-start.c:308
    #35 0x55f02532b7fd in _start (./escargot/escargot+0x2597fd)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV src/runtime/EnumerateObject.cpp:30 in Escargot::EnumerateObject::checkLastEnumerateKey(Escargot::ExecutionState&)
==2072273==ABORTING

when executed in release mode

Output

Segmentation fault

Expected behavior

undefined

Credits: @Ye0nny, @EJueon