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

CVE-2017-11797

CVE-2017-11797

Description

ChakraCore allows an attacker to execute arbitrary code in the context of the current user, due to how the ChakraCore scripting engine handles objects in memory, aka "Scripting Engine Information Disclosure Vulnerability". This CVE ID is unique from CVE-2017-11792, CVE-2017-11793, CVE-2017-11796, CVE-2017-11798, CVE-2017-11799, CVE-2017-11800, CVE-2017-11801, CVE-2017-11802, CVE-2017-11804, CVE-2017-11805, CVE-2017-11806, CVE-2017-11807, CVE-2017-11808, CVE-2017-11809, CVE-2017-11810, CVE-2017-11811, CVE-2017-11812, and CVE-2017-11821.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
Microsoft.ChakraCoreNuGet
< 1.7.31.7.3

Affected products

2
  • cpe:2.3:a:microsoft:chakracore:*:*:*:*:*:*:*:*
    Range: <=1.7.2
  • Microsoft Corporation/ChakraCorev5
    Range: ChakraCore

Patches

1
9a3ad7ccba1f

[CVE-2017-11797] Invalid memory read of out params on a bailout when array destructuring is used as call arg

https://github.com/chakra-core/ChakraCoreAkrosh GandhiAug 18, 2017via ghsa
4 files changed · +172 58
  • lib/Parser/Parse.cpp+9 1 modified
    @@ -90,6 +90,8 @@ Parser::Parser(Js::ScriptContext* scriptContext, BOOL strictMode, PageAllocator
         m_stoppedDeferredParse = FALSE;
         m_hasParallelJob = false;
         m_doingFastScan = false;
    +    m_isInParsingArgList = false;
    +    m_hasDestructuringPattern = false;
         m_scriptContext = scriptContext;
         m_pCurrentAstSize = nullptr;
         m_arrayDepth = 0;
    @@ -1252,7 +1254,7 @@ Parser::CreateCallNode(OpCode nop, ParseNodePtr pnode1, ParseNodePtr pnode2,char
         pnode->sxCall.isApplyCall = false;
         pnode->sxCall.isEvalCall = false;
         pnode->sxCall.isSuperCall = false;
    -
    +    pnode->sxCall.hasDestructuring = false;
         pnode->ichMin = ichMin;
         pnode->ichLim = ichLim;
     
    @@ -3660,6 +3662,7 @@ ParseNodePtr Parser::ParsePostfixOperators(
             {
             case tkLParen:
                 {
    +                AutoMarkInParsingArgs autoMarkInParsingArgs(this);
                     if (fInNew)
                     {
                         ParseNodePtr pnodeArgs = ParseArgList<buildAST>(&callOfConstants, &spreadArgCount, &count);
    @@ -3672,6 +3675,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
                             pnode->sxCall.isApplyCall = false;
                             pnode->sxCall.isEvalCall = false;
                             pnode->sxCall.isSuperCall = false;
    +                        pnode->sxCall.hasDestructuring = m_hasDestructuringPattern;
    +                        Assert(!m_hasDestructuringPattern || count > 0);
                             pnode->sxCall.argCount = count;
                             pnode->sxCall.spreadArgCount = spreadArgCount;
                             pnode->ichLim = m_pscan->IchLimTok();
    @@ -3743,6 +3748,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
                             pnode->sxCall.spreadArgCount = spreadArgCount;
                             pnode->sxCall.isApplyCall = false;
                             pnode->sxCall.isEvalCall = fCallIsEval;
    +                        pnode->sxCall.hasDestructuring = m_hasDestructuringPattern;
    +                        Assert(!m_hasDestructuringPattern || count > 0);
                             pnode->sxCall.argCount = count;
                             pnode->ichLim = m_pscan->IchLimTok();
                         }
    @@ -8630,6 +8637,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
     
                 if (buildAST)
                 {
    +                this->SetHasDestructuringPattern(true);
                     pnode = ConvertToPattern(pnode);
                 }
     
    
  • lib/Parser/Parse.h+32 1 modified
    @@ -136,6 +136,12 @@ class Parser
         bool IsBackgroundParser() const { return m_isInBackground; }
         bool IsDoingFastScan() const { return m_doingFastScan; }
     
    +    bool GetIsInParsingArgList() const { return m_isInParsingArgList; }
    +    void SetIsInParsingArgList(bool set) { m_isInParsingArgList = set; }
    +
    +    bool GetHasDestructuringPattern() const { return m_hasDestructuringPattern; }
    +    void SetHasDestructuringPattern(bool set) { m_hasDestructuringPattern = set; }
    +
         static IdentPtr PidFromNode(ParseNodePtr pnode);
     
         ParseNode* CopyPnode(ParseNode* pnode);
    @@ -395,7 +401,8 @@ class Parser
         bool m_isInBackground;
         bool m_reparsingLambdaParams;
         bool m_disallowImportExportStmt;
    -
    +    bool m_isInParsingArgList;
    +    bool m_hasDestructuringPattern;
         // This bool is used for deferring the shorthand initializer error ( {x = 1}) - as it is allowed in the destructuring grammar.
         bool m_hasDeferredShorthandInitError;
         uint * m_pnestedCount; // count of functions nested at one level below the current node
    @@ -1110,6 +1117,30 @@ class Parser
             }
         };
     
    +    class AutoMarkInParsingArgs
    +    {
    +    public:
    +        AutoMarkInParsingArgs(Parser * parser)
    +            : m_parser(parser)
    +        {
    +            m_prevState = m_parser->GetIsInParsingArgList();
    +            m_parser->SetHasDestructuringPattern(false);
    +            m_parser->SetIsInParsingArgList(true);
    +        }
    +        ~AutoMarkInParsingArgs()
    +        {
    +            m_parser->SetIsInParsingArgList(m_prevState);
    +            if (!m_prevState)
    +            {
    +                m_parser->SetHasDestructuringPattern(false);
    +            }
    +        }
    +
    +    private:
    +        Parser *m_parser;
    +        bool m_prevState;
    +    };
    +
     public:
         charcount_t GetSourceIchLim() { return m_sourceLim; }
         static BOOL NodeEqualsName(ParseNodePtr pnode, LPCOLESTR sz, uint32 cch);
    
  • lib/Parser/ptree.h+1 0 modified
    @@ -459,6 +459,7 @@ struct PnCall
         BYTE isApplyCall : 1;
         BYTE isEvalCall : 1;
         BYTE isSuperCall : 1;
    +    BYTE hasDestructuring : 1;
     };
     
     struct PnStmt
    
  • lib/Runtime/ByteCode/ByteCodeEmitter.cpp+130 56 modified
    @@ -6879,12 +6879,112 @@ void EmitList(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *
         }
     }
     
    -void EmitSpreadArgToListBytecodeInstr(ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo, Js::RegSlot argLoc, Js::ProfileId callSiteId, Js::ArgSlot &argIndex)
    +void EmitOneArg(
    +    ParseNode *pnode,
    +    BOOL fAssignRegs,
    +    ByteCodeGenerator *byteCodeGenerator,
    +    FuncInfo *funcInfo,
    +    Js::ProfileId callSiteId,
    +    Js::ArgSlot &argIndex,
    +    Js::ArgSlot &spreadIndex,
    +    Js::RegSlot argTempLocation,
    +    Js::AuxArray<uint32> *spreadIndices = nullptr
    +)
     {
    -    Js::RegSlot regVal = funcInfo->AcquireTmpRegister();
    -    byteCodeGenerator->Writer()->Reg2(Js::OpCode::LdCustomSpreadIteratorList, regVal, argLoc);
    -    byteCodeGenerator->Writer()->ArgOut<true>(++argIndex, regVal, callSiteId);
    -    funcInfo->ReleaseTmpRegister(regVal);
    +    bool noArgOuts = argTempLocation != Js::Constants::NoRegister;
    +
    +    // If this is a put, the arguments have already been evaluated (see EmitReference).
    +    // We just need to emit the ArgOut instructions.
    +    if (fAssignRegs)
    +    {
    +        Emit(pnode, byteCodeGenerator, funcInfo, false);
    +    }
    +
    +    if (pnode->nop == knopEllipsis)
    +    {
    +        Assert(spreadIndices != nullptr);
    +        spreadIndices->elements[spreadIndex++] = argIndex + 1; // account for 'this'
    +        Js::RegSlot regVal = funcInfo->AcquireTmpRegister();
    +        byteCodeGenerator->Writer()->Reg2(Js::OpCode::LdCustomSpreadIteratorList, regVal, pnode->location);
    +        if (noArgOuts)
    +        {
    +            byteCodeGenerator->Writer()->Reg2(Js::OpCode::Ld_A, argTempLocation, regVal);
    +        }
    +        else
    +        {
    +            byteCodeGenerator->Writer()->ArgOut<true>(argIndex + 1, regVal, callSiteId);
    +        }
    +        funcInfo->ReleaseTmpRegister(regVal);
    +    }
    +    else
    +    {
    +        if (noArgOuts)
    +        {
    +            byteCodeGenerator->Writer()->Reg2(Js::OpCode::Ld_A, argTempLocation, pnode->location);
    +        }
    +        else
    +        {
    +            byteCodeGenerator->Writer()->ArgOut<true>(argIndex + 1, pnode->location, callSiteId);
    +        }
    +    }
    +    argIndex++;
    +
    +    if (fAssignRegs)
    +    {
    +        funcInfo->ReleaseLoc(pnode);
    +    }
    +}
    +
    +size_t EmitArgsWithArgOutsAtEnd(
    +    ParseNode *pnode,
    +    BOOL fAssignRegs,
    +    ByteCodeGenerator *byteCodeGenerator,
    +    FuncInfo *funcInfo,
    +    Js::ProfileId callSiteId,
    +    Js::RegSlot thisLocation,
    +    Js::ArgSlot argsCountForStartCall,
    +    Js::AuxArray<uint32> *spreadIndices = nullptr
    +)
    +{
    +    AssertOrFailFast(pnode != nullptr);
    +
    +    Js::ArgSlot argIndex = 0;
    +    Js::ArgSlot spreadIndex = 0;
    +
    +    Js::RegSlot argTempLocation = funcInfo->AcquireTmpRegister();
    +    Js::RegSlot firstArgTempLocation = argTempLocation;
    +
    +    while (pnode->nop == knopList)
    +    {
    +        EmitOneArg(pnode->sxBin.pnode1, fAssignRegs, byteCodeGenerator, funcInfo, callSiteId, argIndex, spreadIndex, argTempLocation, spreadIndices);
    +        pnode = pnode->sxBin.pnode2;
    +        argTempLocation = funcInfo->AcquireTmpRegister();
    +    }
    +
    +    EmitOneArg(pnode, fAssignRegs, byteCodeGenerator, funcInfo, callSiteId, argIndex, spreadIndex, argTempLocation, spreadIndices);
    +
    +    byteCodeGenerator->Writer()->StartCall(Js::OpCode::StartCall, argsCountForStartCall);
    +
    +    // Emit all argOuts now
    +
    +    if (thisLocation != Js::Constants::NoRegister)
    +    {
    +        // Emit the "this" object.
    +        byteCodeGenerator->Writer()->ArgOut<true>(0, thisLocation, callSiteId);
    +    }
    +
    +    for (Js::ArgSlot index = 0; index < argIndex; index++)
    +    {
    +        byteCodeGenerator->Writer()->ArgOut<true>(index + 1, firstArgTempLocation + index, callSiteId);
    +    }
    +
    +    // Now release all those temps register
    +    for (Js::ArgSlot index = argIndex; index > 0; index--)
    +    {
    +        funcInfo->ReleaseTmpRegister(argTempLocation--);
    +    }
    +
    +    return argIndex;
     }
     
     size_t EmitArgs(
    @@ -6903,57 +7003,18 @@ size_t EmitArgs(
         {
             while (pnode->nop == knopList)
             {
    -            // If this is a put, the arguments have already been evaluated (see EmitReference).
    -            // We just need to emit the ArgOut instructions.
    -            if (fAssignRegs)
    -            {
    -                Emit(pnode->sxBin.pnode1, byteCodeGenerator, funcInfo, false);
    -            }
    -
    -            if (pnode->sxBin.pnode1->nop == knopEllipsis)
    -            {
    -                Assert(spreadIndices != nullptr);
    -                spreadIndices->elements[spreadIndex++] = argIndex + 1; // account for 'this'
    -                EmitSpreadArgToListBytecodeInstr(byteCodeGenerator, funcInfo, pnode->sxBin.pnode1->location, callSiteId, argIndex);
    -            }
    -            else
    -            {
    -                byteCodeGenerator->Writer()->ArgOut<true>(++argIndex, pnode->sxBin.pnode1->location, callSiteId);
    -            }
    -            if (fAssignRegs)
    -            {
    -                funcInfo->ReleaseLoc(pnode->sxBin.pnode1);
    -            }
    -
    +            EmitOneArg(pnode->sxBin.pnode1, fAssignRegs, byteCodeGenerator, funcInfo, callSiteId, argIndex, spreadIndex, Js::Constants::NoRegister, spreadIndices);
                 pnode = pnode->sxBin.pnode2;
             }
     
    -        // If this is a put, the call target has already been evaluated (see EmitReference).
    -        if (fAssignRegs)
    -        {
    -            Emit(pnode, byteCodeGenerator, funcInfo, false);
    -        }
    -
    -        if (pnode->nop == knopEllipsis)
    -        {
    -            Assert(spreadIndices != nullptr);
    -            spreadIndices->elements[spreadIndex++] = argIndex + 1; // account for 'this'
    -            EmitSpreadArgToListBytecodeInstr(byteCodeGenerator, funcInfo, pnode->location, callSiteId, argIndex);
    -        }
    -        else
    -        {
    -            byteCodeGenerator->Writer()->ArgOut<true>(++argIndex, pnode->location, callSiteId);
    -        }
    -
    -        if (fAssignRegs)
    -        {
    -            funcInfo->ReleaseLoc(pnode);
    -        }
    +        EmitOneArg(pnode, fAssignRegs, byteCodeGenerator, funcInfo, callSiteId, argIndex, spreadIndex, Js::Constants::NoRegister, spreadIndices);
         }
     
         return argIndex;
     }
     
    +
    +
     void EmitArgListStart(
         Js::RegSlot thisLocation,
         ByteCodeGenerator *byteCodeGenerator,
    @@ -7074,13 +7135,18 @@ Js::ArgSlot EmitArgList(
         ByteCodeGenerator *byteCodeGenerator,
         FuncInfo *funcInfo,
         Js::ProfileId callSiteId,
    +    Js::ArgSlot argsCountForStartCall,
    +    bool emitArgOutsAtEnd,
         uint16 spreadArgCount = 0,
         Js::AuxArray<uint32> **spreadIndices = nullptr)
     {
         // This function emits the arguments for a call.
         // ArgOut's with uses immediately following defs.
    -
    -    EmitArgListStart(thisLocation, byteCodeGenerator, funcInfo, callSiteId);
    +    if (!emitArgOutsAtEnd)
    +    {
    +        byteCodeGenerator->Writer()->StartCall(Js::OpCode::StartCall, argsCountForStartCall);
    +        EmitArgListStart(thisLocation, byteCodeGenerator, funcInfo, callSiteId);
    +    }
     
         Js::RegSlot evalLocation = Js::Constants::NoRegister;
     
    @@ -7100,7 +7166,15 @@ Js::ArgSlot EmitArgList(
             *spreadIndices = AnewPlus(byteCodeGenerator->GetAllocator(), extraAlloc, Js::AuxArray<uint32>, spreadArgCount);
         }
     
    -    size_t argIndex = EmitArgs(pnode, fAssignRegs, byteCodeGenerator, funcInfo, callSiteId, spreadIndices == nullptr ? nullptr : *spreadIndices);
    +    size_t argIndex = 0;
    +    if (emitArgOutsAtEnd)
    +    {
    +        argIndex = EmitArgsWithArgOutsAtEnd(pnode, fAssignRegs, byteCodeGenerator, funcInfo, callSiteId, thisLocation, argsCountForStartCall, spreadIndices == nullptr ? nullptr : *spreadIndices);
    +    }
    +    else
    +    {
    +        argIndex = EmitArgs(pnode, fAssignRegs, byteCodeGenerator, funcInfo, callSiteId, spreadIndices == nullptr ? nullptr : *spreadIndices);
    +    }
     
         Js::ArgSlot argumentsCount = EmitArgListEnd(pnode, rhsLocation, thisLocation, evalLocation, newTargetLocation, byteCodeGenerator, funcInfo, argIndex, callSiteId);
     
    @@ -7855,11 +7929,12 @@ void EmitNew(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, FuncInfo* f
         }
         else
         {
    -        byteCodeGenerator->Writer()->StartCall(Js::OpCode::StartCall, argCount);
    +
             uint32 actualArgCount = 0;
     
             if (IsCallOfConstants(pnode))
             {
    +            byteCodeGenerator->Writer()->StartCall(Js::OpCode::StartCall, argCount);
                 funcInfo->ReleaseLoc(pnode->sxCall.pnodeTarget);
                 actualArgCount = EmitNewObjectOfConstants(pnode, byteCodeGenerator, funcInfo, argCount);
             }
    @@ -7880,10 +7955,9 @@ void EmitNew(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, FuncInfo* f
     
                 Js::AuxArray<uint32> *spreadIndices = nullptr;
                 actualArgCount = EmitArgList(pnode->sxCall.pnodeArgs, Js::Constants::NoRegister, Js::Constants::NoRegister, Js::Constants::NoRegister,
    -                false, true, byteCodeGenerator, funcInfo, callSiteId, pnode->sxCall.spreadArgCount, &spreadIndices);
    +                false, true, byteCodeGenerator, funcInfo, callSiteId, argCount, pnode->sxCall.hasDestructuring, pnode->sxCall.spreadArgCount, &spreadIndices);
                 funcInfo->ReleaseLoc(pnode->sxCall.pnodeTarget);
     
    -
                 if (pnode->sxCall.spreadArgCount > 0)
                 {
                     Assert(spreadIndices != nullptr);
    @@ -8025,9 +8099,9 @@ void EmitCall(
     
         Js::ProfileId callSiteId = byteCodeGenerator->GetNextCallSiteId(Js::OpCode::CallI);
     
    -    byteCodeGenerator->Writer()->StartCall(Js::OpCode::StartCall, argSlotCount);
         Js::AuxArray<uint32> *spreadIndices;
    -    Js::ArgSlot actualArgCount = EmitArgList(pnodeArgs, rhsLocation, thisLocation, newTargetLocation, fIsEval, fEvaluateComponents, byteCodeGenerator, funcInfo, callSiteId, spreadArgCount, &spreadIndices);
    +    Js::ArgSlot actualArgCount = EmitArgList(pnodeArgs, rhsLocation, thisLocation, newTargetLocation, fIsEval, fEvaluateComponents, byteCodeGenerator, funcInfo, callSiteId, argSlotCount, pnode->sxCall.hasDestructuring, spreadArgCount, &spreadIndices);
    +
         Assert(argSlotCount == actualArgCount);
     
         if (!fEvaluateComponents)
    

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

7

News mentions

0

No linked articles in our index yet.