diff options
Diffstat (limited to 'src/vm/securitystackwalk.cpp')
-rw-r--r-- | src/vm/securitystackwalk.cpp | 2439 |
1 files changed, 0 insertions, 2439 deletions
diff --git a/src/vm/securitystackwalk.cpp b/src/vm/securitystackwalk.cpp deleted file mode 100644 index 9b8b150f68..0000000000 --- a/src/vm/securitystackwalk.cpp +++ /dev/null @@ -1,2439 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - - -// - - -#include "common.h" - -#include "security.h" -#include "perfcounters.h" -#include "stackcompressor.h" -#ifdef FEATURE_REMOTING -#include "crossdomaincalls.h" -#else -#include "callhelpers.h" -#endif -#include "appdomain.inl" -#include "appdomainstack.inl" - -COUNTER_ONLY(PERF_COUNTER_TIMER_PRECISION g_TotalTimeInSecurityRuntimeChecks = 0); -COUNTER_ONLY(PERF_COUNTER_TIMER_PRECISION g_LastTimeInSecurityRuntimeChecks = 0); -COUNTER_ONLY(UINT32 g_SecurityChecksIterations=0); - -bool SecurityStackWalk::IsSpecialRunFrame(MethodDesc* pMeth) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); - } CONTRACTL_END; - -#ifndef FEATURE_CORECLR - if (pMeth == MscorlibBinder::GetMethod(METHOD__EXECUTIONCONTEXT__RUN)) - return true; - -#if defined(FEATURE_IMPERSONATION) || defined(FEATURE_COMPRESSEDSTACK) - if (pMeth == MscorlibBinder::GetMethod(METHOD__SECURITYCONTEXT__RUN)) - return true; -#endif // #if defined(FEATURE_IMPERSONATION) || defined(FEATURE_COMPRESSEDSTACK) - -#ifdef FEATURE_COMPRESSEDSTACK - if (pMeth == MscorlibBinder::GetMethod(METHOD__COMPRESSED_STACK__RUN)) - return true; -#endif // FEATURE_COMPRESSEDSTACK - -#endif // !FEATURE_CORECLR - - return false; -} - -void SecurityStackWalk::CheckPermissionAgainstGrants(OBJECTREF refCS, OBJECTREF refGrants, OBJECTREF refRefused, AppDomain *pDomain, MethodDesc* pMethod, Assembly* pAssembly) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - struct _gc { - OBJECTREF orCS; - OBJECTREF orGranted; - OBJECTREF orRefused; - OBJECTREF orDemand; - OBJECTREF orToken; - OBJECTREF orAssembly; - } gc; - ZeroMemory(&gc, sizeof(gc)); - gc.orCS = refCS; - gc.orGranted = refGrants; - gc.orRefused = refRefused; - - GCPROTECT_BEGIN(gc); - - // Switch into the destination context if necessary. - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) //have it on the stack - { - // Fetch input objects that might originate from a different appdomain, - // marshalling if necessary. - gc.orDemand = m_objects.GetObjects(pDomain, &gc.orToken); - if(pAssembly) - gc.orAssembly = pAssembly->GetExposedObject(); - - PREPARE_NONVIRTUAL_CALLSITE(METHOD__SECURITY_ENGINE__CHECK_HELPER); - - DECLARE_ARGHOLDER_ARRAY(helperArgs, 8); - helperArgs[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.orCS); - helperArgs[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.orGranted); - helperArgs[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(gc.orRefused); - helperArgs[ARGNUM_3] = OBJECTREF_TO_ARGHOLDER(gc.orDemand); - helperArgs[ARGNUM_4] = OBJECTREF_TO_ARGHOLDER(gc.orToken); - helperArgs[ARGNUM_5] = PTR_TO_ARGHOLDER(pMethod); - helperArgs[ARGNUM_6] = OBJECTREF_TO_ARGHOLDER(gc.orAssembly); - helperArgs[ARGNUM_7] = DWORD_TO_ARGHOLDER(dclDemand); - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD_NORET(helperArgs); - - } - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); -} - - -void SecurityStackWalk::CheckSetAgainstGrants(OBJECTREF refCS, OBJECTREF refGrants, OBJECTREF refRefused, AppDomain *pDomain, MethodDesc* pMethod, Assembly* pAssembly) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - struct _gc { - OBJECTREF orCS; - OBJECTREF orGranted; - OBJECTREF orRefused; - OBJECTREF orDemand; - OBJECTREF orAssembly; - } gc; - ZeroMemory(&gc, sizeof(gc)); - gc.orCS = refCS; - gc.orGranted = refGrants; - gc.orRefused = refRefused; - - GCPROTECT_BEGIN(gc); - - // Switch into the destination context if necessary. - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) //have it on the stack - { - // Fetch input objects that might originate from a different appdomain, - // marshalling if necessary. - gc.orDemand = m_objects.GetObject(pDomain); - if(pAssembly) - gc.orAssembly = pAssembly->GetExposedObject(); - - PREPARE_NONVIRTUAL_CALLSITE(METHOD__SECURITY_ENGINE__CHECK_SET_HELPER); - - DECLARE_ARGHOLDER_ARRAY(helperArgs, 7); - helperArgs[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.orCS); - helperArgs[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.orGranted); - helperArgs[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(gc.orRefused); - helperArgs[ARGNUM_3] = OBJECTREF_TO_ARGHOLDER(gc.orDemand); - helperArgs[ARGNUM_4] = PTR_TO_ARGHOLDER(pMethod); - helperArgs[ARGNUM_5] = OBJECTREF_TO_ARGHOLDER(gc.orAssembly); - helperArgs[ARGNUM_6] = DWORD_TO_ARGHOLDER(dclDemand); - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD_NORET(helperArgs); - } - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); -} - -void SecurityStackWalk::GetZoneAndOriginGrants(OBJECTREF refCS, OBJECTREF refGrants, OBJECTREF refRefused, AppDomain *pDomain, MethodDesc* pMethod, Assembly* pAssembly) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - Thread *pThread = GetThread(); - - struct _gc { - OBJECTREF orCS; - OBJECTREF orGranted; - OBJECTREF orRefused; - OBJECTREF orZoneList; - OBJECTREF orOriginList; - } gc; - ZeroMemory(&gc, sizeof(gc)); - gc.orCS = refCS; - gc.orGranted = refGrants; - gc.orRefused = refRefused; - - GCPROTECT_BEGIN(gc); - - // Fetch input objects that might originate from a different appdomain, - // marshalling if necessary. - gc.orZoneList = m_objects.GetObjects(pDomain, &gc.orOriginList); - - // Switch into the destination context if necessary. - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) //have it on the stack - { - - BOOL inProgress = pThread->IsSecurityStackwalkInProgess(); - - // We turn security stackwalk in progress off which turns security back - // on for a thread. This means that if the managed call throws an exception - // we are already in the proper state so we don't need to do anything. - - if (inProgress) - pThread->SetSecurityStackwalkInProgress(FALSE); - - MethodDescCallSite getZoneAndOriginHelper(METHOD__SECURITY_ENGINE__GET_ZONE_AND_ORIGIN_HELPER); - - ARG_SLOT helperArgs[5]; - - helperArgs[0] = ObjToArgSlot(gc.orCS); - helperArgs[1] = ObjToArgSlot(gc.orGranted); - helperArgs[2] = ObjToArgSlot(gc.orRefused); - helperArgs[3] = ObjToArgSlot(gc.orZoneList); - helperArgs[4] = ObjToArgSlot(gc.orOriginList); - - getZoneAndOriginHelper.Call(&(helperArgs[0])); - - if (inProgress) - pThread->SetSecurityStackwalkInProgress(TRUE); - } - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); -} - -BOOL SecurityStackWalk::CheckPermissionAgainstFrameData(OBJECTREF refFrameData, AppDomain* pDomain, MethodDesc* pMethod) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - CLR_BOOL ret = FALSE; - - struct _gc { - OBJECTREF orFrameData; - OBJECTREF orDemand; - OBJECTREF orToken; - } gc; - ZeroMemory(&gc, sizeof(gc)); - gc.orFrameData = refFrameData; - - GCPROTECT_BEGIN(gc); - - // Fetch input objects that might originate from a different appdomain, - // marshalling if necessary. - gc.orDemand = m_objects.GetObjects(pDomain, &gc.orToken); - - // Switch into the destination context if necessary. - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) //have it on the stack - { - PREPARE_NONVIRTUAL_CALLSITE(METHOD__SECURITY_RUNTIME__FRAME_DESC_HELPER); - - DECLARE_ARGHOLDER_ARRAY(args, 4); - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.orFrameData); // arg 0 - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.orDemand); // arg 1 - args[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(gc.orToken); // arg 2 - args[ARGNUM_3] = PTR_TO_ARGHOLDER(pMethod); // arg 3 - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD(ret, CLR_BOOL, args); - - } - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); - - return ret; -} - -BOOL SecurityStackWalk::CheckSetAgainstFrameData(OBJECTREF refFrameData, AppDomain* pDomain, MethodDesc* pMethod) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - CLR_BOOL ret = FALSE; - - struct _gc { - OBJECTREF orFrameData; - OBJECTREF orDemand; - OBJECTREF orPermSetOut; - } gc; - ZeroMemory(&gc, sizeof(gc)); - gc.orFrameData = refFrameData; - - GCPROTECT_BEGIN(gc); - - // Fetch input objects that might originate from a different appdomain, - // marshalling if necessary. - gc.orDemand = m_objects.GetObject(pDomain); - - // Switch into the destination context if necessary. - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) //have it on the stack - { - PREPARE_NONVIRTUAL_CALLSITE(METHOD__SECURITY_RUNTIME__FRAME_DESC_SET_HELPER); - - DECLARE_ARGHOLDER_ARRAY(args, 4); - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.orFrameData); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.orDemand); - args[ARGNUM_2] = PTR_TO_ARGHOLDER(&gc.orPermSetOut); - args[ARGNUM_3] = PTR_TO_ARGHOLDER(pMethod); - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD(ret, CLR_BOOL, args); - - if (gc.orPermSetOut != NULL) { - // Update the cached object. - m_objects.UpdateObject(pDomain, gc.orPermSetOut); - } - } - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); - - return ret; -} - - - - - - - - - - - - - - - - - - -// ------------------------------------------------------------------------------- -// -// DemandStackWalk -// -// ------------------------------------------------------------------------------- - -class DemandStackWalk : public SecurityStackWalk -{ -public: - enum DemandType - { - DT_PERMISSION = 1, - DT_SET = 2, - DT_ZONE_AND_URL = 3, - }; - -protected: - Frame* m_pCtxTxFrame; - AppDomain * m_pPrevAppDomain; - AppDomain* m_pSkipAppDomain; - Assembly * m_pPrevAssembly; - StackCrawlMark * m_pStackMark; - DemandType m_eDemandType; - bool m_bHaveFoundStartingFrameYet; - BOOL m_bFoundStackMark; - DWORD m_dwdemandFlags; - DWORD m_adStackIndex; - AppDomainStack* m_pThreadADStack; - -public: - DemandStackWalk(SecurityStackWalkType eType, DWORD flags, StackCrawlMark* stackMark, DemandType eDemandType, DWORD demandFlags) - : SecurityStackWalk(eType, flags) - { - WRAPPER_NO_CONTRACT; - m_pCtxTxFrame = NULL; - m_pPrevAppDomain = NULL; - m_pSkipAppDomain = NULL; - m_pPrevAssembly = NULL; - m_eDemandType = eDemandType; - m_bHaveFoundStartingFrameYet = false; - m_pStackMark = stackMark; - m_bFoundStackMark = FALSE; - m_dwdemandFlags = demandFlags; - m_pThreadADStack = GetThread()->GetAppDomainStackPointer(); - m_pThreadADStack->InitDomainIteration(&m_adStackIndex); - } - - void DoStackWalk(); - StackWalkAction WalkFrame(CrawlFrame* pCf); - -protected: - bool IsStartingFrame(CrawlFrame* pCf); - bool IsSpecialRunFrame(MethodDesc* pMeth) - { - return SecurityStackWalk::IsSpecialRunFrame(pMeth); - } - void CheckGrant(OBJECTREF refCS, OBJECTREF refGrants, OBJECTREF refRefused, AppDomain *pDomain, MethodDesc* pMethod, Assembly* pAssembly); - BOOL CheckFrame(OBJECTREF refFrameData, AppDomain* pDomain, MethodDesc* pMethod); - -private: - FORCEINLINE BOOL QuickCheck(OBJECTREF refCS, OBJECTREF refGrants, OBJECTREF refRefused) - { - if (refCS == NULL && refRefused == NULL && refGrants != NULL) - { - // if we have a FT grant and nothing else, and our demand is for something that FT can satisfy, we're done - PERMISSIONSETREF permSetRef = (PERMISSIONSETREF)refGrants; - return permSetRef->IsUnrestricted(); - } - return FALSE; - } - void ProcessAppDomainTransition(AppDomain * pAppDomain, bool bCheckPrevAppDomain); -#ifdef _DEBUG - BOOL IsValidReturnFromWalkFrame(StackWalkAction retVal, CrawlFrame* pCF) - { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - // This function checks that when we hit a Special frame, we are indeed returning the action to stop the stackwalk - MethodDesc *pFunc = pCF->GetFunction(); - if (pFunc != NULL && IsSpecialRunFrame(pFunc)) - { - return (retVal == SWA_ABORT); - } - return TRUE; - } -#endif // _DEBUG - -#ifdef FEATURE_COMPRESSEDSTACK - BOOL CheckAnonymouslyHostedDynamicMethodCompressedStack(OBJECTREF refDynamicResolver, AppDomain* pDomain, MethodDesc* pMethod); - BOOL CheckAnonymouslyHostedDynamicMethodCompressedStackPermission(OBJECTREF refDynamicResolver, AppDomain* pDomain, MethodDesc* pMethod); - BOOL CheckAnonymouslyHostedDynamicMethodCompressedStackPermissionSet(OBJECTREF refDynamicResolver, AppDomain* pDomain, MethodDesc* pMethod); -#endif // FEATURE_COMPRESSEDSTACK -}; - -void DemandStackWalk::CheckGrant(OBJECTREF refCS, OBJECTREF refGrants, OBJECTREF refRefused, AppDomain *pDomain, MethodDesc* pMethod, Assembly* pAssembly) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - switch(m_eDemandType) - { - case DT_PERMISSION: - // Test early out scenario (quickcheck) before calling into managed code - if (!QuickCheck(refCS, refGrants, refRefused)) - CheckPermissionAgainstGrants(refCS, refGrants, refRefused, pDomain, pMethod, pAssembly); - break; - - case DT_SET: - // Test early out scenario (quickcheck) before calling into managed code - if (!QuickCheck(refCS, refGrants, refRefused)) - CheckSetAgainstGrants(refCS, refGrants, refRefused, pDomain, pMethod, pAssembly); - break; - case DT_ZONE_AND_URL: - GetZoneAndOriginGrants(refCS, refGrants, refRefused, pDomain, pMethod, pAssembly); - break; - default: - _ASSERTE(!"unexpected demand type"); - break; - } -} - -BOOL DemandStackWalk::CheckFrame(OBJECTREF refFrameData, AppDomain* pDomain, MethodDesc* pMethod) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - switch(m_eDemandType) - { - case DT_PERMISSION: - return CheckPermissionAgainstFrameData(refFrameData, pDomain, pMethod); - - case DT_SET: - return CheckSetAgainstFrameData(refFrameData, pDomain, pMethod); - case DT_ZONE_AND_URL: - return TRUE; //Nothing to do here since CS cannot live on a Frame anymore. - default: - _ASSERTE(!"unexpected demand type"); - } - return TRUE; -} - -bool DemandStackWalk::IsStartingFrame(CrawlFrame* pCf) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); - } CONTRACTL_END; - - switch(m_eStackWalkType) - { - case SSWT_DECLARATIVE_DEMAND: // Begin after the security stub(s) - _ASSERTE(m_pStackMark == NULL); - // skip the current method that has decl sec - if (m_bFoundStackMark) - return true; - else - { - m_bFoundStackMark = true; - return false; - } - - case SSWT_IMPERATIVE_DEMAND: // Begin where the StackMark says to - case SSWT_GET_ZONE_AND_URL: // Begin where the StackMark says to - _ASSERTE(*m_pStackMark == LookForMyCaller || *m_pStackMark == LookForMyCallersCaller); - - // See if we've passed the stack mark yet - if (!pCf->IsInCalleesFrames(m_pStackMark)) - return false; - - // Skip the frame after the stack mark as well. - if(*m_pStackMark == LookForMyCallersCaller && !m_bFoundStackMark) - { - m_bFoundStackMark = TRUE; - return false; - } - - return true; - - case SSWT_LATEBOUND_LINKDEMAND: // Begin immediately - case SSWT_DEMAND_FROM_NATIVE: - _ASSERTE(m_pStackMark == NULL); - return true; - - default: - _ASSERTE(FALSE); // Unexpected stack walk type - break; - } - return true; -} -void DemandStackWalk::ProcessAppDomainTransition(AppDomain* pAppDomain, bool bCheckPrevAppDomain) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - _ASSERTE(pAppDomain != m_pPrevAppDomain); - - if (m_pPrevAppDomain != NULL && bCheckPrevAppDomain) - { - // We have not checked the previous AppDomain. Check it now. - if (m_pSkipAppDomain != m_pPrevAppDomain) - { - ApplicationSecurityDescriptor *pSecDesc = - static_cast<ApplicationSecurityDescriptor*>(m_pPrevAppDomain->GetSecurityDescriptor()); - - // Only process AppDomains which have completed security initialization. If the domain is not - // yet fully initialized then only fully trusted code can be running in the domain, so we're - // safe to ignore the transition. The domain may also not yet have a sane grant set setup on it - // yet if the demand is coming out of AppDomainManager code. - if (pSecDesc && !pSecDesc->IsInitializationInProgress()) - { - DBG_TRACE_STACKWALK(" Checking appdomain...\n", true); - - if (!pSecDesc->IsDefaultAppDomain() && - !pSecDesc->IsFullyTrusted() && - !pSecDesc->CheckSpecialFlag(m_dwdemandFlags)) - { - OBJECTREF orRefused; - OBJECTREF orGranted = pSecDesc->GetGrantedPermissionSet(&orRefused); - CheckGrant(NULL, orGranted, orRefused, m_pPrevAppDomain, NULL, m_pPrevAssembly); - } - } - else - { - DBG_TRACE_STACKWALK(" Skipping appdomain...\n", true); - } - } - } - // Move the domain index forward - m_pThreadADStack->GetNextDomainEntryOnStack(&m_adStackIndex); - - // At the end of the stack walk, do a check on the grants of - // the m_pPrevAppDomain by the stackwalk caller if needed. - m_pPrevAppDomain = pAppDomain; - - // Check if we can skip the entire pAppDomain. If so, assign m_pSkipAppDomain - // TODO: Can Check the AppDomain PLS also here. - if ((m_pThreadADStack->GetCurrentDomainEntryOnStack(m_adStackIndex))->HasFlagsOrFullyTrustedWithNoStackModifiers(m_dwdemandFlags)) - m_pSkipAppDomain = pAppDomain; - else - m_pSkipAppDomain = NULL; - - - -} -StackWalkAction DemandStackWalk::WalkFrame(CrawlFrame* pCf) -{ - CONTRACT (StackWalkAction) { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - POSTCONDITION(IsValidReturnFromWalkFrame(RETVAL, pCf)); - } CONTRACT_END; - - StackWalkAction ret = SWA_CONTINUE; - -#ifdef FEATURE_REMOTING -#ifdef FEATURE_COMPRESSEDSTACK - - // Save the CtxTxFrame if this is one - if (m_pCtxTxFrame == NULL) - { - Frame *pFrame = pCf->GetFrame(); - if (SecurityStackWalk::IsContextTransitionFrameWithCS(pFrame)) - { - - m_pCtxTxFrame = pFrame; - } - } -#endif // #ifdef FEATURE_COMPRESSEDSTACK -#endif // FEATURE_REMOTING - - MethodDesc * pFunc = pCf->GetFunction(); - Assembly * pAssem = pCf->GetAssembly(); - // Get the current app domain. - AppDomain *pAppDomain = pCf->GetAppDomain(); - if (pAppDomain != m_pPrevAppDomain) - { -#ifndef FEATURE_REMOTING - BOOL bRealAppDomainTransition = (m_pPrevAppDomain != NULL); -#endif - ProcessAppDomainTransition(pAppDomain, m_bHaveFoundStartingFrameYet); - -#ifndef FEATURE_REMOTING - // The first AppDomain transition is the transition from NULL to current domain. We should not stop on that. - // We should stop on the first "real" appdomain transition - which is a transition out of the current domain. - if (bRealAppDomainTransition) - { - // without remoting other appdomains do not matter (can be only createdomain call anyhow) so stop the stack walk - m_dwFlags |= CORSEC_STACKWALK_HALTED; - RETURN SWA_ABORT; - } -#endif - } - - if ((pFunc == NULL && pAssem == NULL) || (pFunc && pFunc->IsILStub())) - RETURN ret; // Not a function - - // Skip until the frame where the stackwalk should begin - if (!m_bHaveFoundStartingFrameYet) - { - if (IsStartingFrame(pCf)) - m_bHaveFoundStartingFrameYet = true; - else - RETURN ret; - } - - // - // Now check the current frame! - // - // If this is a *.Run method, then we need to terminate the stackwalk after considering this frame - if (pFunc && IsSpecialRunFrame(pFunc)) - { - DBG_TRACE_STACKWALK(" Halting stackwalk for .Run.\n", false); - // Dont mark the CORSEC_STACKWALK_HALTED in m_dwFlags because we still need to look at the CS - ret = SWA_ABORT; - } - - DBG_TRACE_STACKWALK(" Checking granted permissions for current method...\n", true); - - // Reached here imples we walked atleast a single frame. - COUNTER_ONLY(GetPerfCounters().m_Security.stackWalkDepth++); - - - // Get the previous assembly - Assembly *pPrevAssem = m_pPrevAssembly; - - - // Check if we can skip the entire appdomain - if (m_pSkipAppDomain == pAppDomain) - { - RETURN ret; - } - - // Keep track of the last module checked. If we have just checked the - // permissions on the module, we don't need to do it again. - if (pAssem != pPrevAssem) - { - DBG_TRACE_STACKWALK(" Checking grants for current assembly.\n", true); - - // Get the security descriptor for the current assembly and pass it to - // the interpreted helper. - AssemblySecurityDescriptor * pSecDesc = static_cast<AssemblySecurityDescriptor*>(pAssem->GetSecurityDescriptor(pAppDomain)); - _ASSERTE(pSecDesc != NULL); - - // We have to check the permissions if we are not fully trusted or - // we cannot be overrided by full trust. Plus we always skip checks - // on system classes. - if (!pSecDesc->IsSystem() && - !pSecDesc->IsFullyTrusted() && - !pSecDesc->CheckSpecialFlag(m_dwdemandFlags)) - { - OBJECTREF orRefused; - OBJECTREF orGranted = pSecDesc->GetGrantedPermissionSet(&orRefused); - CheckGrant(NULL, orGranted, orRefused, pAppDomain, pFunc, pAssem); - } - - m_pPrevAssembly = pAssem; - } - else - { - DBG_TRACE_STACKWALK(" Current assembly same as previous. Skipping check.\n", true); - } - - - // Passed initial check. See if there is security info on this frame. - OBJECTREF *pFrameObjectSlot = pCf->GetAddrOfSecurityObject(); - if (pFrameObjectSlot != NULL) - { - SecurityDeclarative::DoDeclarativeSecurityAtStackWalk(pFunc, pAppDomain, pFrameObjectSlot); - if (*pFrameObjectSlot != NULL) - { - DBG_TRACE_STACKWALK(" + Frame-specific security info found. Checking...\n", false); - - if(!CheckFrame(*pFrameObjectSlot, pAppDomain, pFunc)) - { - DBG_TRACE_STACKWALK(" Halting stackwalk for assert.\n", false); - m_dwFlags |= CORSEC_STACKWALK_HALTED; - ret = SWA_ABORT; - } - } - } - -#if FEATURE_COMPRESSEDSTACK - // If this frame is an anonymously hosted dynamic assembly, we need to run the demand against its compressed stack - // to ensure the creator had the permissions for this demand - if(pAssem != NULL && pAppDomain != NULL && pAssem->GetDomainAssembly(pAppDomain) == pAppDomain->GetAnonymouslyHostedDynamicMethodsAssembly() && - !CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_Security_DisableAnonymouslyHostedDynamicMethodCreatorSecurityCheck)) - { - _ASSERTE(pFunc->IsLCGMethod()); - OBJECTREF dynamicResolver = pFunc->AsDynamicMethodDesc()->GetLCGMethodResolver()->GetManagedResolver(); - if(!CheckAnonymouslyHostedDynamicMethodCompressedStack(dynamicResolver, pAppDomain, pFunc)) - { - m_dwFlags |= CORSEC_STACKWALK_HALTED; - ret = SWA_ABORT; - } - } -#endif // FEATURE_COMPRESSEDSTACK - - DBG_TRACE_STACKWALK(" Check passes for this method.\n", true); - - - // Passed all the checks, return current value of ret (could be SWA_ABORT of SWA_CONTINUE based on above checks) - RETURN ret; -} - -static -StackWalkAction CodeAccessCheckStackWalkCB(CrawlFrame* pCf, VOID* pData) -{ - WRAPPER_NO_CONTRACT; - DemandStackWalk *pCBdata = (DemandStackWalk*)pData; - return pCBdata->WalkFrame(pCf); -} - -void DemandStackWalk::DoStackWalk() -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - // Get the current thread. - Thread *pThread = GetThread(); - _ASSERTE(pThread != NULL); - - // Don't allow recursive security stackwalks. Note that this implies that - // *no* untrusted code must ever be called during a security stackwalk. - if (pThread->IsSecurityStackwalkInProgess()) - return; - - // NOTE: Initialize the stack depth. Note that if more that one thread tries - // to perform stackwalk then these counters gets stomped upon. - COUNTER_ONLY(GetPerfCounters().m_Security.stackWalkDepth = 0); - - // Walk the thread. - EX_TRY - { - pThread->SetSecurityStackwalkInProgress( TRUE ); - - DBG_TRACE_STACKWALK("Code-access security check invoked.\n", false); - // LIGHTUNWIND flag: allow using stackwalk cache for security stackwalks - pThread->StackWalkFrames(CodeAccessCheckStackWalkCB, this, SKIPFUNCLETS | LIGHTUNWIND); - DBG_TRACE_STACKWALK("\tCode-access stackwalk completed.\n", false); - - // check the last app domain or CompressedStack at the thread base - if (((m_dwFlags & CORSEC_STACKWALK_HALTED) == 0) /*&& m_cCheck != 0*/) - { - AppDomain *pAppDomain = m_pPrevAppDomain; -#ifdef FEATURE_COMPRESSEDSTACK - OBJECTREF orCS = pThread->GetCompressedStack(); - - if (orCS == NULL) - { - // There may have been an AD transition and we shd look at the CB data to see if this is the case - if (m_pCtxTxFrame != NULL) - { - orCS = (OBJECTREF)SecurityStackWalk::GetCSFromContextTransitionFrame(m_pCtxTxFrame); - pAppDomain = m_pCtxTxFrame->GetReturnDomain(); - } - } - - - if (orCS != NULL) - { - // We have a CS at the thread base - just look at that. Dont look at the last AD - DBG_TRACE_STACKWALK("\tChoosing CompressedStack check.\n", true); - DBG_TRACE_STACKWALK("\tChecking CompressedStack...\n", true); - - CheckGrant(orCS, NULL, NULL, pAppDomain, NULL, NULL); - DBG_TRACE_STACKWALK("\tCompressedStack check passed.\n", true); - } - else -#endif // FEATURE_COMPRESSEDSTACK - { - // No CS at thread base - must look at the last AD - DBG_TRACE_STACKWALK("\tChoosing appdomain check.\n", true); - - ApplicationSecurityDescriptor *pSecDesc = static_cast<ApplicationSecurityDescriptor*>(pAppDomain->GetSecurityDescriptor()); - - if (pSecDesc != NULL) - { - // Note: the order of these calls is important since you have to have done a - // GetEvidence() on the security descriptor before you check for the - // CORSEC_DEFAULT_APPDOMAIN property. IsFullyTrusted calls Resolve so - // we're all good. - if (!pSecDesc->IsDefaultAppDomain() && - !pSecDesc->IsFullyTrusted() && - !pSecDesc->CheckSpecialFlag(m_dwdemandFlags)) - { - DBG_TRACE_STACKWALK("\tChecking appdomain...\n", true); - OBJECTREF orRefused; - OBJECTREF orGranted = pSecDesc->GetGrantedPermissionSet(&orRefused); - CheckGrant(NULL, orGranted, orRefused, pAppDomain, NULL, NULL); - DBG_TRACE_STACKWALK("\tappdomain check passed.\n", true); - } - } - else - { - DBG_TRACE_STACKWALK("\tSkipping appdomain check.\n", true); - } - } - } - else - { - DBG_TRACE_STACKWALK("\tSkipping CS/appdomain check.\n", true); - } - - pThread->SetSecurityStackwalkInProgress( FALSE ); - } - EX_CATCH - { - // We catch exceptions and rethrow like this to ensure that we've - // established an exception handler on the fs:[0] chain (managed - // exception handlers won't do this). This in turn guarantees that - // managed exception filters in any of our callers won't be found, - // otherwise they could get to execute untrusted code with security - // turned off. - pThread->SetSecurityStackwalkInProgress( FALSE ); - - EX_RETHROW; - } - EX_END_CATCH_UNREACHABLE - - - DBG_TRACE_STACKWALK("Code-access check passed.\n", false); -} - -#ifdef FEATURE_COMPRESSEDSTACK -BOOL DemandStackWalk::CheckAnonymouslyHostedDynamicMethodCompressedStack(OBJECTREF refDynamicResolver, AppDomain* pDomain, MethodDesc* pMethod) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - BOOL ret = TRUE; - - switch(m_eDemandType) - { - case DT_PERMISSION: - ret = CheckAnonymouslyHostedDynamicMethodCompressedStackPermission(refDynamicResolver, pDomain, pMethod); - break; - - case DT_SET: - ret = CheckAnonymouslyHostedDynamicMethodCompressedStackPermissionSet(refDynamicResolver, pDomain, pMethod); - break; - - case DT_ZONE_AND_URL: - // Not needed for compressed stack - break; - - default: - _ASSERTE(!"unexpected demand type"); - break; - } - - return ret; -} - -BOOL DemandStackWalk::CheckAnonymouslyHostedDynamicMethodCompressedStackPermissionSet(OBJECTREF refDynamicResolver, AppDomain* pDomain, MethodDesc* pMethod) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - CLR_BOOL ret = FALSE; - - - struct _gc { - OBJECTREF orDynamicResolver; - OBJECTREF orDemandSet; - OBJECTREF orPermSetOut; - } gc; - ZeroMemory(&gc, sizeof(gc)); - gc.orDynamicResolver = refDynamicResolver; - - GCPROTECT_BEGIN(gc); - - // Fetch input objects that might originate from a different appdomain, - // marshalling if necessary. - gc.orDemandSet = m_objects.GetObject(pDomain); - - // Switch into the destination context if necessary. - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) //have it on the stack - { - PREPARE_NONVIRTUAL_CALLSITE(METHOD__SECURITY_RUNTIME__CHECK_DYNAMIC_METHOD_SET_HELPER); - - DECLARE_ARGHOLDER_ARRAY(args, 4); - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.orDynamicResolver); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.orDemandSet); - args[ARGNUM_2] = PTR_TO_ARGHOLDER(&gc.orPermSetOut); - args[ARGNUM_3] = PTR_TO_ARGHOLDER(pMethod); - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD(ret, CLR_BOOL, args); - - if (gc.orPermSetOut != NULL) { - // Update the cached object. - m_objects.UpdateObject(pDomain, gc.orPermSetOut); - } - } - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); - - return ret; -} - - -BOOL DemandStackWalk::CheckAnonymouslyHostedDynamicMethodCompressedStackPermission(OBJECTREF refDynamicResolver, AppDomain* pDomain, MethodDesc* pMethod) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - CLR_BOOL ret = FALSE; - - - struct _gc { - OBJECTREF orDynamicResolver; - OBJECTREF orDemand; - OBJECTREF orToken; - } gc; - ZeroMemory(&gc, sizeof(gc)); - gc.orDynamicResolver = refDynamicResolver; - - GCPROTECT_BEGIN(gc); - - // Fetch input objects that might originate from a different appdomain, - // marshalling if necessary. - gc.orDemand = m_objects.GetObjects(pDomain, &gc.orToken); - - // Switch into the destination context if necessary. - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) //have it on the stack - { - PREPARE_NONVIRTUAL_CALLSITE(METHOD__SECURITY_RUNTIME__CHECK_DYNAMIC_METHOD_HELPER); - - DECLARE_ARGHOLDER_ARRAY(args, 4); - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.orDynamicResolver); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.orDemand); - args[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(gc.orToken); - args[ARGNUM_3] = PTR_TO_ARGHOLDER(pMethod); - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD(ret, CLR_BOOL, args); - } - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); - - return ret; -} -#endif // FEATURE_COMPRESSEDSTACK - - - - -// ------------------------------------------------------------------------------- -// -// AssertStackWalk -// -// ------------------------------------------------------------------------------- - -class AssertStackWalk : public SecurityStackWalk -{ -protected: - StackCrawlMark * m_pStackMark; - bool m_bHaveFoundStartingFrameYet; - INT_PTR m_cCheck; - -public: - OBJECTREF* m_pSecurityObject; - AppDomain* m_pSecurityObjectDomain; - - AssertStackWalk(SecurityStackWalkType eType, DWORD dwFlags, StackCrawlMark* stackMark) - : SecurityStackWalk(eType, dwFlags) - { - LIMITED_METHOD_CONTRACT; - m_pStackMark = stackMark; - m_bHaveFoundStartingFrameYet = false; - m_cCheck = 1; - m_pSecurityObject = NULL; - m_pSecurityObjectDomain = NULL; - } - - void DoStackWalk(); - StackWalkAction WalkFrame(CrawlFrame* pCf); -}; - -StackWalkAction AssertStackWalk::WalkFrame(CrawlFrame* pCf) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - DBG_TRACE_METHOD(pCf); - - MethodDesc * pFunc = pCf->GetFunction(); - _ASSERTE(pFunc != NULL); // we requested functions only! - _ASSERTE(m_eStackWalkType == SSWT_IMPERATIVE_ASSERT); - _ASSERTE(*m_pStackMark == LookForMyCaller); - - // Skip until we pass the StackMark - if (!m_bHaveFoundStartingFrameYet) - { - if (pCf->IsInCalleesFrames(m_pStackMark)) - m_bHaveFoundStartingFrameYet = true; - else - return SWA_CONTINUE; - } - - // Check if we've visited the maximum number of frames - if (m_cCheck >= 0) - { - if (m_cCheck == 0) - { - m_dwFlags |= CORSEC_STACKWALK_HALTED; - return SWA_ABORT; - } - else - --m_cCheck; - } - - // Reached here imples we walked atleast a single frame. - COUNTER_ONLY(GetPerfCounters().m_Security.stackWalkDepth++); - - DBG_TRACE_STACKWALK(" Checking grants for current assembly.\n", true); - - // Get the security descriptor for the current assembly and pass it to - // the interpreted helper. - // Get the current assembly - Assembly *pAssem = pFunc->GetModule()->GetAssembly(); - AppDomain *pAppDomain = pCf->GetAppDomain(); - IAssemblySecurityDescriptor * pSecDesc = pAssem->GetSecurityDescriptor(pAppDomain); - _ASSERTE(pSecDesc != NULL); - - - if (!SecurityTransparent::IsAllowedToAssert(pFunc)) - { - // Transparent method can't have the permission to Assert - COMPlusThrow(kInvalidOperationException,W("InvalidOperation_AssertTransparentCode")); - } - - if (!pSecDesc->IsSystem() && !pSecDesc->IsFullyTrusted()) - { - OBJECTREF orRefused; - OBJECTREF orGranted = pSecDesc->GetGrantedPermissionSet(&orRefused); - CheckPermissionAgainstGrants(NULL, orGranted, orRefused, pAppDomain, pFunc, pAssem); - } - - // Passed initial check. See if there is security info on this frame. - m_pSecurityObject = pCf->GetAddrOfSecurityObject(); - m_pSecurityObjectDomain = pAppDomain; - - DBG_TRACE_STACKWALK(" Check Immediate passes for this method.\n", true); - - // Passed all the checks, so continue. - return SWA_ABORT; -} - -static -StackWalkAction CheckNReturnSOStackWalkCB(CrawlFrame* pCf, VOID* pData) -{ - WRAPPER_NO_CONTRACT; - AssertStackWalk *pCBdata = (AssertStackWalk*)pData; - return pCBdata->WalkFrame(pCf); -} - -FCIMPL4(Object*, SecurityStackWalk::CheckNReturnSO, Object* permTokenUNSAFE, Object* permUNSAFE, StackCrawlMark* stackMark, INT32 create) -{ - FCALL_CONTRACT; - - OBJECTREF refRetVal = NULL; - OBJECTREF permToken = (OBJECTREF) permTokenUNSAFE; - OBJECTREF perm = (OBJECTREF) permUNSAFE; - HELPER_METHOD_FRAME_BEGIN_RET_2(permToken, perm); - - _ASSERTE((permToken != NULL) && (perm != NULL)); - - // Track perfmon counters. Runtime security checkes. - IncrementSecurityPerfCounter(); - -#if defined(ENABLE_PERF_COUNTERS) - // Perf Counter "%Time in Runtime check" support - PERF_COUNTER_TIMER_PRECISION _startPerfCounterTimer = GET_CYCLE_COUNT(); -#endif - - // Initialize callback data. - DWORD dwFlags = 0; - AssertStackWalk walkData(SSWT_IMPERATIVE_ASSERT, dwFlags, stackMark); - walkData.m_objects.SetObjects(perm, permToken); - - // Protect the object references in the callback data. - GCPROTECT_BEGIN(walkData.m_objects.m_sGC); - - walkData.DoStackWalk(); - - GCPROTECT_END(); - -#if defined(ENABLE_PERF_COUNTERS) - // Accumulate the counter - PERF_COUNTER_TIMER_PRECISION _stopPerfCounterTimer = GET_CYCLE_COUNT(); - g_TotalTimeInSecurityRuntimeChecks += _stopPerfCounterTimer - _startPerfCounterTimer; - - // Report the accumulated counter only after NUM_OF_TERATIONS - if (g_SecurityChecksIterations++ > PERF_COUNTER_NUM_OF_ITERATIONS) - { - GetPerfCounters().m_Security.timeRTchecks = static_cast<DWORD>(g_TotalTimeInSecurityRuntimeChecks); - GetPerfCounters().m_Security.timeRTchecksBase = static_cast<DWORD>(_stopPerfCounterTimer - g_LastTimeInSecurityRuntimeChecks); - - g_TotalTimeInSecurityRuntimeChecks = 0; - g_LastTimeInSecurityRuntimeChecks = _stopPerfCounterTimer; - g_SecurityChecksIterations = 0; - } -#endif // #if defined(ENABLE_PERF_COUNTERS) - - if (walkData.m_pSecurityObject == NULL) - { - goto lExit; - } - - // Is security object frame in a different context? - Thread *pThread; - pThread = GetThread(); - bool fSwitchContext; - - fSwitchContext = walkData.m_pSecurityObjectDomain != pThread->GetDomain(); - if (create && *walkData.m_pSecurityObject == NULL) - { - // If necessary, shift to correct context to allocate security object. - ENTER_DOMAIN_PTR(walkData.m_pSecurityObjectDomain,ADV_RUNNINGIN) //on the stack - { - MethodTable* pMethFrameSecDesc = MscorlibBinder::GetClass(CLASS__FRAME_SECURITY_DESCRIPTOR); - - *walkData.m_pSecurityObject = AllocateObject(pMethFrameSecDesc); - } - END_DOMAIN_TRANSITION; - } - - // If we found or created a security object in a different context, make a - // copy in the current context. -#ifndef FEATURE_CORECLR // should not happen in core clr - if (fSwitchContext && *walkData.m_pSecurityObject != NULL) - refRetVal = AppDomainHelper::CrossContextCopyFrom(walkData.m_pSecurityObjectDomain, - walkData.m_pSecurityObject); - else -#else - _ASSERTE(!fSwitchContext); -#endif - - refRetVal = *walkData.m_pSecurityObject; - -lExit: ; - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(refRetVal); -} -FCIMPLEND - - -void AssertStackWalk::DoStackWalk() -{ - // Get the current thread. - Thread *pThread = GetThread(); - _ASSERTE(pThread != NULL); - - // NOTE: Initialize the stack depth. Note that if more that one thread tries - // to perform stackwalk then these counters gets stomped upon. - COUNTER_ONLY(GetPerfCounters().m_Security.stackWalkDepth = 0); - - // Walk the thread. - DBG_TRACE_STACKWALK("Code-access security check immediate invoked.\n", false); - // LIGHTUNWIND flag: allow using stackwalk cache for security stackwalks - pThread->StackWalkFrames(CheckNReturnSOStackWalkCB, this, FUNCTIONSONLY | SKIPFUNCLETS | LIGHTUNWIND); - - DBG_TRACE_STACKWALK("\tCode-access stackwalk completed.\n", false); -} - - - - - - - - - - - - - - - - - - -// ------------------------------------------------------------------------------- -// -// CountOverridesStackWalk -// -// ------------------------------------------------------------------------------- - -typedef struct _SkipFunctionsData -{ - INT32 cSkipFunctions; - StackCrawlMark* pStackMark; - BOOL bUseStackMark; - BOOL bFoundCaller; - MethodDesc* pFunction; - OBJECTREF* pSecurityObject; - AppDomain* pSecurityObjectAppDomain; -} SkipFunctionsData; - -static StackWalkAction SkipFunctionsCB(CrawlFrame* pCf, VOID* pData) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); - } CONTRACTL_END; - SkipFunctionsData *skipData = (SkipFunctionsData*)pData; - _ASSERTE(skipData != NULL); - - MethodDesc *pFunc = pCf->GetFunction(); - -#ifdef _DEBUG - // Get the interesting info now, so we can get a trace - // while debugging... - OBJECTREF *pSecObj; - pSecObj = pCf->GetAddrOfSecurityObject(); -#endif - - _ASSERTE(skipData->bUseStackMark && "you must specify a stackmark"); - - // First check if the walk has skipped the required frames. The check - // here is between the address of a local variable (the stack mark) and a - // pointer to the EIP for a frame (which is actually the pointer to the - // return address to the function from the previous frame). So we'll - // actually notice which frame the stack mark was in one frame later. This - // is fine for our purposes since we're always looking for the frame of the - // caller of the method that actually created the stack mark. - if ((skipData->pStackMark != NULL) && - !pCf->IsInCalleesFrames(skipData->pStackMark)) - - return SWA_CONTINUE; - - skipData->pFunction = pFunc; - skipData->pSecurityObject = pCf->GetAddrOfSecurityObject(); - skipData->pSecurityObjectAppDomain = pCf->GetAppDomain(); - return SWA_ABORT; // This actually indicates success. -} - -// Version of the above method that looks for a stack mark (the address of a -// local variable in a frame called by the target frame). -BOOL SecurityStackWalk::SkipAndFindFunctionInfo(StackCrawlMark* stackMark, MethodDesc ** ppFunc, OBJECTREF ** ppObj, AppDomain ** ppAppDomain) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); - } CONTRACTL_END; - _ASSERTE(ppFunc != NULL || ppObj != NULL || !"Why was this function called?!"); - - SkipFunctionsData walkData; - walkData.pStackMark = stackMark; - walkData.bUseStackMark = TRUE; - walkData.bFoundCaller = FALSE; - walkData.pFunction = NULL; - walkData.pSecurityObject = NULL; - // LIGHTUNWIND flag: allow using stackwalk cache for security stackwalks - StackWalkAction action = GetThread()->StackWalkFrames(SkipFunctionsCB, &walkData, FUNCTIONSONLY | SKIPFUNCLETS | LIGHTUNWIND); - if (action == SWA_ABORT) - { - if (ppFunc != NULL) - *ppFunc = walkData.pFunction; - if (ppObj != NULL) - { - *ppObj = walkData.pSecurityObject; - if (ppAppDomain != NULL) - *ppAppDomain = walkData.pSecurityObjectAppDomain; - } - return TRUE; - } - else - { - return FALSE; - } -} - - - - - - - - - - - - - - - - - - - - - - - -// ------------------------------------------------------------------------------- -// -// CountOverridesStackWalk -// -// ------------------------------------------------------------------------------- - -class CountOverridesStackWalk -{ -public: - DWORD numOverrides; // Can be removed - DWORD numAsserts; // Can be removed - DWORD numDomainOverrides; - DWORD numDomainAsserts; - AppDomain* prev_AppDomain; - Frame* pCtxTxFrame; - DWORD adStackIndex; - - CountOverridesStackWalk() - { - LIMITED_METHOD_CONTRACT; - numOverrides = 0; - numAsserts = 0; - numDomainAsserts = 0; - numDomainOverrides = 0; - prev_AppDomain = NULL; - pCtxTxFrame = NULL; - GetThread()->InitDomainIteration(&adStackIndex); - } - bool IsSpecialRunFrame(MethodDesc* pMeth) - { - return SecurityStackWalk::IsSpecialRunFrame(pMeth); - } -}; - -static -StackWalkAction UpdateOverridesCountCB(CrawlFrame* pCf, void *pData) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - DBG_TRACE_METHOD(pCf); - - CountOverridesStackWalk *pCBdata = static_cast<CountOverridesStackWalk *>(pData); - - - // First check if the walk has skipped the required frames. The check - // here is between the address of a local variable (the stack mark) and a - // pointer to the EIP for a frame (which is actually the pointer to the - // return address to the function from the previous frame). So we'll - // actually notice which frame the stack mark was in one frame later. This - // is fine for our purposes since we're always looking for the frame of the - // caller (or the caller's caller) of the method that actually created the - // stack mark. - -#ifdef FEATURE_REMOTING -#ifdef FEATURE_COMPRESSEDSTACK - - // Save the CtxTxFrame if this is one - if (pCBdata->pCtxTxFrame == NULL) - { - Frame *pFrame = pCf->GetFrame(); - if (SecurityStackWalk::IsContextTransitionFrameWithCS(pFrame)) - { - pCBdata->pCtxTxFrame = pFrame; - } - } -#endif // #ifdef FEATURE_COMPRESSEDSTACK -#endif // FEATURE_REMOTING - MethodDesc* pMeth = pCf->GetFunction(); - if (pMeth == NULL || pMeth->IsILStub()) - return SWA_CONTINUE; // not a function frame and not a security stub. - // Since we were just looking for CtxTransitionFrames, resume the stackwalk... - - - - - AppDomain* pAppDomain = pCf->GetAppDomain(); - if (pCBdata->prev_AppDomain == NULL) - { - pCBdata->prev_AppDomain = pAppDomain; //innermost AD - } - else if (pCBdata->prev_AppDomain != pAppDomain) - { - // AppDomain Transition - // Update the values in the ADStack for the current AD - Thread *t = GetThread(); - t->GetNextDomainOnStack(&pCBdata->adStackIndex, NULL, NULL); - t->UpdateDomainOnStack(pCBdata->adStackIndex, pCBdata->numDomainAsserts, pCBdata->numDomainOverrides); - - // Update CBdata values - pCBdata->numAsserts+= pCBdata->numDomainAsserts; - pCBdata->numOverrides += pCBdata->numDomainOverrides; - pCBdata->numDomainAsserts = 0; - pCBdata->numDomainOverrides = 0; - pCBdata->prev_AppDomain = pAppDomain; - - } - // Get the security object for this function... - OBJECTREF* pRefSecDesc = pCf->GetAddrOfSecurityObject(); - if (pRefSecDesc != NULL) - { - SecurityDeclarative::DoDeclarativeSecurityAtStackWalk(pMeth, pAppDomain, pRefSecDesc); - FRAMESECDESCREF refFSD = *((FRAMESECDESCREF*)pRefSecDesc); - if (refFSD != NULL) - { - - INT32 ret = refFSD->GetOverridesCount(); - pCBdata->numDomainAsserts+= refFSD->GetAssertCount(); - - if (ret > 0) - { - DBG_TRACE_STACKWALK(" SecurityDescriptor with overrides FOUND.\n", false); - pCBdata->numDomainOverrides += ret; - } - else - { - DBG_TRACE_STACKWALK(" SecurityDescriptor with no override found.\n", false); - } - } - - } - -#ifdef FEATURE_COMPRESSEDSTACK - if(SecurityStackWalk::MethodIsAnonymouslyHostedDynamicMethodWithCSToEvaluate(pMeth)) - { - pCBdata->numDomainAsserts++; - pCBdata->numDomainOverrides++; - } -#endif // FEATURE_COMPRESSEDSTACK - - // If this is a *.Run method, - // or if it has a CompressedStack then we need to terminate the stackwalk - if (pCBdata->IsSpecialRunFrame(pMeth)) - { - DBG_TRACE_STACKWALK(" Halting stackwalk for .Run.\n", false); - return SWA_ABORT; - } - - return SWA_CONTINUE; -} - -VOID SecurityStackWalk::UpdateOverridesCount() -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - // - // Initialize the callback data on the stack. - // - - CountOverridesStackWalk walkData; - - // Get the current thread that we're to walk. - Thread * t = GetThread(); - - - // Don't allow recursive security stackwalks. Note that this implies that - // *no* untrusted code must ever be called during a security stackwalk. - if (t->IsSecurityStackwalkInProgess()) - return; - - EX_TRY - { - t->SetSecurityStackwalkInProgress( TRUE ); - - // - // Begin the stack walk - // - DBG_TRACE_STACKWALK(" Update Overrides Count invoked .\n", false); - // LIGHTUNWIND flag: allow using stackwalk cache for security stackwalks - t->StackWalkFrames(UpdateOverridesCountCB, &walkData, SKIPFUNCLETS | LIGHTUNWIND); -#ifdef FEATURE_COMPRESSEDSTACK - COMPRESSEDSTACKREF csRef = (COMPRESSEDSTACKREF)t->GetCompressedStack(); - - // There may have been an AD transition and we shd look at the CB data to see if this is the case - if (csRef == NULL && walkData.pCtxTxFrame != NULL) - { - csRef = SecurityStackWalk::GetCSFromContextTransitionFrame(walkData.pCtxTxFrame); - } - - // Use CS if found - if (csRef != NULL) - { - - walkData.numDomainOverrides += StackCompressor::GetCSInnerAppDomainOverridesCount(csRef); - walkData.numDomainAsserts += StackCompressor::GetCSInnerAppDomainAssertCount(csRef); - } -#endif // #ifdef FEATURE_COMPRESSEDSTACK - t->GetNextDomainOnStack(&walkData.adStackIndex, NULL, NULL); - t->UpdateDomainOnStack(walkData.adStackIndex, walkData.numDomainAsserts, walkData.numDomainOverrides); - walkData.numAsserts += walkData.numDomainAsserts; - walkData.numOverrides += walkData.numDomainOverrides; - - t->SetSecurityStackwalkInProgress( FALSE ); - } - EX_CATCH - { - // We catch exceptions and rethrow like this to ensure that we've - // established an exception handler on the fs:[0] chain (managed - // exception handlers won't do this). This in turn guarantees that - // managed exception filters in any of our callers won't be found, - // otherwise they could get to execute untrusted code with security - // turned off. - t->SetSecurityStackwalkInProgress( FALSE ); - - EX_RETHROW; - } - EX_END_CATCH_UNREACHABLE - - - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - -// ------------------------------------------------------------------------------- -// -// COMCodeAccessSecurityEngine -// -// ------------------------------------------------------------------------------- -#ifdef FEATURE_COMPRESSEDSTACK -COMPRESSEDSTACKREF SecurityStackWalk::GetCSFromContextTransitionFrame(Frame *pFrame) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - MODE_COOPERATIVE; - } - CONTRACTL_END; - EXECUTIONCONTEXTREF ecRef = NULL; - - if (pFrame != NULL) - ecRef = (EXECUTIONCONTEXTREF)pFrame->GetReturnExecutionContext(); - if (ecRef != NULL) - return (ecRef->GetCompressedStack()); - - return NULL; -} - -#endif // #ifdef FEATURE_COMPRESSEDSTACK - -//-----------------------------------------------------------+ -// Helper used to check a demand set against a provided grant -// and possibly denied set. Grant and denied set might be from -// another domain. -//-----------------------------------------------------------+ -void SecurityStackWalk::CheckSetHelper(OBJECTREF *prefDemand, - OBJECTREF *prefGrant, - OBJECTREF *prefRefused, - AppDomain *pGrantDomain, - MethodDesc *pMethod, - OBJECTREF *pAssembly, - CorDeclSecurity action) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(IsProtectedByGCFrame (prefDemand)); - PRECONDITION(IsProtectedByGCFrame (prefGrant)); - PRECONDITION(IsProtectedByGCFrame (prefRefused)); - PRECONDITION(IsProtectedByGCFrame (pAssembly)); - } CONTRACTL_END; - - // We might need to marshal the grant and denied sets into the current - // domain. -#ifndef FEATURE_CORECLR // should not happen in core clr - if (pGrantDomain != GetAppDomain()) - { - *prefGrant = AppDomainHelper::CrossContextCopyFrom(pGrantDomain, prefGrant); - if (*prefRefused != NULL) - *prefRefused = AppDomainHelper::CrossContextCopyFrom(pGrantDomain, prefRefused); - } -#else - _ASSERTE(pGrantDomain == GetAppDomain()); -#endif - MethodDescCallSite checkSetHelper(METHOD__SECURITY_ENGINE__CHECK_SET_HELPER); - - ARG_SLOT args[] = { - ObjToArgSlot(NULL), - ObjToArgSlot(*prefGrant), - ObjToArgSlot(*prefRefused), - ObjToArgSlot(*prefDemand), - PtrToArgSlot(pMethod), - ObjToArgSlot(*pAssembly), - (ARG_SLOT)action - }; - - checkSetHelper.Call(args); -} - - - - - -FCIMPL0(FC_BOOL_RET, SecurityStackWalk::FCallQuickCheckForAllDemands) -{ - FCALL_CONTRACT; - // This function collides with SecurityPolicy::IsDefaultThreadSecurityInfo - FCUnique(0x17); - FC_RETURN_BOOL(QuickCheckForAllDemands(0)); - -} -FCIMPLEND - -FCIMPL0(FC_BOOL_RET, SecurityStackWalk::FCallAllDomainsHomogeneousWithNoStackModifiers) -{ - FCALL_CONTRACT; - - Thread* t = GetThread(); - FC_RETURN_BOOL(t->AllDomainsHomogeneousWithNoStackModifiers()); - -} -FCIMPLEND - -//----------------------------------------------------------- -// Native implementation for code-access security check. -// Checks that callers on the stack have the permission -// specified in the arguments or checks for unrestricted -// access if the permission is null. -//----------------------------------------------------------- -FCIMPL3(void, SecurityStackWalk::Check, Object* permOrPermSetUNSAFE, StackCrawlMark* stackMark, CLR_BOOL isPermSet) -{ - FCALL_CONTRACT; - - if (QuickCheckForAllDemands(0)) - return; - - FC_INNER_RETURN_VOID(CheckFramed(permOrPermSetUNSAFE, stackMark, isPermSet)); -} -FCIMPLEND - -NOINLINE void SecurityStackWalk::CheckFramed(Object* permOrPermSetUNSAFE, - StackCrawlMark* stackMark, - CLR_BOOL isPermSet) -{ - CONTRACTL { - THROWS; - DISABLED(GC_TRIGGERS); // FCALLS with HELPER frames have issues with GC_TRIGGERS - MODE_COOPERATIVE; - SO_TOLERANT; - } CONTRACTL_END; - - FC_INNER_PROLOG(SecurityStackWalk::Check); - - OBJECTREF permOrPermSet = (OBJECTREF) permOrPermSetUNSAFE; - HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_CAPTURE_DEPTH_2, permOrPermSet); - - Check_PLS_SW(isPermSet, SSWT_IMPERATIVE_DEMAND, &permOrPermSet, stackMark); - - HELPER_METHOD_FRAME_END(); - FC_INNER_EPILOG(); -} - - -void SecurityStackWalk::Check_PLS_SW(BOOL isPermSet, - SecurityStackWalkType eType, - OBJECTREF* permOrPermSet, - StackCrawlMark* stackMark) -{ - - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - if (!PreCheck(permOrPermSet, isPermSet)) - { - Check_StackWalk(eType, permOrPermSet, stackMark, isPermSet); - } -} -void SecurityStackWalk::Check_PLS_SW_GC( BOOL isPermSet, - SecurityStackWalkType eType, - OBJECTREF permOrPermSet, - StackCrawlMark* stackMark) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - GCPROTECT_BEGIN(permOrPermSet); - Check_PLS_SW(isPermSet, eType, &permOrPermSet, stackMark); - GCPROTECT_END(); -} - -void SecurityStackWalk::Check_StackWalk(SecurityStackWalkType eType, - OBJECTREF* pPermOrPermSet, - StackCrawlMark* stackMark, - BOOL isPermSet) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(*pPermOrPermSet != NULL); - } CONTRACTL_END; - -#if defined(ENABLE_PERF_COUNTERS) - // Perf Counter "%Time in Runtime check" support - PERF_COUNTER_TIMER_PRECISION _startPerfCounterTimer = GET_CYCLE_COUNT(); -#endif - - if (GetThread()->GetOverridesCount() != 0) - { - // First let's make sure the overrides count is OK. - UpdateOverridesCount(); - // Once the overrides count has been fixes, let's see if we really need to stackwalk - // This is an additional cost if we do need to walk, but can remove an unnecessary SW otherwise. - // Pick your poison. - if (QuickCheckForAllDemands(0)) - return; // - } - // Initialize callback data. - DWORD dwFlags = 0; - DWORD demandFlags = GetPermissionSpecialFlags(pPermOrPermSet); - - DemandStackWalk walkData(eType, dwFlags, stackMark, (isPermSet?DemandStackWalk::DT_SET:DemandStackWalk::DT_PERMISSION), demandFlags); - walkData.m_objects.SetObject(*pPermOrPermSet); - - // Protect the object references in the callback data. - GCPROTECT_BEGIN(walkData.m_objects.m_sGC); - - walkData.DoStackWalk(); - - GCPROTECT_END(); - -#if defined(ENABLE_PERF_COUNTERS) - // Accumulate the counter - PERF_COUNTER_TIMER_PRECISION _stopPerfCounterTimer = GET_CYCLE_COUNT(); - g_TotalTimeInSecurityRuntimeChecks += _stopPerfCounterTimer - _startPerfCounterTimer; - - // Report the accumulated counter only after NUM_OF_TERATIONS - if (g_SecurityChecksIterations++ > PERF_COUNTER_NUM_OF_ITERATIONS) - { - GetPerfCounters().m_Security.timeRTchecks = static_cast<DWORD>(g_TotalTimeInSecurityRuntimeChecks); - GetPerfCounters().m_Security.timeRTchecksBase = static_cast<DWORD>(_stopPerfCounterTimer - g_LastTimeInSecurityRuntimeChecks); - - g_TotalTimeInSecurityRuntimeChecks = 0; - g_LastTimeInSecurityRuntimeChecks = _stopPerfCounterTimer; - g_SecurityChecksIterations = 0; - } -#endif // #if defined(ENABLE_PERF_COUNTERS) -} - -FCIMPL3(void, SecurityStackWalk::GetZoneAndOrigin, Object* pZoneListUNSAFE, Object* pOriginListUNSAFE, StackCrawlMark* stackMark) -{ - FCALL_CONTRACT; - - OBJECTREF zoneList = (OBJECTREF) pZoneListUNSAFE; - OBJECTREF originList = (OBJECTREF) pOriginListUNSAFE; - HELPER_METHOD_FRAME_BEGIN_2(zoneList, originList); - - // Initialize callback data. - DWORD dwFlags = 0; - DemandStackWalk walkData(SSWT_GET_ZONE_AND_URL, dwFlags, stackMark, DemandStackWalk::DT_ZONE_AND_URL, 0); - walkData.m_objects.SetObjects(zoneList, originList); - - GCPROTECT_BEGIN(walkData.m_objects.m_sGC); - - walkData.DoStackWalk(); - - GCPROTECT_END(); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - -#ifdef FEATURE_COMPRESSEDSTACK -FCIMPL1(VOID, SecurityStackWalk::FcallDestroyDelayedCompressedStack, void *compressedStack) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_0(); - - StackCompressor::Destroy(compressedStack); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND -#endif // FEATURE_COMPRESSEDSTACK -// -// This method checks a few special demands in case we can -// avoid looking at the real PLS object. -// - -DWORD SecurityStackWalk::GetPermissionSpecialFlags (OBJECTREF* orDemand) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM();); - } CONTRACTL_END; - - MethodTable* pMethPermissionSet = MscorlibBinder::GetClass(CLASS__PERMISSION_SET); - MethodTable* pMethNamedPermissionSet = MscorlibBinder::GetClass(CLASS__NAMEDPERMISSION_SET); - MethodTable* pMethReflectionPermission = MscorlibBinder::GetClass(CLASS__REFLECTION_PERMISSION); - MethodTable* pMethSecurityPermission = MscorlibBinder::GetClass(CLASS__SECURITY_PERMISSION); - - DWORD dwSecurityPermissionFlags = 0, dwReflectionPermissionFlags = 0; - MethodTable* pMeth = (*orDemand)->GetMethodTable(); - if (pMeth == pMethPermissionSet || pMeth == pMethNamedPermissionSet) { - // NamedPermissionSet derives from PermissionSet and we're interested only - // in the fields in PermissionSet: so it's OK to cast to the unmanaged - // equivalent of PermissionSet even for a NamedPermissionSet object - PERMISSIONSETREF permSet = (PERMISSIONSETREF) *orDemand; - - if (permSet->IsUnrestricted()) { - return (1 << SECURITY_FULL_TRUST); - } - TOKENBASEDSETREF tokenBasedSet = (TOKENBASEDSETREF) permSet->GetTokenBasedSet(); - if (tokenBasedSet != NULL && tokenBasedSet->GetNumElements() == 1 && tokenBasedSet->GetPermSet() != NULL) { - pMeth = (tokenBasedSet->GetPermSet())->GetMethodTable(); - - if (pMeth == pMethReflectionPermission) { - dwReflectionPermissionFlags = ((REFLECTIONPERMISSIONREF) tokenBasedSet->GetPermSet())->GetFlags(); - } - else if (pMeth == pMethSecurityPermission) { - dwSecurityPermissionFlags = ((SECURITYPERMISSIONREF) tokenBasedSet->GetPermSet())->GetFlags(); - } - } - } - else { - if (pMeth == pMethReflectionPermission) - dwReflectionPermissionFlags = ((REFLECTIONPERMISSIONREF) (*orDemand))->GetFlags(); - else if (pMeth == pMethSecurityPermission) - dwSecurityPermissionFlags = ((SECURITYPERMISSIONREF) (*orDemand))->GetFlags(); - } - - if (pMeth == pMethReflectionPermission) { - switch (dwReflectionPermissionFlags) { - case REFLECTION_PERMISSION_TYPEINFO: - return (1 << REFLECTION_TYPE_INFO); - case REFLECTION_PERMISSION_MEMBERACCESS: - return (1 << REFLECTION_MEMBER_ACCESS); - case REFLECTION_PERMISSION_RESTRICTEDMEMBERACCESS: - return (1 << REFLECTION_RESTRICTED_MEMBER_ACCESS); - default: - return 0; // There is no mapping for this reflection permission flag - } - } else if (pMeth == pMethSecurityPermission) { - switch (dwSecurityPermissionFlags) { - case SECURITY_PERMISSION_ASSERTION: - return (1 << SECURITY_ASSERT); - case SECURITY_PERMISSION_UNMANAGEDCODE: - return (1 << SECURITY_UNMANAGED_CODE); - case SECURITY_PERMISSION_SKIPVERIFICATION: - return (1 << SECURITY_SKIP_VER); - case SECURITY_PERMISSION_SERIALIZATIONFORMATTER: - return (1 << SECURITY_SERIALIZATION); - case SECURITY_PERMISSION_BINDINGREDIRECTS: - return (1 << SECURITY_BINDING_REDIRECTS); - case SECURITY_PERMISSION_CONTROLEVIDENCE: - return (1 << SECURITY_CONTROL_EVIDENCE); - case SECURITY_PERMISSION_CONTROLPRINCIPAL: - return (1 << SECURITY_CONTROL_PRINCIPAL); - default: - return 0; // There is no mapping for this security permission flag - } - } - - // We couldn't find an exact match for the permission, so we'll just return no flags. - return 0; -} - -// check is a stackwalk is needed to evaluate the demand -BOOL SecurityStackWalk::PreCheck (OBJECTREF* orDemand, BOOL fDemandSet) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - // Track perfmon counters. Runtime security checks. - IncrementSecurityPerfCounter(); - - Thread* pThread = GetThread(); - // The PLS optimization does not support overrides. - if (pThread->GetOverridesCount() > 0) - return FALSE; - - DWORD dwDemandSpecialFlags = GetPermissionSpecialFlags(orDemand); - - // If we were able to map the demand to an exact permission special flag, and we know that all code on - // this stack has been granted that permission, then we can take the fast path and allow the demand to - // succeed. - if (dwDemandSpecialFlags != 0) - { - return SecurityStackWalk::HasFlagsOrFullyTrustedIgnoreMode(dwDemandSpecialFlags); - } - -#ifdef FEATURE_PLS - // If we know there is only one AppDomain, then there is - // no need to walk the AppDomainStack structure. - if (pThread->GetNumAppDomainsOnThread() == 1) - { - ApplicationSecurityDescriptor* pASD = static_cast<ApplicationSecurityDescriptor*>(GetAppDomain()->GetSecurityDescriptor()); - return pASD->CheckPLS(orDemand, dwDemandSpecialFlags, fDemandSet); - } - - // Walk all AppDomains in the stack and check the PLS on each one of them - DWORD dwAppDomainIndex = 0; - pThread->InitDomainIteration(&dwAppDomainIndex); - _ASSERT(SystemDomain::System() && "SystemDomain not yet created!"); - while (dwAppDomainIndex != 0) { - AppDomainFromIDHolder appDomain(pThread->GetNextDomainOnStack(&dwAppDomainIndex, NULL, NULL), FALSE); - if (appDomain.IsUnloaded()) - // appdomain has been unloaded, so we can just continue on the loop - continue; - - ApplicationSecurityDescriptor* pAppSecDesc = static_cast<ApplicationSecurityDescriptor*>(appDomain->GetSecurityDescriptor()); - appDomain.Release(); - - if (!pAppSecDesc->CheckPLS(orDemand, dwDemandSpecialFlags, fDemandSet)) - return FALSE; - } - return TRUE; -#else - return FALSE; -#endif // FEATURE_PLS -} - -//-----------------------------------------------------------+ -// Unmanaged version of CodeAccessSecurityEngine.Demand() in BCL -// Any change there may have to be propagated here -// This call has to be virtual, unlike DemandSet -//-----------------------------------------------------------+ -void -SecurityStackWalk::Demand(SecurityStackWalkType eType, OBJECTREF demand) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - if (QuickCheckForAllDemands(0)) - return; - - Check_PLS_SW_GC(FALSE, eType, demand, NULL); -} - -// -// Demand which succeeds if either a demand for a single well known permission or restricted member access is -// granted and a demand for the permission set of the target of a reflection operation would have suceeded. -// -// Arguments: -// dwPermission - Permission input to the demand (See SecurityPolicy.h) -// psdTarget - Security descriptor for the target assembly -// -// Return Value: -// None, a SecurityException is thrown if the demands fail. -// -// Notes: -// This is used by Reflection to implement partial trust reflection, where demands should succeed if either -// a single permission demand, such as MemberAccess, would succeed for compatibility reasons, or if a -// demand for the permission set of the target assembly would succeed. -// -// The intent is to allow reflection in partial trust when reflecting within the same permission set. Note -// that this is inexact, since in the face of RequestRefuse, the target assembly may fail the demand even -// within the same permission set. - -// static -void SecurityStackWalk::ReflectionTargetDemand(DWORD dwPermission, - AssemblySecurityDescriptor *psdTarget) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(dwPermission != 0); - PRECONDITION(CheckPointer(psdTarget)); - } - CONTRACTL_END; - - // If everybody on the stack has the special permission, the disjunctive demand will succeed. - if (QuickCheckForAllDemands(1 << dwPermission)) - return; - - // In the simple sandbox case, we know the disjunctive demand will succeed if: - // * we are granted restricted member access - // * we are not reflecting on a FullTrust assembly - // * every other AppDomain in the call stack is fully trusted - Thread *pCurrentThread = GetThread(); - AppDomainStack appDomains = pCurrentThread->GetAppDomainStack(); - - if (QuickCheckForAllDemands(1 << REFLECTION_RESTRICTED_MEMBER_ACCESS) && - !psdTarget->IsFullyTrusted() && - pCurrentThread->GetDomain()->GetSecurityDescriptor()->IsHomogeneous() && - !pCurrentThread->GetDomain()->GetSecurityDescriptor()->ContainsAnyRefusedPermissions() && - appDomains.GetOverridesCount() == 0) - { - DWORD dwCurrentDomain; - appDomains.InitDomainIteration(&dwCurrentDomain); - - bool fFullTrustStack = true; - while (dwCurrentDomain != 0 && fFullTrustStack) - { - AppDomainStackEntry *pCurrentDomain = appDomains.GetNextDomainEntryOnStack(&dwCurrentDomain); - fFullTrustStack = pCurrentDomain->m_domainID == pCurrentThread->GetDomain()->GetId() || - pCurrentDomain->IsFullyTrustedWithNoStackModifiers(); - } - - if (fFullTrustStack) - return; - } - - OBJECTREF objTargetRefusedSet; - OBJECTREF objTargetGrantSet = psdTarget->GetGrantedPermissionSet(&objTargetRefusedSet); - - GCPROTECT_BEGIN(objTargetGrantSet); - - MethodDescCallSite reflectionTargetDemandHelper(METHOD__SECURITY_ENGINE__REFLECTION_TARGET_DEMAND_HELPER); - ARG_SLOT ilargs[] = - { - static_cast<ARG_SLOT>(dwPermission), - ObjToArgSlot(objTargetGrantSet) - }; - - reflectionTargetDemandHelper.Call(ilargs); - - GCPROTECT_END(); -} - -// -// Similar to a standard refelection target demand, however the demand is done against a captured compressed -// stack instead of the current callstack -// -// Arguments: -// dwPermission - Permission input to the demand (See SecurityPolicy.h) -// psdTarget - Security descriptor for the target assembly -// securityContext - Compressed stack to perform the demand against -// -// Return Value: -// None, a SecurityException is thrown if the demands fail. -// - -// static -void SecurityStackWalk::ReflectionTargetDemand(DWORD dwPermission, - AssemblySecurityDescriptor *psdTarget, - DynamicResolver * pAccessContext) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(dwPermission >= 0 && dwPermission < 32); - PRECONDITION(CheckPointer(psdTarget)); - } - CONTRACTL_END; - - struct - { - OBJECTREF objTargetRefusedSet; - OBJECTREF objTargetGrantSet; - OBJECTREF objAccessContextObject; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - - gc.objTargetGrantSet = psdTarget->GetGrantedPermissionSet(&(gc.objTargetRefusedSet)); - - _ASSERTE(pAccessContext->GetDynamicMethod()->IsLCGMethod()); - gc.objAccessContextObject = ((LCGMethodResolver *)pAccessContext)->GetManagedResolver(); - - MethodDescCallSite reflectionTargetDemandHelper(METHOD__SECURITY_ENGINE__REFLECTION_TARGET_DEMAND_HELPER_WITH_CONTEXT); - ARG_SLOT ilargs[] = - { - static_cast<ARG_SLOT>(dwPermission), - ObjToArgSlot(gc.objTargetGrantSet), - ObjToArgSlot(gc.objAccessContextObject) - }; - - reflectionTargetDemandHelper.Call(ilargs); - - GCPROTECT_END(); -} - -//-----------------------------------------------------------+ -// Special case of Demand(). This remembers the result of the -// previous demand, and reuses it if new assemblies have not -// been added since then -//-----------------------------------------------------------+ -void SecurityStackWalk::SpecialDemand(SecurityStackWalkType eType, DWORD whatPermission, StackCrawlMark* stackMark) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - if (QuickCheckForAllDemands(1<<whatPermission)) - { - // Track perfmon counters. Runtime security checks. - IncrementSecurityPerfCounter(); - return; - } - OBJECTREF demand = NULL; - GCPROTECT_BEGIN(demand); - - SecurityDeclarative::GetPermissionInstance(&demand, whatPermission); - Check_PLS_SW(IS_SPECIAL_FLAG_PERMISSION_SET(whatPermission), eType, &demand, stackMark); - - GCPROTECT_END(); - -} - -// Do a demand for a special permission type -FCIMPL2(void, SecurityStackWalk::FcallSpecialDemand, DWORD whatPermission, StackCrawlMark* stackMark) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_0(); - - SpecialDemand(SSWT_IMPERATIVE_DEMAND, whatPermission, stackMark); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -//-----------------------------------------------------------+ -// Unmanaged version of PermissionSet.Demand() -//-----------------------------------------------------------+ -void SecurityStackWalk::DemandSet(SecurityStackWalkType eType, OBJECTREF demand) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - - // Though the PermissionSet may contain non-CAS permissions, we are considering it as a CAS permission set only - // at this point and so it's safe to check for the FT and if FTmeansFT and return - if (QuickCheckForAllDemands(0)) - return; - - // Do further checks (PLS/SW) only if this set contains CAS perms - if(((PERMISSIONSETREF)demand)->CheckedForNonCas() && !((PERMISSIONSETREF)demand)->ContainsCas()) - return; - - Check_PLS_SW_GC(TRUE, eType, demand, NULL); -} - -void SecurityStackWalk::DemandSet(SecurityStackWalkType eType, PsetCacheEntry *pPCE, DWORD dwAction) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - - // Though the PermissionSet may contain non-CAS permissions, we are considering it as a CAS permission set only - // at this point and so it's safe to check for the FT and if FTmeansFT and return - if (QuickCheckForAllDemands(0)) - return; - - OBJECTREF refPermSet = pPCE->CreateManagedPsetObject (dwAction); - - if(refPermSet != NULL) - { - // Do further checks (PLS/SW) only if this set contains CAS perms - if(((PERMISSIONSETREF)refPermSet)->CheckedForNonCas() && !((PERMISSIONSETREF)refPermSet)->ContainsCas()) - return; - - Check_PLS_SW_GC(TRUE, eType, refPermSet, NULL); - - } -} - -// -// Demand for the grant set of an assembly, without any identity permissions -// -// Arguments: -// psdAssembly - assembly security descriptor to demand the grant set of -// -// Return Value: -// None, a SecurityException is thrown if the demands fail. -// - -// static -void SecurityStackWalk::DemandGrantSet(AssemblySecurityDescriptor *psdAssembly) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(psdAssembly)); - } - CONTRACTL_END; - - OBJECTREF objRefusedSet; - OBJECTREF objGrantSet = psdAssembly->GetGrantedPermissionSet(&objRefusedSet); - - GCPROTECT_BEGIN(objGrantSet); - - if (OBJECTREFToObject(objGrantSet) != NULL) - { - MethodDescCallSite checkWithoutIdentityPermissions(METHOD__SECURITY_ENGINE__CHECK_GRANT_SET_HELPER); - ARG_SLOT ilargs[] = - { - ObjToArgSlot(objGrantSet) - }; - - checkWithoutIdentityPermissions.Call(ilargs); - } - else - { - // null grant set means full trust (mscorlib or anything created by it) - StackCrawlMark scm = LookForMyCaller; - SpecialDemand(SSWT_IMPERATIVE_DEMAND, SECURITY_FULL_TRUST, &scm); - } - - GCPROTECT_END(); -} - -//-----------------------------------------------------------+ -// L I N K /I N H E R I T A N C E T I M E C H E C K -//-----------------------------------------------------------+ -void SecurityStackWalk::LinkOrInheritanceCheck(IAssemblySecurityDescriptor *pSecDesc, OBJECTREF refDemands, Assembly* pAssembly, CorDeclSecurity action) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - // MSCORLIB is not subject to inheritance checks - if (pAssembly->IsSystem()) - return; - - struct _gc { - OBJECTREF refDemands; - OBJECTREF refExposedAssemblyObject; - OBJECTREF refRefused; - OBJECTREF refGranted; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - gc.refDemands = refDemands; - gc.refExposedAssemblyObject = NULL; - - GCPROTECT_BEGIN(gc); - - - OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED); - - // We only do LinkDemands if the assembly is not fully trusted or if the demand contains permissions that don't implement IUnrestricted - if (!pAssembly->GetSecurityDescriptor()->IsFullyTrusted()) - { - if (pAssembly) - gc.refExposedAssemblyObject = pAssembly->GetExposedObject(); - - if (!pSecDesc->IsFullyTrusted()) - { - MethodDescCallSite checkSetHelper(METHOD__SECURITY_ENGINE__CHECK_SET_HELPER); - gc.refGranted = pSecDesc->GetGrantedPermissionSet(&(gc.refRefused)); - ARG_SLOT ilargs[7]; - ilargs[0] = ObjToArgSlot(NULL); - ilargs[1] = ObjToArgSlot(gc.refGranted); - ilargs[2] = ObjToArgSlot(gc.refRefused); - ilargs[3] = ObjToArgSlot(gc.refDemands); - ilargs[4] = PtrToArgSlot(NULL); - ilargs[5] = ObjToArgSlot(gc.refExposedAssemblyObject); - ilargs[6] = (ARG_SLOT)action; - checkSetHelper.Call(ilargs); - } - } - GCPROTECT_END(); -} - - -//-----------------------------------------------------------+ -// S T A C K C O M P R E S S I O N FCALLS -//-----------------------------------------------------------+ - - - -#ifdef FEATURE_COMPRESSEDSTACK -FCIMPL2(Object*, SecurityStackWalk::EcallGetDelayedCompressedStack, StackCrawlMark* stackMark, CLR_BOOL fWalkStack) -{ - FCALL_CONTRACT; - - OBJECTREF rv = NULL; - - // No need to GC-protect stackMark as it a byref on the stack - _ASSERTE(PVOID(stackMark) < GetThread()->GetCachedStackBase() && - PVOID(stackMark) > PVOID(&rv)); - - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - rv = StackCompressor::GetCompressedStack(stackMark, fWalkStack); - - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(rv); - -} -FCIMPLEND -#endif // #ifdef FEATURE_COMPRESSEDSTACK - -#ifdef FEATURE_COMPRESSEDSTACK -BOOL SecurityStackWalk::MethodIsAnonymouslyHostedDynamicMethodWithCSToEvaluate(MethodDesc* pMeth) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - if (!pMeth->IsLCGMethod()) - { - return FALSE; - } - Assembly* pAssembly = pMeth->GetAssembly(); - AppDomain* pAppDomain = GetAppDomain(); - if(pAssembly != NULL && pAppDomain != NULL && pAssembly->GetDomainAssembly(pAppDomain) == pAppDomain->GetAnonymouslyHostedDynamicMethodsAssembly()) - { - GCX_COOP(); - DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default; - TypeHandle dynamicOwner; // not used - pMeth->AsDynamicMethodDesc()->GetLCGMethodResolver()->GetJitContextCoop(&dwSecurityFlags, &dynamicOwner); - if((dwSecurityFlags & DynamicResolver::CanSkipCSEvaluation) == 0) - { - return TRUE; - } - } - - return FALSE; -} -#endif // FEATURE_COMPRESSEDSTACK |