Skip to content

Commit

Permalink
[CVE-2020-0712] An uninitialized memory usage error in the latest Mic…
Browse files Browse the repository at this point in the history
…rosoft Edge 44.18362.387.0 may be exploited to execute arbitrary code. - Individual

```javascript
class child extends Object {
    constructor(){
        let f = () => {
            super()++
        };
        f();
    }
}
```

In above snippet, we attempt to emit a load for the target of the super call. This causes us to acquire a tmp register for the target of the super call node out-of-order relative to how the tmp registers are typically acquired in `EmitSuperCall`. Then later when we release the call target location we notice that the tmp registers are being released out-of-order. Fix is to skip emitting the call target when emitting a load of a super call node - this is already handled by `EmitSuperCall` so it isn't necessary anyway.
  • Loading branch information
boingoing authored and akroshg committed Feb 10, 2020
1 parent c7999d9 commit 2e33d82
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 42 deletions.
73 changes: 39 additions & 34 deletions lib/Runtime/ByteCode/ByteCodeEmitter.cpp
Expand Up @@ -5931,39 +5931,43 @@ void EmitReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncI
// These have to be emitted before the RHS, but they have to persist until
// the end of the expression.
// Emit the call target operands first.
switch (pnode->AsParseNodeCall()->pnodeTarget->nop)
// The call target does not need to be emitted for a super call - EmitSuperCall will do this.
if (!pnode->AsParseNodeCall()->isSuperCall)
{
case knopDot:
case knopIndex:
funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget);
EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
break;

case knopName:
{
Symbol *sym = pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym;
if (!sym || sym->GetLocation() == Js::Constants::NoRegister)
switch (pnode->AsParseNodeCall()->pnodeTarget->nop)
{
case knopDot:
case knopIndex:
funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget);
}
if (sym && (sym->IsInSlot(byteCodeGenerator, funcInfo) || sym->GetScope()->GetFunc() != funcInfo))
EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
break;

case knopName:
{
// Can't get the value from the assigned register, so load it here.
EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
Symbol* sym = pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym;
if (!sym || sym->GetLocation() == Js::Constants::NoRegister)
{
funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget);
}
if (sym && (sym->IsInSlot(byteCodeGenerator, funcInfo) || sym->GetScope()->GetFunc() != funcInfo))
{
// Can't get the value from the assigned register, so load it here.
EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
}
else
{
// EmitLoad will check for needsDeclaration and emit the Use Before Declaration error
// bytecode op as necessary, but EmitReference does not check this (by design). So we
// must manually check here.
EmitUseBeforeDeclaration(pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym, byteCodeGenerator, funcInfo);
EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
}
break;
}
else
{
// EmitLoad will check for needsDeclaration and emit the Use Before Declaration error
// bytecode op as necessary, but EmitReference does not check this (by design). So we
// must manually check here.
EmitUseBeforeDeclaration(pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym, byteCodeGenerator, funcInfo);
EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
default:
EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
break;
}
break;
}
default:
EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
break;
}

// Now the arg list. We evaluate everything now and emit the ArgOut's later.
Expand All @@ -5977,12 +5981,6 @@ void EmitReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncI
}
Emit(pnodeArg, byteCodeGenerator, funcInfo, false);
}

if (pnode->AsParseNodeCall()->isSuperCall)
{
Emit(pnode->AsParseNodeSuperCall()->pnodeThis, byteCodeGenerator, funcInfo, false);
Emit(pnode->AsParseNodeSuperCall()->pnodeNewTarget, byteCodeGenerator, funcInfo, false);
}
break;

default:
Expand Down Expand Up @@ -6961,7 +6959,14 @@ void EmitLoad(
case knopCall:
{
ParseNodeCall * pnodeCallLhs = lhs->AsParseNodeCall();
if (pnodeCallLhs->pnodeTarget->nop == knopImport)

if (pnodeCallLhs->isSuperCall)
{
funcInfo->AcquireLoc(pnodeCallLhs);
EmitReference(pnodeCallLhs, byteCodeGenerator, funcInfo);
byteCodeGenerator->EmitSuperCall(funcInfo, pnodeCallLhs->AsParseNodeSuperCall(), /*fReturnValue=*/ false);
}
else if (pnodeCallLhs->pnodeTarget->nop == knopImport)
{
ParseNodePtr args = pnodeCallLhs->pnodeArgs;
Assert(CountArguments(args) == 2); // import() takes one argument
Expand Down
19 changes: 11 additions & 8 deletions lib/Runtime/ByteCode/FuncInfo.cpp
Expand Up @@ -341,16 +341,19 @@ void FuncInfo::ReleaseReference(ParseNode *pnode)
}
}
// Now release the call target.
switch (pnode->AsParseNodeCall()->pnodeTarget->nop)
if (!pnode->AsParseNodeCall()->isSuperCall)
{
case knopDot:
case knopIndex:
this->ReleaseReference(pnode->AsParseNodeCall()->pnodeTarget);
this->ReleaseLoc(pnode->AsParseNodeCall()->pnodeTarget);
break;
default:
this->ReleaseLoad(pnode->AsParseNodeCall()->pnodeTarget);
switch (pnode->AsParseNodeCall()->pnodeTarget->nop)
{
case knopDot:
case knopIndex:
this->ReleaseReference(pnode->AsParseNodeCall()->pnodeTarget);
this->ReleaseLoc(pnode->AsParseNodeCall()->pnodeTarget);
break;
default:
this->ReleaseLoad(pnode->AsParseNodeCall()->pnodeTarget);
break;
}
}
break;
default:
Expand Down

0 comments on commit 2e33d82

Please sign in to comment.