CVE-2017-11871
Description
ChakraCore and Microsoft Edge in Windows 10 1703, 1709, and Windows Server, version 1709 allows an attacker to gain the same user rights as 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-11836, CVE-2017-11837, CVE-2017-11838, CVE-2017-11839, CVE-2017-11840, CVE-2017-11841, CVE-2017-11843, CVE-2017-11846, CVE-2017-11858, CVE-2017-11859, CVE-2017-11861, CVE-2017-11862, CVE-2017-11866, CVE-2017-11869, CVE-2017-11870, and CVE-2017-11873.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
Microsoft.ChakraCoreNuGet | < 1.7.4 | 1.7.4 |
Affected products
3- cpe:2.3:a:microsoft:chakracore:-:*:*:*:*:*:*:*
- Microsoft Corporation/ChakraCore, Microsoft Edgev5Range: Windows 10 1703, 1709, and Windows Server, version 1709.
Patches
19d211a417757[CVE-2017-11871] Redeferal - Invalid pointer read during native codegen for function objects with inline cache
3 files changed · +157 −129
lib/Backend/NativeCodeGenerator.cpp+140 −123 modified@@ -2331,130 +2331,137 @@ NativeCodeGenerator::GatherCodeGenData( bool isPolymorphic = (cacheType & Js::FldInfo_Polymorphic) != 0; if (!isPolymorphic) { - Js::InlineCache *inlineCache; + Js::InlineCache *inlineCache = nullptr; + if(function && Js::ScriptFunctionWithInlineCache::Is(function)) { - inlineCache = Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(i); + if (Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCaches() != nullptr) + { + inlineCache = Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(i); + } } else { inlineCache = functionBody->GetInlineCache(i); } - ObjTypeSpecFldInfo* objTypeSpecFldInfo = nullptr; + if (inlineCache != nullptr) + { + ObjTypeSpecFldInfo* objTypeSpecFldInfo = nullptr; #if ENABLE_DEBUG_CONFIG_OPTIONS - if (PHASE_VERBOSE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_VERBOSE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody)) - { - char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]; - Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(i); - Js::PropertyRecord const * const propertyRecord = functionBody->GetScriptContext()->GetPropertyName(propertyId); - Output::Print(_u("ObTypeSpec: top function %s (%s), function %s (%s): cloning mono cache for %s (#%d) cache %d \n"), - topFunctionBody->GetDisplayName(), topFunctionBody->GetDebugNumberSet(debugStringBuffer), - functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer2), propertyRecord->GetBuffer(), propertyId, i); - Output::Flush(); - } + if (PHASE_VERBOSE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_VERBOSE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody)) + { + char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]; + Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(i); + Js::PropertyRecord const * const propertyRecord = functionBody->GetScriptContext()->GetPropertyName(propertyId); + Output::Print(_u("ObTypeSpec: top function %s (%s), function %s (%s): cloning mono cache for %s (#%d) cache %d \n"), + topFunctionBody->GetDisplayName(), topFunctionBody->GetDebugNumberSet(debugStringBuffer), + functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer2), propertyRecord->GetBuffer(), propertyId, i); + Output::Flush(); + } #endif - IncInlineCacheCount(monoInlineCacheCount); + IncInlineCacheCount(monoInlineCacheCount); - if (inlineCache->IsEmpty()) - { - IncInlineCacheCount(emptyMonoInlineCacheCount); - } + if (inlineCache->IsEmpty()) + { + IncInlineCacheCount(emptyMonoInlineCacheCount); + } - if(!PHASE_OFF(Js::ObjTypeSpecPhase, functionBody) || !PHASE_OFF(Js::FixedMethodsPhase, functionBody) || !PHASE_OFF(Js::UseFixedDataPropsPhase, functionBody)) - { - if(cacheType & (Js::FldInfo_FromLocal | Js::FldInfo_FromLocalWithoutProperty | Js::FldInfo_FromProto)) + if(!PHASE_OFF(Js::ObjTypeSpecPhase, functionBody) || !PHASE_OFF(Js::FixedMethodsPhase, functionBody) || !PHASE_OFF(Js::UseFixedDataPropsPhase, functionBody)) { - // WinBlue 170722: Disable ObjTypeSpec optimization for activation object in debug mode, - // as it can result in BailOutFailedTypeCheck before locals are set to undefined, - // which can result in using garbage object during bailout/restore values. - if (!(functionBody->IsInDebugMode() && inlineCache->GetType() && - inlineCache->GetType()->GetTypeId() == Js::TypeIds_ActivationObject)) + if(cacheType & (Js::FldInfo_FromLocal | Js::FldInfo_FromLocalWithoutProperty | Js::FldInfo_FromProto)) { - objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData)); - if (objTypeSpecFldInfo) + // WinBlue 170722: Disable ObjTypeSpec optimization for activation object in debug mode, + // as it can result in BailOutFailedTypeCheck before locals are set to undefined, + // which can result in using garbage object during bailout/restore values. + if (!(functionBody->IsInDebugMode() && inlineCache->GetType() && + inlineCache->GetType()->GetTypeId() == Js::TypeIds_ActivationObject)) { - IncInlineCacheCount(clonedMonoInlineCacheCount); - - if (!PHASE_OFF(Js::InlineApplyTargetPhase, functionBody) && (cacheType & Js::FldInfo_InlineCandidate)) + objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData)); + if (objTypeSpecFldInfo) { - if (IsInlinee || objTypeSpecFldInfo->IsBuiltin()) + IncInlineCacheCount(clonedMonoInlineCacheCount); + + if (!PHASE_OFF(Js::InlineApplyTargetPhase, functionBody) && (cacheType & Js::FldInfo_InlineCandidate)) { - inlineApplyTarget = true; + if (IsInlinee || objTypeSpecFldInfo->IsBuiltin()) + { + inlineApplyTarget = true; + } } - } - if (!PHASE_OFF(Js::InlineCallTargetPhase, functionBody) && (cacheType & Js::FldInfo_InlineCandidate)) - { - inlineCallTarget = true; - } - if (!isJitTimeDataComputed) - { - jitTimeData->GetObjTypeSpecFldInfoArray()->SetInfo(recycler, functionBody, i, objTypeSpecFldInfo); - objTypeSpecFldInfoList->Prepend(objTypeSpecFldInfo); + if (!PHASE_OFF(Js::InlineCallTargetPhase, functionBody) && (cacheType & Js::FldInfo_InlineCandidate)) + { + inlineCallTarget = true; + } + if (!isJitTimeDataComputed) + { + jitTimeData->GetObjTypeSpecFldInfoArray()->SetInfo(recycler, functionBody, i, objTypeSpecFldInfo); + objTypeSpecFldInfoList->Prepend(objTypeSpecFldInfo); + } } } } } - } - if(!PHASE_OFF(Js::FixAccessorPropsPhase, functionBody)) - { - if (!objTypeSpecFldInfo && (cacheType & Js::FldInfo_FromAccessor) && (cacheType & Js::FldInfo_InlineCandidate)) + if(!PHASE_OFF(Js::FixAccessorPropsPhase, functionBody)) { - objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData)); - if (objTypeSpecFldInfo) + if (!objTypeSpecFldInfo && (cacheType & Js::FldInfo_FromAccessor) && (cacheType & Js::FldInfo_InlineCandidate)) { - inlineGetterSetter = true; - if (!isJitTimeDataComputed) + objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData)); + if (objTypeSpecFldInfo) { - IncInlineCacheCount(clonedMonoInlineCacheCount); - jitTimeData->GetObjTypeSpecFldInfoArray()->SetInfo(recycler, functionBody, i, objTypeSpecFldInfo); - objTypeSpecFldInfoList->Prepend(objTypeSpecFldInfo); + inlineGetterSetter = true; + if (!isJitTimeDataComputed) + { + IncInlineCacheCount(clonedMonoInlineCacheCount); + jitTimeData->GetObjTypeSpecFldInfoArray()->SetInfo(recycler, functionBody, i, objTypeSpecFldInfo); + objTypeSpecFldInfoList->Prepend(objTypeSpecFldInfo); + } } - } + } } - } - if (!PHASE_OFF(Js::RootObjectFldFastPathPhase, functionBody)) - { - if (i >= functionBody->GetRootObjectLoadInlineCacheStart() && inlineCache->IsLocal()) + if (!PHASE_OFF(Js::RootObjectFldFastPathPhase, functionBody)) { - void * rawType = inlineCache->u.local.type; - Js::Type * type = TypeWithoutAuxSlotTag(rawType); - Js::RootObjectBase * rootObject = functionBody->GetRootObject(); - if (rootObject->GetType() == type) + if (i >= functionBody->GetRootObjectLoadInlineCacheStart() && inlineCache->IsLocal()) { - Js::BigPropertyIndex propertyIndex = inlineCache->u.local.slotIndex; - if (rawType == type) + void * rawType = inlineCache->u.local.type; + Js::Type * type = TypeWithoutAuxSlotTag(rawType); + Js::RootObjectBase * rootObject = functionBody->GetRootObject(); + if (rootObject->GetType() == type) { - // type is not tagged, inline slot - propertyIndex = rootObject->GetPropertyIndexFromInlineSlotIndex(inlineCache->u.local.slotIndex); - } - else - { - propertyIndex = rootObject->GetPropertyIndexFromAuxSlotIndex(inlineCache->u.local.slotIndex); - } - Js::PropertyAttributes attributes; - if (rootObject->GetAttributesWithPropertyIndex(functionBody->GetPropertyIdFromCacheId(i), propertyIndex, &attributes) - && (attributes & PropertyConfigurable) == 0 - && !isJitTimeDataComputed) - { - // non configurable - if (objTypeSpecFldInfo == nullptr) + Js::BigPropertyIndex propertyIndex = inlineCache->u.local.slotIndex; + if (rawType == type) { - objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData)); - if (objTypeSpecFldInfo) - { - IncInlineCacheCount(clonedMonoInlineCacheCount); - jitTimeData->GetObjTypeSpecFldInfoArray()->SetInfo(recycler, functionBody, i, objTypeSpecFldInfo); - objTypeSpecFldInfoList->Prepend(objTypeSpecFldInfo); - } + // type is not tagged, inline slot + propertyIndex = rootObject->GetPropertyIndexFromInlineSlotIndex(inlineCache->u.local.slotIndex); } - if (objTypeSpecFldInfo != nullptr) + else { - objTypeSpecFldInfo->SetRootObjectNonConfigurableField(i < functionBody->GetRootObjectStoreInlineCacheStart()); + propertyIndex = rootObject->GetPropertyIndexFromAuxSlotIndex(inlineCache->u.local.slotIndex); + } + Js::PropertyAttributes attributes; + if (rootObject->GetAttributesWithPropertyIndex(functionBody->GetPropertyIdFromCacheId(i), propertyIndex, &attributes) + && (attributes & PropertyConfigurable) == 0 + && !isJitTimeDataComputed) + { + // non configurable + if (objTypeSpecFldInfo == nullptr) + { + objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData)); + if (objTypeSpecFldInfo) + { + IncInlineCacheCount(clonedMonoInlineCacheCount); + jitTimeData->GetObjTypeSpecFldInfoArray()->SetInfo(recycler, functionBody, i, objTypeSpecFldInfo); + objTypeSpecFldInfoList->Prepend(objTypeSpecFldInfo); + } + } + if (objTypeSpecFldInfo != nullptr) + { + objTypeSpecFldInfo->SetRootObjectNonConfigurableField(i < functionBody->GetRootObjectStoreInlineCacheStart()); + } } } } @@ -2464,33 +2471,36 @@ NativeCodeGenerator::GatherCodeGenData( // Even if the FldInfo says that the field access may be polymorphic, be optimistic that if the function object has inline caches, they'll be monomorphic else if(function && Js::ScriptFunctionWithInlineCache::Is(function) && (cacheType & Js::FldInfo_InlineCandidate || !polymorphicCacheOnFunctionBody)) { - Js::InlineCache *inlineCache = Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(i); - ObjTypeSpecFldInfo* objTypeSpecFldInfo = nullptr; - - if(!PHASE_OFF(Js::ObjTypeSpecPhase, functionBody) || !PHASE_OFF(Js::FixedMethodsPhase, functionBody)) + if (Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCaches() != nullptr) { - if(cacheType & (Js::FldInfo_FromLocal | Js::FldInfo_FromProto)) // Remove FldInfo_FromLocal? - { + Js::InlineCache *inlineCache = Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(i); + ObjTypeSpecFldInfo* objTypeSpecFldInfo = nullptr; - // WinBlue 170722: Disable ObjTypeSpec optimization for activation object in debug mode, - // as it can result in BailOutFailedTypeCheck before locals are set to undefined, - // which can result in using garbage object during bailout/restore values. - if (!(functionBody->IsInDebugMode() && inlineCache->GetType() && - inlineCache->GetType()->GetTypeId() == Js::TypeIds_ActivationObject)) + if(!PHASE_OFF(Js::ObjTypeSpecPhase, functionBody) || !PHASE_OFF(Js::FixedMethodsPhase, functionBody)) + { + if(cacheType & (Js::FldInfo_FromLocal | Js::FldInfo_FromProto)) // Remove FldInfo_FromLocal? { - objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData)); - if (objTypeSpecFldInfo) - { - IncInlineCacheCount(clonedMonoInlineCacheCount); - if (!PHASE_OFF(Js::InlineApplyTargetPhase, functionBody) && IsInlinee && (cacheType & Js::FldInfo_InlineCandidate)) - { - inlineApplyTarget = true; - } - if (!isJitTimeDataComputed) + // WinBlue 170722: Disable ObjTypeSpec optimization for activation object in debug mode, + // as it can result in BailOutFailedTypeCheck before locals are set to undefined, + // which can result in using garbage object during bailout/restore values. + if (!(functionBody->IsInDebugMode() && inlineCache->GetType() && + inlineCache->GetType()->GetTypeId() == Js::TypeIds_ActivationObject)) + { + objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData)); + if (objTypeSpecFldInfo) { - jitTimeData->GetObjTypeSpecFldInfoArray()->SetInfo(recycler, functionBody, i, objTypeSpecFldInfo); - objTypeSpecFldInfoList->Prepend(objTypeSpecFldInfo); + IncInlineCacheCount(clonedMonoInlineCacheCount); + + if (!PHASE_OFF(Js::InlineApplyTargetPhase, functionBody) && IsInlinee && (cacheType & Js::FldInfo_InlineCandidate)) + { + inlineApplyTarget = true; + } + if (!isJitTimeDataComputed) + { + jitTimeData->GetObjTypeSpecFldInfoArray()->SetInfo(recycler, functionBody, i, objTypeSpecFldInfo); + objTypeSpecFldInfoList->Prepend(objTypeSpecFldInfo); + } } } } @@ -2597,21 +2607,25 @@ NativeCodeGenerator::GatherCodeGenData( // the inline caches, as their cached data is not guaranteed to be stable while jitting. Js::InlineCache *const inlineCache = function && Js::ScriptFunctionWithInlineCache::Is(function) - ? Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(i) + ? (Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCaches() != nullptr ? Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(i) : nullptr) : functionBody->GetInlineCache(i); - Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(i); - const auto clone = runtimeData->ClonedInlineCaches()->GetInlineCache(functionBody, i); - if (clone) - { - inlineCache->CopyTo(propertyId, functionBody->GetScriptContext(), clone); - } - else + + if (inlineCache != nullptr) { - runtimeData->ClonedInlineCaches()->SetInlineCache( - recycler, - functionBody, - i, - inlineCache->Clone(propertyId, functionBody->GetScriptContext())); + Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(i); + const auto clone = runtimeData->ClonedInlineCaches()->GetInlineCache(functionBody, i); + if (clone) + { + inlineCache->CopyTo(propertyId, functionBody->GetScriptContext(), clone); + } + else + { + runtimeData->ClonedInlineCaches()->SetInlineCache( + recycler, + functionBody, + i, + inlineCache->Clone(propertyId, functionBody->GetScriptContext())); + } } } } @@ -2724,7 +2738,10 @@ NativeCodeGenerator::GatherCodeGenData( { if(function && Js::ScriptFunctionWithInlineCache::Is(function)) { - inlineCache = Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(ldFldInlineCacheIndex); + if (Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCaches() != nullptr) + { + inlineCache = Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(ldFldInlineCacheIndex); + } } else {
lib/Runtime/Language/InterpreterStackFrame.cpp+1 −0 modified@@ -1065,6 +1065,7 @@ namespace Js if (this->function->GetHasInlineCaches() && Js::ScriptFunctionWithInlineCache::Is(this->function)) { this->inlineCaches = (void**)Js::ScriptFunctionWithInlineCache::FromVar(this->function)->GetInlineCaches(); + Assert(this->inlineCaches != nullptr); } else {
lib/Runtime/Library/ScriptFunction.cpp+16 −6 modified@@ -717,7 +717,7 @@ namespace Js InlineCache * ScriptFunctionWithInlineCache::GetInlineCache(uint index) { void** inlineCaches = this->GetInlineCaches(); - Assert(inlineCaches != nullptr); + AssertOrFailFast(inlineCaches != nullptr); AssertOrFailFast(index < this->GetInlineCacheCount()); #if DBG Assert(this->m_inlineCacheTypes[index] == InlineCacheTypeNone || @@ -730,12 +730,22 @@ namespace Js Field(void**) ScriptFunctionWithInlineCache::GetInlineCaches() { // If script function have inline caches pointing to function body and function body got reparsed we need to reset cache - if (this->GetHasInlineCaches() && - !this->GetHasOwnInlineCaches() && - this->m_inlineCaches != this->GetFunctionBody()->GetInlineCaches()) + if (this->GetHasInlineCaches() && !this->GetHasOwnInlineCaches()) { - Assert(this->GetFunctionBody()->GetCompileCount() > 1); - this->SetInlineCachesFromFunctionBody(); + // Script function have inline caches pointing to function body + if (!this->HasFunctionBody()) + { + // Function body got re-deferred and have not been re-parsed yet. Reset cache to null + this->m_inlineCaches = nullptr; + this->inlineCacheCount = 0; + this->SetHasInlineCaches(false); + } + else if (this->m_inlineCaches != this->GetFunctionBody()->GetInlineCaches()) + { + // Function body got reparsed we need to reset cache + Assert(this->GetFunctionBody()->GetCompileCount() > 1); + this->SetInlineCachesFromFunctionBody(); + } } return this->m_inlineCaches;
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
9- portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-11871nvdPatchVendor AdvisoryWEB
- www.securityfocus.com/bid/101730nvdThird Party AdvisoryVDB Entry
- www.securitytracker.com/id/1039780nvdThird Party AdvisoryVDB Entry
- github.com/advisories/GHSA-43qp-hphf-5rjwghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2017-11871ghsaADVISORY
- github.com/chakra-core/ChakraCore/commit/9d211a417757ba1ddcd0f2e72d9553535256107eghsaWEB
- github.com/chakra-core/ChakraCore/pull/4226ghsaWEB
- web.archive.org/web/20210124114740/http://www.securityfocus.com/bid/101730ghsaWEB
- web.archive.org/web/20210517135249/http://www.securitytracker.com/id/1039780ghsaWEB
News mentions
0No linked articles in our index yet.