diff options
Diffstat (limited to 'src/vm/pefingerprint.cpp')
-rw-r--r-- | src/vm/pefingerprint.cpp | 557 |
1 files changed, 0 insertions, 557 deletions
diff --git a/src/vm/pefingerprint.cpp b/src/vm/pefingerprint.cpp index 775966663f..b02e8a30bb 100644 --- a/src/vm/pefingerprint.cpp +++ b/src/vm/pefingerprint.cpp @@ -33,330 +33,6 @@ #include "pefile.h" #include "pefingerprint.h" -#ifdef FEATURE_FUSION - -static VOID ThrowTornState(LPCWSTR path); -static void FetchILTimestampAndSize(LPCWSTR path, FILETIME *pTimestamp, DWORD *pSize, HANDLE hFileHandleIfOpen = INVALID_HANDLE_VALUE); - - -const size_t PEFingerprint::s_offsets[] = -{ - offsetof(PEFingerprint, m_timeStamp), - offsetof(PEFingerprint, m_size), - offsetof(PEFingerprint, m_mvid), -}; - -const DWORD PEFingerprint::s_sizes[] = -{ - sizeof(((PEFingerprint *)NULL)->m_timeStamp), - sizeof(((PEFingerprint *)NULL)->m_size), - sizeof(((PEFingerprint *)NULL)->m_mvid), -}; - - - -//--------------------------------------------------------------- -// Ctor -//--------------------------------------------------------------- -PEFingerprint::PEFingerprint(PEImage *owner) : - m_pcrst(NULL) - ,m_peimage(owner) - ,m_commitMask(0) - ,m_alreadyLoaded(FALSE) - ,m_priorLockAndLoadFailure(S_OK) -{ - - LIMITED_METHOD_CONTRACT; - - _ASSERTE(owner); - - memset(&m_timeStamp, 0xcc, sizeof(m_timeStamp)); - memset(&m_size, 0xcc, sizeof(m_size)); - memset(&m_mvid, 0xcc, sizeof(m_mvid)); - - return; -} - - -//--------------------------------------------------------------- -// PEFingerprint factory -//--------------------------------------------------------------- -/*static*/ PEFingerprint *PEFingerprint::CreatePEFingerprint(PEImage *owner) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - SO_INTOLERANT; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END - - NewHolder<PEFingerprint> pPEFingerprint = new PEFingerprint(owner); - pPEFingerprint->m_pcrst = new Crst(CrstLeafLock); - - //--------------------------------------------------------------- - // Since obtaining the timestamp is cheap and doesn't need to open the - // file, go ahead and get it now and commit into the fingerprint. - // - // @review: Would it be better to lock the file right now to - // prevent overwriter for the life of the fingerprint? - //--------------------------------------------------------------- - LPCWSTR path = pPEFingerprint->m_peimage->GetPath(); - _ASSERTE(path); - - FILETIME lastWriteTime; - DWORD size; - FetchILTimestampAndSize(path, &lastWriteTime, &size); - - ILFingerprintComponent components[] = - { - { ILFTagTimestamp, &lastWriteTime }, - { ILFTagSize, &size }, - }; - BOOL success = pPEFingerprint->CommitAndCompareMulti(COUNTOF(components), components); - _ASSERTE(success); // No way this commit can fail - we own the only pointer! - return pPEFingerprint.Extract(); -} - - - -//--------------------------------------------------------------- -// Dtor -//--------------------------------------------------------------- -PEFingerprint::~PEFingerprint() -{ - LIMITED_METHOD_CONTRACT; - delete m_pcrst; - return; -} - -//--------------------------------------------------------------- -// AddRef -//--------------------------------------------------------------- -ULONG PEFingerprint::AddRef() -{ - LIMITED_METHOD_CONTRACT; - return m_peimage->AddRef(); -} - -//--------------------------------------------------------------- -// Release -//--------------------------------------------------------------- -ULONG PEFingerprint::Release() -{ - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_CAN_TAKE_LOCK; - return m_peimage->Release(); -} - -//--------------------------------------------------------------------------------------------- -// Convenience fcn: equivalent to calling CommitAndCompareMulti() with one component. -//--------------------------------------------------------------------------------------------- -BOOL PEFingerprint::CommitAndCompare(ILFingerprintTag componentType, LPCVOID data) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - SO_INTOLERANT; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END - - ILFingerprintComponent c = {componentType, data}; - return CommitAndCompareMulti(1, &c); -} - - - //--------------------------------------------------------------------------------------------- - // CommitAndCompareMulti(): Atomically commits one or more fingerprint components into - // the fingerprint. Once a component is committed, its value can never change. - // - // An attempt to commit a component succeeds only if the component was not already committed - // or the prior value maches the new one exactly. - // - // Calling CommitAndCompare() multiple times is not equivalent to calling CommitAndCompareMulti(). - // CommitAndCompareMulti() is atomic - either all the commits happen or none of them do. - // - // Returns: - // TRUE: All passed components committed successful. - // FALSE: At leat one component failed to commit successfully. - //--------------------------------------------------------------------------------------------- -BOOL PEFingerprint::CommitAndCompareMulti(UINT numComponents, const ILFingerprintComponent *pComponents) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - SO_INTOLERANT; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END - - //------------------------------------------------------------------------------ - // See "Dev11 note on timing of torn state detection". This step should not be - // here but this is how we "verify" the MVID/SNHash on IL open. We wait until - // the first time someone attempts a commit on an opened file to do the check. - // The caller will think we did the check at file open time, even though we - // actually left a window of vulnerability. - //------------------------------------------------------------------------------ - if (!m_alreadyLoaded) - { - PEImageHolder pOpenedILimage; - m_peimage->Clone(MDInternalImport_OnlyLookInCache,&pOpenedILimage); - - if(pOpenedILimage != NULL && pOpenedILimage->IsOpened()) - { - - for (UINT j = 0; j < numComponents; j++) - { - // Don't open if we're just checking timestamp (forecloses possible reentrancy problems - // due to timestamp commits occurring within PEImage itself.) - ILFingerprintTag tag = pComponents[j]._tag; - if (tag == ILFTagMvid) - { - this->LockAndLoadIL(); - break; - } - - } - } - } - - //------------------------------------------------------------------------------ - // Inside the crit section, make sure all the components can successfully commit - // before commitng any of them. - //------------------------------------------------------------------------------ - CrstHolder ch(m_pcrst); - UINT i; - for (i = 0; i < numComponents; i++) - { - ILFingerprintTag tag = pComponents[i]._tag; - if (IsComponentCommitted(tag)) - { - if (0 != memcmp(pComponents[i]._data, TagDataStart(tag), TagDataSize(tag))) - return FALSE; - } - } - for (i = 0; i < numComponents; i++) - { - ILFingerprintTag tag = pComponents[i]._tag; - if (!IsComponentCommitted(tag)) - { - memcpy(TagDataStart(tag), pComponents[i]._data, TagDataSize(tag)); - SetComponentCommitted(tag); - } - } - - return TRUE; -} - - - -//--------------------------------------------------------------------------------------------- -// LockAndLoadIL() -// -// Forces the runtime to open the IL file and lock it against future overwrites. This -// is bad for working set so this should be avoided. -// -// Once opened and locked, this method extracts the actual fingerprint from the IL file -// and attempts to commit it into the ILFingerprint. If successful, all future commits -// will now be compared against this trusted data. If unsuccessful, this is a torn state -// situation and LockAndLoadIL() throws the torn state exception. -//--------------------------------------------------------------------------------------------- -void PEFingerprint::LockAndLoadIL() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - SO_INTOLERANT; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END - - //---------------------------------------------------------------------------------- - // If already loaded, return the prior result. - //---------------------------------------------------------------------------------- - if (m_alreadyLoaded) - { - if (FAILED(m_priorLockAndLoadFailure)) - { - ThrowHR(m_priorLockAndLoadFailure); - } - else - { - return; - } - } - PEImageHolder pOpenedILimage; - m_peimage->Clone(MDInternalImport_Default,&pOpenedILimage); - HRESULT hr = S_OK; - { - GCX_PREEMP(); - IfFailThrow(m_peimage->TryOpenFile()); - } - //---------------------------------------------------------------------------------- - // Force the file open (by requesting a metadata pointer to it.) - //---------------------------------------------------------------------------------- - IMDInternalImport *pMDImport = NULL; - EX_TRY - { - pMDImport = pOpenedILimage->GetMDImport(); - hr = S_OK; - } - EX_CATCH_HRESULT(hr); - if (Exception::IsTransient(hr)) - ThrowHR(hr); - if (FAILED(hr)) - { - m_priorLockAndLoadFailure = hr; - m_alreadyLoaded = TRUE; - ThrowHR(hr); - } - - m_alreadyLoaded = TRUE; - - //------------------------------------------------------------------------------ - // See "Dev11 note on timing of torn state detection". This step should not be - // here as the "right" design is to extract the actual MVID before we officially - // open the file. But since we don't do that in the current implementation, we do - // it now. - //------------------------------------------------------------------------------ - GUID mvid; - pOpenedILimage->GetMVID(&mvid); - - BOOL success = this->CommitAndCompare(ILFTagMvid, &mvid); - if (!success) - ThrowTornState(m_peimage->GetPath()); -} - - -//================================================================================== -// Helper for throwing a torn state exception. -//================================================================================== -static VOID ThrowTornState(LPCWSTR path) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - SO_INTOLERANT; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END - - COMPlusThrow(kFileLoadException, IDS_EE_TORNSTATE, path); -} - -#endif // FEATURE_FUSION @@ -384,240 +60,7 @@ PEFingerprintVerificationHolder::PEFingerprintVerificationHolder(PEImage *owner) } CONTRACTL_END -#ifdef FEATURE_FUSION - if (owner->IsTrustedNativeImage()) - return; // Waste of cycles to check timestamps for NI images. - - - LPCWSTR path = owner->GetPath(); - _ASSERTE(path); - - if (owner->IsOpened()) - return; // Not the first layout to be opened - no need to repeat the work in that case. - - // First, lock the file and verify that the timestamp hasn't changed. - TESTHOOKCALL(AboutToLockImage(path, IsCompilationProcess())); - m_fileHandle = WszCreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (m_fileHandle == INVALID_HANDLE_VALUE) - { - // @review: If this call to open the file fails, it sounds a bit risky to fail the PE open altogether - // just to do a torn state check. Let the torn state detection bake a bit before we take this step. - return; - } - - FILETIME lastWriteTime; - DWORD size; - FetchILTimestampAndSize(path, &lastWriteTime, &size, m_fileHandle); - ReleaseHolder<IILFingerprint> fingerPrint; - ILFingerprintComponent components[] = - { - { ILFTagTimestamp, &lastWriteTime }, - { ILFTagSize, &size }, - }; - IfFailThrow(owner->GetILFingerprint(&fingerPrint)); - if (!fingerPrint->CommitAndCompareMulti(COUNTOF(components), components)) - ThrowTornState(path); - - - // Now, verify that the MVID/SNHash/TPBand hasn't changed. - // Oh wait, where that'd code go? See "Dev11 note on timing of torn state detection". -#endif // FEATURE_FUSION - return; -} - -#ifdef FEATURE_FUSION -#ifndef DACCESS_COMPILE -class CachingILFingerprintFactory : public IILFingerprintFactory -{ -private: - LONG m_refCount; - Crst m_lock; - - // Hash Type ... NOTE! This is a case sensitive hash of a filename to an IL fingerprint. - // This is acceptable as duplicates are not errors, and chosen as case insensitive hashes - // are somewhat slower, and most hash lookups will actually match in case. If this is not - // the case, converting to a case-insensitive hash should be trivial. - typedef StringSHashWithCleanup< IILFingerprint, WCHAR > ILFingerprintHash; - typedef StringHashElement< IILFingerprint, WCHAR > ILFingerprintHashElement; - - ILFingerprintHash m_hash; - - ~CachingILFingerprintFactory() - { - } - -public: - - CachingILFingerprintFactory() : m_refCount(1), m_lock(CrstILFingerprintCache) - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END; - } - - STDMETHOD_(ULONG, AddRef)() - { - CONTRACT(ULONG) - { - PRECONDITION(m_refCount>0 && m_refCount < COUNT_T_MAX); - NOTHROW; - GC_NOTRIGGER; - } - CONTRACT_END; - - RETURN (static_cast<ULONG>(FastInterlockIncrement(&m_refCount))); - } - - STDMETHOD_(ULONG, Release)() - { - CONTRACTL - { - DESTRUCTOR_CHECK; - NOTHROW; - MODE_ANY; - FORBID_FAULT; - } - CONTRACTL_END; - - ULONG result = 0; - result=FastInterlockDecrement(&m_refCount); - if (result == 0) - delete this; - - return result; - } - - STDMETHOD(GetILFingerprintForPath)( - LPCWSTR pwzPath, - IILFingerprint **ppFingerprint) - { - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - HRESULT hr = S_OK; - - EX_TRY - { - CrstHolder ch(&m_lock); - // Lookup in cache - ILFingerprintHashElement *pCacheElement = m_hash.Lookup(pwzPath); - - // If that fails, run the parser, and populate the cache - if (pCacheElement != NULL) - { - *ppFingerprint = clr::SafeAddRef(pCacheElement->Object); - } - else - { - // Create new assembly name object; - ReleaseHolder<IILFingerprint> pFingerprint; - NewArrayHolder<WCHAR> pwzPathCopy; - IfFailThrow(RuntimeGetILFingerprintForPath(pwzPath, &pFingerprint)); - - // Create hash element object - NewHolder<ILFingerprintHashElement> pHashElem = new ILFingerprintHashElement(); - pwzPathCopy = DuplicateStringThrowing(pwzPath); - pHashElem->String = pwzPathCopy; - pHashElem->Object = pFingerprint; - - // Insert into hash table - m_hash.Add(pHashElem); - - *ppFingerprint = clr::SafeAddRef(pFingerprint); - - // Prevent disastrous cleanup - pwzPathCopy.SuppressRelease(); - pHashElem.SuppressRelease(); - pFingerprint.SuppressRelease(); - } - } - EX_CATCH_HRESULT(hr); - - return hr; - } -}; - -HRESULT RuntimeCreateCachingILFingerprintFactory(IILFingerprintFactory **ppILFingerprintFactory) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - HRESULT hr = S_OK; - - EX_TRY - { - *ppILFingerprintFactory = new CachingILFingerprintFactory(); - } - EX_CATCH_HRESULT(hr); - - return hr; -} - -//------------------------------------------------------------------------------------------------------------- -// Common routine to fetch the IL file's timestamp and size. If the caller already has an open file handle, it should -// pass that as "hFileHandleIfOpen" to avoid the overhead of opening the file again. -//------------------------------------------------------------------------------------------------------------- -static void FetchILTimestampAndSize(LPCWSTR path, FILETIME *pTimestamp, DWORD *pSize, HANDLE hFileHandleIfOpen /* = INVALID_HANDLE_VALUE*/) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - SO_INTOLERANT; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END - - _ASSERTE(pTimestamp != NULL && pSize != NULL); - - if (hFileHandleIfOpen != INVALID_HANDLE_VALUE) - { - BY_HANDLE_FILE_INFORMATION info; - if (!GetFileInformationByHandle(hFileHandleIfOpen, &info)) - ThrowLastError(); - *pTimestamp = info.ftLastWriteTime; - *pSize = info.nFileSizeLow; - return; - } - - // For normal files, we can obtain the timestamp without opening the file - attempt to do so. - WIN32_FILE_ATTRIBUTE_DATA wfd; - if (!WszGetFileAttributesEx(path, GetFileExInfoStandard, &wfd)) - ThrowLastError(); - if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) - { - *pTimestamp = wfd.ftLastWriteTime; - *pSize = wfd.nFileSizeLow; - return; - } - - // If we got here, the original path pointed to a symbolic or some other form of reparse point. In such cases, GetFileAttributesEx - // may not return the same timestamp as GetFileInformationByHandle. (E.g. in the symbolic link case, GetFileAttributeEx returns - // the symbolic link's timestamp rather than the target's timestamp.) - // - // Since this is the uncommon case, we can justify the perf hit of opening the file so we get the timestamp - // on the actual target. - HandleHolder hFile(WszCreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); - if (hFile == INVALID_HANDLE_VALUE) - ThrowLastError(); - BY_HANDLE_FILE_INFORMATION info; - if (!GetFileInformationByHandle(hFile, &info)) - ThrowLastError(); - *pTimestamp = info.ftLastWriteTime; - *pSize = info.nFileSizeLow; return; } -#endif // !DACCESS_COMPILE -#endif // FEATURE_FUSION |