Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dynamic-stack-buffer-overflow in Escargot::PointerValue::getTypeTag #1332

Open
Ye0nny opened this issue Apr 7, 2024 · 0 comments
Open

dynamic-stack-buffer-overflow in Escargot::PointerValue::getTypeTag #1332

Ye0nny opened this issue Apr 7, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@Ye0nny
Copy link

Ye0nny commented Apr 7, 2024

Escargot

  • OS: Ubuntu 20.04.5 LTS (Linux 5.4.0-144-generic x86_64)
  • Revision : 28451a7

Build Steps

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

Describe the bug
dynamic-stack-buffer-overflow

Test case

testcase

32 ; 
( ( { [ e. b ] : e = { b } = { b : 32 } } = { } ) => a. b = 0 && a. b ^= b ) 
( { b : 32 } ) ; 
32 ; 
b ;

// poc.js
( ( { [ e. b ] : e = { } } = { } ) => a ) 
( { b : 32 } ) ;

Execution steps & Output

$ ./escargot poc.js
=================================================================
==2069311==ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address 0x7ffd090af208 at pc 0x55a5eb048a51 bp 0x7ffd090ada30 sp 0x7ffd090ada20
READ of size 8 at 0x7ffd090af208 thread T0
    #0 0x55a5eb048a50 in Escargot::PointerValue::getTypeTag() const src/runtime/PointerValue.h:1080
    #1 0x55a5eb047201 in Escargot::PointerValue::isObject() const src/runtime/PointerValue.h:168
    #2 0x55a5eb0512f5 in Escargot::Value::isObject() const src/runtime/ValueInlines.h:558
    #3 0x55a5eb2b8f32 in Escargot::InterpreterSlowPath::getObjectPrecomputedCaseOperation(Escargot::ExecutionState&, Escargot::GetObjectPreComputedCase*, Escargot::Value*, Escargot::ByteCodeBlock*) src/interpreter/ByteCodeInterpreter.cpp:2362
    #4 0x55a5eb2aab09 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:654
    #5 0x55a5eb850c77 in Escargot::Value Escargot::FunctionObjectProcessCallGenerator::processCall<Escargot::ScriptArrowFunctionObject, false, false, false, Escargot::ScriptArrowFunctionObjectThisValueBinder, Escargot::FunctionObjectNewTargetBinder, Escargot::FunctionObjectReturnValueBinder>(Escargot::ExecutionState&, Escargot::ScriptArrowFunctionObject*, Escargot::Value const&, unsigned long, Escargot::Value*, Escargot::Object*) src/runtime/FunctionObjectInlines.h:221
    #6 0x55a5eb8500ae in Escargot::ScriptArrowFunctionObject::call(Escargot::ExecutionState&, Escargot::Value const&, unsigned long, Escargot::Value*) (./escargot/escargot+0xa650ae)
    #7 0x55a5eb2ab871 in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:767
    #8 0x55a5eb4741bb in Escargot::Script::execute(Escargot::ExecutionState&, bool, bool) src/parser/Script.cpp:499
    #9 0x55a5eb066c62 in Escargot::ScriptRef::execute(Escargot::ExecutionStateRef*) src/api/EscargotPublic.cpp:4715
    #10 0x55a5eb90803c in operator() src/shell/Shell.cpp:790
    #11 0x55a5eb908067 in _FUN src/shell/Shell.cpp:791
    #12 0x55a5eb911d3d 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
    #13 0x55a5eb911349 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
    #14 0x55a5eb9107a9 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
    #15 0x55a5eb90f85c 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
    #16 0x55a5eb90de70 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
    #17 0x55a5eb90defe 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
    #18 0x55a5eb062de0 in operator() src/api/EscargotPublic.cpp:1087
    #19 0x55a5eb062e1a in _FUN src/api/EscargotPublic.cpp:1088
    #20 0x55a5eb848dd4 in Escargot::SandBox::run(Escargot::Value (*)(Escargot::ExecutionState&, void*), void*) src/runtime/SandBox.cpp:111
    #21 0x55a5eb063079 in Escargot::Evaluator::executeFunction(Escargot::ContextRef*, Escargot::ValueRef* (*)(Escargot::ExecutionStateRef*, void*, void*), void*, void*) src/api/EscargotPublic.cpp:1089
    #22 0x55a5eb90e100 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
    #23 0x55a5eb90c69a in execute<Escargot::ScriptRef*, evalScript(Escargot::ContextRef*, Escargot::StringRef*, Escargot::StringRef*, bool, bool)::<lambda(Escargot::ExecutionStateRef*, Escargot::ScriptRef*)> > src/api/EscargotPublic.h:585
    #24 0x55a5eb908838 in evalScript src/shell/Shell.cpp:792
    #25 0x55a5eb90b2db in main src/shell/Shell.cpp:1143
    #26 0x7fe8563b3082 in __libc_start_main ../csu/libc-start.c:308
    #27 0x55a5eb0447fd in _start (./escargot/escargot+0x2597fd)

