CVE-2017-11893
Description
ChakraCore and Microsoft Edge in Windows 10 1511, 1607, 1703, 1709, and Windows Server 2016 allows an attacker to execute arbitrary code in the context of the current user, due to how the scripting engine handles objects in memory, aka "Scripting Engine Memory Corruption Vulnerability". This CVE ID is unique from CVE-2017-11886, CVE-2017-11889, CVE-2017-11890, CVE-2017-11894, CVE-2017-11895, CVE-2017-11901, CVE-2017-11903, CVE-2017-11905, CVE-2017-11907, CVE-2017-11908, CVE-2017-11909, CVE-2017-11910, CVE-2017-11911, CVE-2017-11912, CVE-2017-11913, CVE-2017-11914, CVE-2017-11916, CVE-2017-11918, and CVE-2017-11930.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
Microsoft.ChakraCoreNuGet | < 1.7.5 | 1.7.5 |
Affected products
3- Microsoft Corporation/ChakraCore, Microsoft Edgev5Range: Windows 10 1511, 1607, 1703, 1709, and Windows Server 2016.
Patches
1760822c7bf4f[CVE-2017-11893] JIT Op_MaxInAnArray and Op_MinInAnArray can explicitly call user defined JavaScript functions - Google, Inc.
2 files changed · +59 −38
lib/Backend/Inline.cpp+56 −35 modified@@ -1983,19 +1983,7 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo * StackSym* originalCallTargetStackSym = callInstr->GetSrc1()->GetStackSym(); bool originalCallTargetOpndIsJITOpt = callInstr->GetSrc1()->GetIsJITOptimizedReg(); - // We are committed to inlining, optimize the call instruction for fixed fields now and don't attempt it later. - bool safeThis = false; - if (TryOptimizeCallInstrWithFixedMethod(callInstr, inlineeData, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/, safeThis /*unused here*/)) - { - Assert(callInstr->m_opcode == Js::OpCode::CallIFixed); - Assert(callInstr->GetFixedFunction()->GetFuncInfoAddr() == inlineeData->GetFunctionInfoAddr()); - } - else - { - // FunctionObject check for built-ins - IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func); - InsertFunctionObjectCheck(callInstr, callInstr, bailOutInstr, inlineeData); - } + IR::ByteCodeUsesInstr* useCallTargetInstr = EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, inlineeData, false, true, false, true); // To push function object for cases when we have to make calls to helper method to assist in inlining if(inlineCallOpCode == Js::OpCode::CallDirect) @@ -2031,11 +2019,9 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo * } } - // Insert a byteCodeUsesInstr to make sure the function object's lifetime is extended beyond the last bailout point - // at which we may need to call the inlinee again in the interpreter. + if (useCallTargetInstr) { - IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr); - useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetOpndIsJITOpt, originalCallTargetStackSym->m_id); + useCallTargetInstr->Unlink(); callInstr->InsertBefore(useCallTargetInstr); } @@ -2071,7 +2057,7 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo * // Insert a byteCodeUsesInstr to make sure the function object's lifetime is extended beyond the last bailout point // at which we may need to call the inlinee again in the interpreter. - IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr->GetPrevRealInstrOrLabel()); + useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr->GetPrevRealInstrOrLabel()); useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetOpndIsJITOpt, originalCallTargetStackSym->m_id); if(inlineCallOpCode == Js::OpCode::InlineArrayPop) @@ -2364,7 +2350,7 @@ IR::Instr* Inline::InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo * // TODO: OOP JIT enable assert (readprocessmemory?) //Assert((inlineeData->GetFunctionInfo()->GetAttributes() & Js::FunctionInfo::Attributes::BuiltInInlinableAsLdFldInlinee) != 0); - return InlineApplyWithArray(callInstr, applyData, Js::JavascriptLibrary::GetBuiltInForFuncInfo(inlineeData->GetFunctionInfoAddr(), this->topFunc->GetThreadContextInfo())); + return InlineApplyBuiltInTargetWithArray(callInstr, applyData, inlineeData); } else { @@ -2477,15 +2463,33 @@ IR::Instr * Inline::InlineApplyWithArgumentsObject(IR::Instr * callInstr, IR::In /* This method will only do CallDirect style inlining of built-in targets. No script function inlining. */ -IR::Instr * Inline::InlineApplyWithArray(IR::Instr * callInstr, const FunctionJITTimeInfo * funcInfo, Js::BuiltinFunction builtInId) +IR::Instr * Inline::InlineApplyBuiltInTargetWithArray(IR::Instr * callInstr, const FunctionJITTimeInfo * applyInfo, const FunctionJITTimeInfo * builtInInfo) { IR::Instr * implicitThisArgOut = nullptr; IR::Instr * explicitThisArgOut = nullptr; IR::Instr * arrayArgOut = nullptr; uint argOutCount = 0; this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &arrayArgOut, argOutCount); - TryFixedMethodAndPrepareInsertionPoint(callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/); + Js::OpCode originalCallOpcode = callInstr->m_opcode; + IR::Opnd * originalCallSrc1 = callInstr->GetSrc1()->Copy(this->topFunc); + IR::AutoReuseOpnd autoReuseOriginalCallSrc1(originalCallSrc1, this->topFunc); + + IR::Instr* applyLdInstr = nullptr; + IR::Instr* applyTargetLdInstr = nullptr; + if (!TryGetApplyAndTargetLdInstrs(callInstr, &applyLdInstr, &applyTargetLdInstr)) + { + return callInstr; + } + + // Fixed function/function object checks for target built-in + callInstr->ReplaceSrc1(applyTargetLdInstr->GetDst()); + EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, builtInInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/); + + // Fixed function/function object checks for .apply + callInstr->m_opcode = originalCallOpcode; + callInstr->ReplaceSrc1(originalCallSrc1); + EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/); IR::Instr* builtInEndInstr = InsertInlineeBuiltInStartEndTags(callInstr, 3); // 3 args (implicit this + explicit this + array = 3) builtInEndInstr->m_opcode = Js::OpCode::InlineNonTrackingBuiltInEnd; // We will call EndTrackCall when we see CallDirect for reasons explained in GlobOpt::TrackCalls @@ -2513,6 +2517,7 @@ IR::Instr * Inline::InlineApplyWithArray(IR::Instr * callInstr, const FunctionJI argOut = IR::Instr::New(Js::OpCode::ArgOut_A_InlineSpecialized, linkOpnd, implicitThisArgOut->GetSrc1(), argOut->GetDst(), callInstr->m_func); callInstr->InsertBefore(argOut); + Js::BuiltinFunction builtInId = Js::JavascriptLibrary::GetBuiltInForFuncInfo(builtInInfo->GetFunctionInfoAddr(), this->topFunc->GetThreadContextInfo()); IR::HelperCallOpnd * helperCallOpnd = nullptr; switch (builtInId) { @@ -2543,7 +2548,7 @@ IR::Instr * Inline::InlineApplyWithoutArrayArgument(IR::Instr *callInstr, const uint argOutCount = 0; this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &dummyInstr, argOutCount); - TryFixedMethodAndPrepareInsertionPoint(callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/); + EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/); InsertInlineeBuiltInStartEndTags(callInstr, 2); // 2 args (implicit this + explicit this) @@ -2616,6 +2621,22 @@ void Inline::GetArgInstrsForCallAndApply(IR::Instr* callInstr, IR::Instr** impli linkOpnd->AsRegOpnd()->m_sym->m_isInlinedArgSlot = true; } +bool Inline::TryGetApplyAndTargetLdInstrs(IR::Instr * callInstr, _Outptr_result_maybenull_ IR::Instr ** applyLdInstr, _Outptr_result_maybenull_ IR::Instr ** applyTargetLdInstr) +{ + IR::Opnd* applyOpnd = callInstr->GetSrc1(); + Assert(applyOpnd->IsRegOpnd()); + StackSym* applySym = applyOpnd->AsRegOpnd()->m_sym->AsStackSym(); + if (!applySym->IsSingleDef()) + { + *applyLdInstr = nullptr; + *applyTargetLdInstr = nullptr; + return false; + } + *applyLdInstr = applySym->GetInstrDef();; + *applyTargetLdInstr = (*applyLdInstr)->m_prev; + return true; +} + /* This method only inlines targets which are script functions, under the condition that the second argument (if any) passed to apply is arguments object. @@ -2637,16 +2658,13 @@ bool Inline::InlineApplyScriptTarget(IR::Instr *callInstr, const FunctionJITTime // Begin inlining apply target - IR::Opnd* applyOpnd = callInstr->GetSrc1(); - Assert(applyOpnd->IsRegOpnd()); - StackSym* applySym = applyOpnd->AsRegOpnd()->m_sym->AsStackSym(); - if (!applySym->IsSingleDef()) + IR::Instr* applyLdInstr = nullptr; + IR::Instr* applyTargetLdInstr = nullptr; + if (!TryGetApplyAndTargetLdInstrs(callInstr, &applyLdInstr, &applyTargetLdInstr)) { return false; } - IR::Instr* applyLdInstr = applySym->GetInstrDef(); - IR::Instr* applyTargetLdInstr = applyLdInstr->m_prev; - + if(applyTargetLdInstr->m_opcode != Js::OpCode::LdFldForCallApplyTarget || ((applyTargetLdInstr->AsProfiledInstr()->u.FldInfo().flags & Js::FldInfo_FromAccessor) != 0)) { @@ -2908,7 +2926,7 @@ Inline::InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, co IR::SymOpnd* orgLinkOpnd = callInstr->GetSrc2()->AsSymOpnd(); - TryFixedMethodAndPrepareInsertionPoint(callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/); + EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/); InsertInlineeBuiltInStartEndTags(callInstr, actualCount); @@ -4225,26 +4243,29 @@ Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *f return primaryBailOutInstr; } -void -Inline::TryFixedMethodAndPrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined) +IR::ByteCodeUsesInstr* +Inline::EmitFixedMethodOrFunctionObjectChecksForBuiltIns(IR::Instr *callInstr, IR::Instr * funcObjCheckInsertInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined) { StackSym* originalCallTargetStackSym = callInstr->GetSrc1()->GetStackSym(); bool originalCallTargetIsJITOpt = callInstr->GetSrc1()->GetIsJITOptimizedReg(); + IR::ByteCodeUsesInstr * useCallTargetInstr = nullptr; bool safeThis = false; if (TryOptimizeCallInstrWithFixedMethod(callInstr, inlineeInfo, isPolymorphic, isBuiltIn, isCtor, isInlined, safeThis)) { Assert(callInstr->m_opcode == Js::OpCode::CallIFixed); - + Assert(callInstr->GetFixedFunction()->GetFuncInfoAddr() == inlineeInfo->GetFunctionInfoAddr()); // If we optimized the call instruction for a fixed function, we must extend the function object's lifetime until after the last bailout before the call. - IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr); + useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr); useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetIsJITOpt, originalCallTargetStackSym->m_id); callInstr->InsertBefore(useCallTargetInstr); } else { - PrepareInsertionPoint(callInstr, inlineeInfo, callInstr); + IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func); + InsertFunctionObjectCheck(callInstr, funcObjCheckInsertInstr, bailOutInstr, inlineeInfo); } + return useCallTargetInstr; } uint Inline::CountActuals(IR::Instr *callInstr)
lib/Backend/Inline.h+3 −3 modified@@ -47,13 +47,13 @@ class Inline IR::Instr * SimulateCallForGetterSetter(IR::Instr *accessorInstr, IR::Instr* insertInstr, IR::PropertySymOpnd* methodOpnd, bool isGetter); IR::Instr * InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo * applyData, const FunctionJITTimeInfo * inlinerData, const StackSym *symThis, bool* pIsInlined, uint callSiteId, uint recursiveInlineDepth, uint argsCount); - IR::Instr * InlineApplyWithArray(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, Js::BuiltinFunction builtInId); + IR::Instr * InlineApplyBuiltInTargetWithArray(IR::Instr *callInstr, const FunctionJITTimeInfo * applyInfo, const FunctionJITTimeInfo * builtInInfo); IR::Instr * InlineApplyWithArgumentsObject(IR::Instr * callInstr, IR::Instr * argsObjectArgInstr, const FunctionJITTimeInfo * inlineeInfo); IR::Instr * InlineApplyWithoutArrayArgument(IR::Instr *callInstr, const FunctionJITTimeInfo * applyInfo, const FunctionJITTimeInfo * applyTargetInfo); bool InlineApplyScriptTarget(IR::Instr *callInstr, const FunctionJITTimeInfo* inlinerData, const FunctionJITTimeInfo** pInlineeData, const FunctionJITTimeInfo * applyFuncInfo, const StackSym *symThis, IR::Instr ** returnInstr, uint recursiveInlineDepth, bool isArrayOpndArgumentsObject, uint argsCount); void GetArgInstrsForCallAndApply(IR::Instr* callInstr, IR::Instr** implicitThisArgOut, IR::Instr** explicitThisArgOut, IR::Instr** argumentsOrArrayArgOut, uint &argOutCount); - + bool TryGetApplyAndTargetLdInstrs(IR::Instr * callInstr, _Outptr_result_maybenull_ IR::Instr ** applyLdInstr, _Outptr_result_maybenull_ IR::Instr ** applyTargetLdInstr); IR::Instr * InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeData, const FunctionJITTimeInfo * inlinerData, const StackSym *symThis, bool* pIsInlined, uint callSiteId, uint recursiveInlineDepth); bool InlineCallTarget(IR::Instr *callInstr, const FunctionJITTimeInfo* inlinerData, const FunctionJITTimeInfo** pInlineeData, const FunctionJITTimeInfo *callFuncInfo, const StackSym *symThis, IR::Instr ** returnInstr, uint recursiveInlineDepth); @@ -83,7 +83,7 @@ class Inline void FixupExtraActualParams(IR::Instr * instr, IR::Instr *argOuts[], IR::Instr *argOutsExtra[], uint index, uint actualCount, Js::ProfileId callSiteId); void RemoveExtraFixupArgouts(IR::Instr* instr, uint argoutRemoveCount, Js::ProfileId callSiteId); IR::Instr* PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind = IR::BailOutOnInlineFunction); - void TryFixedMethodAndPrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined); + IR::ByteCodeUsesInstr* EmitFixedMethodOrFunctionObjectChecksForBuiltIns(IR::Instr *callInstr, IR::Instr * funcObjCheckInsertInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined); Js::ArgSlot MapActuals(IR::Instr *callInstr, __out_ecount(maxParamCount) IR::Instr *argOuts[], Js::ArgSlot formalCount, Func *inlinee, Js::ProfileId callSiteId, bool *stackArgsArgOutExpanded, IR::Instr *argOutsExtra[] = nullptr, Js::ArgSlot maxParamCount = Js::InlineeCallInfo::MaxInlineeArgoutCount); uint32 CountActuals(IR::Instr *callIntr); void MapFormals(Func *inlinee, __in_ecount(formalCount) IR::Instr *argOuts[], uint formalCount, uint actualCount, IR::RegOpnd *retOpnd, IR::Opnd * funcObjOpnd, const StackSym *symCallerThis, bool stackArgsArgOutExpanded, bool fixedFunctionSafeThis = false, IR::Instr *argOutsExtra[] = nullptr);
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
11- portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-11893nvdPatchVendor AdvisoryWEB
- www.exploit-db.com/exploits/43466/nvdExploitThird Party AdvisoryVDB Entry
- www.securityfocus.com/bid/102081nvdThird Party AdvisoryVDB Entry
- www.securitytracker.com/id/1039990nvdThird Party AdvisoryVDB Entry
- github.com/advisories/GHSA-c6r3-ghjw-hgrjghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2017-11893ghsaADVISORY
- github.com/chakra-core/ChakraCore/commit/760822c7bf4ffd5e773da14bc35d9c07d672f0c7ghsaWEB
- github.com/chakra-core/ChakraCore/pull/4411ghsaWEB
- web.archive.org/web/20210124122701/http://www.securityfocus.com/bid/102081ghsaWEB
- web.archive.org/web/20210829201729/http://www.securitytracker.com/id/1039990ghsaWEB
- www.exploit-db.com/exploits/43466ghsaWEB
News mentions
0No linked articles in our index yet.