VYPR
High severity7.5NVD Advisory· Published Dec 12, 2017· Updated May 13, 2026

CVE-2017-11893

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.

PackageAffected versionsPatched versions
Microsoft.ChakraCoreNuGet
< 1.7.51.7.5

Affected products

3
  • cpe:2.3:a:microsoft:chakracore:*:*:*:*:*:*:*:*
    Range: <1.7.5
  • cpe:2.3:a:microsoft:edge:-:*:*:*:*:*:*:*
  • Microsoft Corporation/ChakraCore, Microsoft Edgev5
    Range: Windows 10 1511, 1607, 1703, 1709, and Windows Server 2016.

Patches

1
760822c7bf4f

[CVE-2017-11893] JIT Op_MaxInAnArray and Op_MinInAnArray can explicitly call user defined JavaScript functions - Google, Inc.

https://github.com/chakra-core/ChakraCoreRajat DuaNov 29, 2017via ghsa
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

News mentions

0

No linked articles in our index yet.