Address 0x7ffd090af208 is located in stack of thread T0 at offset 2424 in frame
    #0 0x55a5eb2a605b in Escargot::Interpreter::interpret(Escargot::ExecutionState*, Escargot::ByteCodeBlock*, unsigned long, Escargot::Value*) src/interpreter/ByteCodeInterpreter.cpp:226

  This frame has 61 object(s):
    [32, 36) 'c' (line 367)
    [48, 52) 'c' (line 394)
    [64, 68) 'c' (line 424)
    [80, 84) '<unknown>'
    [96, 104) 'idx' (line 293)
    [128, 136) 'idx' (line 326)
    [160, 168) '<unknown>'
    [192, 200) '<unknown>'
    ...
    [1568, 1576) '<unknown>'
    [1600, 1608) '<unknown>'
    [1632, 1640) 'v' (line 1477)
    [1664, 1672) '<unknown>'
    [1696, 1704) 'v' (line 1496)
    [1728, 1736) '<unknown>'
    [1760, 1768) 'state' (line 225)
    [1792, 1800) 'programCounter' (line 225)
    [1824, 1840) '<unknown>'
    [1856, 1872) '<unknown>'
    [1888, 1912) 'spreadArgs' (line 1443) <== Memory access at offset 2424 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: dynamic-stack-buffer-overflow src/runtime/PointerValue.h:1080 in Escargot::PointerValue::getTypeTag() const
Shadow bytes around the buggy address:
  0x10002120ddf0: f2 f2 00 f2 f2 f2 00 00 f2 f2 00 00 f2 f2 00 00
  0x10002120de00: 00 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00
  0x10002120de10: 00 00 00 00 ca ca ca ca 00 00 00 00 00 00 cb cb
  0x10002120de20: cb cb cb cb 00 00 00 00 ca ca ca ca 00 00 00 00
  0x10002120de30: 00 00 00 00 00 00 cb cb cb cb cb cb 00 00 00 00
=>0x10002120de40: ca[ca]ca ca 00 00 00 cb cb cb cb cb 00 00 00 00
  0x10002120de50: ca ca ca ca 00 00 00 cb cb cb cb cb 00 00 00 00
  0x10002120de60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10002120de70: f1 f1 f1 f1 01 f2 01 f2 00 f2 f2 f2 00 f2 f2 f2
  0x10002120de80: 00 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0x10002120de90: 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
==2069311==ABORTING

when executed in release mode

Output

Segmentation fault

Expected behavior
This code should not crash.
Other JS engines (such as V8, JSC, etc.) identify a ReferenceError.

poc.js:1: ReferenceError: Cannot access 'e' before initialization
( ( { [ e. b ] : e = { } } = { } ) => a )
        ^
ReferenceError: Cannot access 'e' before initialization
    at poc.js:1:9
    at poc.js:2:1

Credits: @Ye0nny, @EJueon

@Ye0nny Ye0nny added the bug Something isn't working label Apr 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant