Samsung / escargot

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

global-buffer-overflow in Escargot::InterpreterSlowPath::unaryTypeof #1333

Open Ye0nny opened 6 months ago

Ye0nny commented 6 months ago

Escargot

Build Steps

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

Describe the bug global-buffer-overflow (sometimes detected memory leaks)

Test case

testcase

```javascript var r = [ " string ", 32, null, 1, undefined, Symbol ( " symbol " ), true, false ] ; var var0 = true ; for ( var e of r ) { for ( let { func0 : n = f = typeof n, b : o = class o { },... t } of e ) n = f ; if ( n!== true ) throw new Error ( " Error : " + n + " bad value : a = " + String. fromCharCode ( 65 + 65, n ) ) ; Object. freeze ( e ) ; } ```

// poc.js
var r = [ " string " ] ; 
for ( var e of r ) { 
    for ( let { func0 : n = f = typeof n, b : o = class o { },... t } of e ) 
    Object. freeze ( e ) ; 
}

Execution steps & Output

$ ./escargot poc.js
=================================================================
==2069958==ERROR: AddressSanitizer: global-buffer-overflow on address 0x564dc5c45a90 at pc 0x564dc5035d0e bp 0x7ffeeff024b0 sp 0x7ffeeff024a0
READ of size 8 at 0x564dc5c45a90 thread T0
    #0 0x564dc5035d0d in Escargot::InterpreterSlowPath::unaryTypeof(Escargot::ExecutionState&, Escargot::UnaryTypeof*, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:4723
    #1 0x564dc50073de in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1089
    #2 0x564dc501fe96 in Escargot::InterpreterSlowPath::tryOperation(Escargot::ExecutionState*&, unsigned long&, Escargot::ByteCodeBlock*, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:3303
    #3 0x564dc5007d29 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1254
    #4 0x564dc501fe96 in Escargot::InterpreterSlowPath::tryOperation(Escargot::ExecutionState*&, unsigned long&, Escargot::ByteCodeBlock*, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:3303
    #5 0x564dc5007d29 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:1254
    #6 0x564dc51cd1bb in Escargot::Script::execute(Escargot::ExecutionState&, bool, bool) src/parser/Script.cpp:499
    #7 0x564dc4dbfc62 in Escargot::ScriptRef::execute(Escargot::ExecutionStateRef*) src/api/EscargotPublic.cpp:4715
    #8 0x564dc566103c in operator() src/shell/Shell.cpp:790
    #9 0x564dc5661067 in _FUN src/shell/Shell.cpp:791
    #10 0x564dc566ad3d 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
    #11 0x564dc566a349 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
    #12 0x564dc56697a9 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
    #13 0x564dc566885c 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
    #14 0x564dc5666e70 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
    #15 0x564dc5666efe 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
    #16 0x564dc4dbbde0 in operator() src/api/EscargotPublic.cpp:1087
    #17 0x564dc4dbbe1a in _FUN src/api/EscargotPublic.cpp:1088
    #18 0x564dc55a1dd4 in Escargot::SandBox::run(Escargot::Value (*)(Escargot::ExecutionState&, void*), void*) src/runtime/SandBox.cpp:111
    #19 0x564dc4dbc079 in Escargot::Evaluator::executeFunction(Escargot::ContextRef*, Escargot::ValueRef* (*)(Escargot::ExecutionStateRef*, void*, void*), void*, void*) src/api/EscargotPublic.cpp:1089
    #20 0x564dc5667100 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
    #21 0x564dc566569a in execute<Escargot::ScriptRef*, evalScript(Escargot::ContextRef*, Escargot::StringRef*, Escargot::StringRef*, bool, bool)::<lambda(Escargot::ExecutionStateRef*, Escargot::ScriptRef*)> > src/api/EscargotPublic.h:585
    #22 0x564dc5661838 in evalScript src/shell/Shell.cpp:792
    #23 0x564dc56642db in main src/shell/Shell.cpp:1143
    #24 0x7f773eca3082 in __libc_start_main ../csu/libc-start.c:308
    #25 0x564dc4d9d7fd in _start (./escargot/escargot+0x2597fd)

0x564dc5c45a90 is located 16 bytes to the left of global variable 'MOD_PRIME' defined in 'third_party/robin_map/include/tsl/robin_growth_policy.h:317:5' (0x564dc5c45aa0) of size 408
0x564dc5c45a90 is located 24 bytes to the right of global variable 'MOD_PRIME' defined in 'third_party/robin_map/include/tsl/robin_growth_policy.h:317:5' (0x564dc5c458e0) of size 408
SUMMARY: AddressSanitizer: global-buffer-overflow src/interpreter/ByteCodeInterpreter.cpp:4723 in Escargot::InterpreterSlowPath::unaryTypeof(Escargot::ExecutionState&, Escargot::UnaryTypeof*, Escargot::Value*)
Shadow bytes around the buggy address:
  0x0aca38b80b00: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
  0x0aca38b80b10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0aca38b80b20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0aca38b80b30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0aca38b80b40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f9
=>0x0aca38b80b50: f9 f9[f9]f9 00 00 00 00 00 00 00 00 00 00 00 00
  0x0aca38b80b60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0aca38b80b70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0aca38b80b80: 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 00 00 00 00
  0x0aca38b80b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0aca38b80ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==2069958==ABORTING

when executed in release mode

Output

Segmentation fault

Expected behavior

poc.js:3: ReferenceError: Cannot access 'n' before initialization
    for ( let { func0 : n = f = typeof n, b : o = class o { },... t } of e )
                     ^
ReferenceError: Cannot access 'n' before initialization
    at poc.js:3:22

Credits: @Ye0nny, @EJueon