Skip to content

Commit 2e33d82

Browse files
boingoingakroshg
authored andcommitted
[CVE-2020-0712] An uninitialized memory usage error in the latest Microsoft 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.
1 parent c7999d9 commit 2e33d82

File tree

2 files changed

+50
-42
lines changed

2 files changed

+50
-42
lines changed

lib/Runtime/ByteCode/ByteCodeEmitter.cpp

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5931,39 +5931,43 @@ void EmitReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncI
59315931
// These have to be emitted before the RHS, but they have to persist until
59325932
// the end of the expression.
59335933
// Emit the call target operands first.
5934-
switch (pnode->AsParseNodeCall()->pnodeTarget->nop)
5934+
// The call target does not need to be emitted for a super call - EmitSuperCall will do this.
5935+
if (!pnode->AsParseNodeCall()->isSuperCall)
59355936
{
5936-
case knopDot:
5937-
case knopIndex:
5938-
funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget);
5939-
EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
5940-
break;
5941-
5942-
case knopName:
5943-
{
5944-
Symbol *sym = pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym;
5945-
if (!sym || sym->GetLocation() == Js::Constants::NoRegister)
5937+
switch (pnode->AsParseNodeCall()->pnodeTarget->nop)
59465938
{
5939+
case knopDot:
5940+
case knopIndex:
59475941
funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget);
5948-
}
5949-
if (sym && (sym->IsInSlot(byteCodeGenerator, funcInfo) || sym->GetScope()->GetFunc() != funcInfo))
5942+
EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
5943+
break;
5944+
5945+
case knopName:
59505946
{
5951-
// Can't get the value from the assigned register, so load it here.
5952-
EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
5947+
Symbol* sym = pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym;
5948+
if (!sym || sym->GetLocation() == Js::Constants::NoRegister)
5949+
{
5950+
funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget);
5951+
}
5952+
if (sym && (sym->IsInSlot(byteCodeGenerator, funcInfo) || sym->GetScope()->GetFunc() != funcInfo))
5953+
{
5954+
// Can't get the value from the assigned register, so load it here.
5955+
EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
5956+
}
5957+
else
5958+
{
5959+
// EmitLoad will check for needsDeclaration and emit the Use Before Declaration error
5960+
// bytecode op as necessary, but EmitReference does not check this (by design). So we
5961+
// must manually check here.
5962+
EmitUseBeforeDeclaration(pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym, byteCodeGenerator, funcInfo);
5963+
EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
5964+
}
5965+
break;
59535966
}
5954-
else
5955-
{
5956-
// EmitLoad will check for needsDeclaration and emit the Use Before Declaration error
5957-
// bytecode op as necessary, but EmitReference does not check this (by design). So we
5958-
// must manually check here.
5959-
EmitUseBeforeDeclaration(pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym, byteCodeGenerator, funcInfo);
5960-
EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
5967+
default:
5968+
EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
5969+
break;
59615970
}
5962-
break;
5963-
}
5964-
default:
5965-
EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo);
5966-
break;
59675971
}
59685972

59695973
// Now the arg list. We evaluate everything now and emit the ArgOut's later.
@@ -5977,12 +5981,6 @@ void EmitReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncI
59775981
}
59785982
Emit(pnodeArg, byteCodeGenerator, funcInfo, false);
59795983
}
5980-
5981-
if (pnode->AsParseNodeCall()->isSuperCall)
5982-
{
5983-
Emit(pnode->AsParseNodeSuperCall()->pnodeThis, byteCodeGenerator, funcInfo, false);
5984-
Emit(pnode->AsParseNodeSuperCall()->pnodeNewTarget, byteCodeGenerator, funcInfo, false);
5985-
}
59865984
break;
59875985

59885986
default:
@@ -6961,7 +6959,14 @@ void EmitLoad(
69616959
case knopCall:
69626960
{
69636961
ParseNodeCall * pnodeCallLhs = lhs->AsParseNodeCall();
6964-
if (pnodeCallLhs->pnodeTarget->nop == knopImport)
6962+
6963+
if (pnodeCallLhs->isSuperCall)
6964+
{
6965+
funcInfo->AcquireLoc(pnodeCallLhs);
6966+
EmitReference(pnodeCallLhs, byteCodeGenerator, funcInfo);
6967+
byteCodeGenerator->EmitSuperCall(funcInfo, pnodeCallLhs->AsParseNodeSuperCall(), /*fReturnValue=*/ false);
6968+
}
6969+
else if (pnodeCallLhs->pnodeTarget->nop == knopImport)
69656970
{
69666971
ParseNodePtr args = pnodeCallLhs->pnodeArgs;
69676972
Assert(CountArguments(args) == 2); // import() takes one argument

lib/Runtime/ByteCode/FuncInfo.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,16 +341,19 @@ void FuncInfo::ReleaseReference(ParseNode *pnode)
341341
}
342342
}
343343
// Now release the call target.
344-
switch (pnode->AsParseNodeCall()->pnodeTarget->nop)
344+
if (!pnode->AsParseNodeCall()->isSuperCall)
345345
{
346-
case knopDot:
347-
case knopIndex:
348-
this->ReleaseReference(pnode->AsParseNodeCall()->pnodeTarget);
349-
this->ReleaseLoc(pnode->AsParseNodeCall()->pnodeTarget);
350-
break;
351-
default:
352-
this->ReleaseLoad(pnode->AsParseNodeCall()->pnodeTarget);
346+
switch (pnode->AsParseNodeCall()->pnodeTarget->nop)
347+
{
348+
case knopDot:
349+
case knopIndex:
350+
this->ReleaseReference(pnode->AsParseNodeCall()->pnodeTarget);
351+
this->ReleaseLoc(pnode->AsParseNodeCall()->pnodeTarget);
352+
break;
353+
default:
354+
this->ReleaseLoad(pnode->AsParseNodeCall()->pnodeTarget);
353355
break;
356+
}
354357
}
355358
break;
356359
default:

0 commit comments

Comments
 (0)