summaryrefslogtreecommitdiff
path: root/src/md/runtime/mdfileformat.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/runtime/mdfileformat.cpp')
-rw-r--r--src/md/runtime/mdfileformat.cpp195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/md/runtime/mdfileformat.cpp b/src/md/runtime/mdfileformat.cpp
new file mode 100644
index 0000000000..2edd2e0292
--- /dev/null
+++ b/src/md/runtime/mdfileformat.cpp
@@ -0,0 +1,195 @@
+// 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.
+//*****************************************************************************
+// MDFileFormat.cpp
+//
+
+//
+// This file contains a set of helpers to verify and read the file format.
+// This code does not handle the paging of the data, or different types of
+// I/O. See the StgTiggerStorage and StgIO code for this level of support.
+//
+//*****************************************************************************
+
+#include "stdafx.h" // Standard header file.
+#include "mdfileformat.h" // The format helpers.
+#include "posterror.h" // Error handling code.
+
+//*****************************************************************************
+// Verify the signature at the front of the file to see what type it is.
+//*****************************************************************************
+#define STORAGE_MAGIC_OLD_SIG 0x2B4D4F43 // +MOC (old version of BSJB signature code:STORAGE_MAGIC_SIG)
+HRESULT
+MDFormat::VerifySignature(
+ PSTORAGESIGNATURE pSig, // The signature to check.
+ ULONG cbData)
+{
+ HRESULT hr = S_OK;
+
+ // If signature didn't match, you shouldn't be here.
+ ULONG dwSignature = pSig->GetSignature();
+ if (dwSignature == STORAGE_MAGIC_OLD_SIG)
+ {
+ Debug_ReportError("Invalid MetaData storage signature - old magic signature +MOC.");
+ return PostError(CLDB_E_FILE_OLDVER, 1, 0);
+ }
+ if (dwSignature != STORAGE_MAGIC_SIG)
+ {
+ Debug_ReportError("Invalid MetaData storage signature - unrecognized magic signature, should be BSJB.");
+ return PostError(CLDB_E_FILE_CORRUPT);
+ }
+
+ // Check for overflow
+ ULONG lVersionString = pSig->GetVersionStringLength();
+ ULONG sum = sizeof(STORAGESIGNATURE) + lVersionString;
+ if ((sum < sizeof(STORAGESIGNATURE)) || (sum < lVersionString))
+ {
+ Debug_ReportError("Invalid MetaData storage signature - version string too long, integer overflow.");
+ return PostError(CLDB_E_FILE_CORRUPT);
+ }
+
+ // Check for invalid version string size
+ if ((sizeof(STORAGESIGNATURE) + lVersionString) > cbData)
+ {
+ Debug_ReportError("Invalid MetaData storage signature - version string too long.");
+ return PostError(CLDB_E_FILE_CORRUPT);
+ }
+
+ // Check that the version string is null terminated. This string
+ // is ANSI, so no double-null checks need to be made.
+ {
+ BYTE *pStart = &pSig->pVersion[0];
+ BYTE *pEnd = pStart + lVersionString + 1; // Account for terminating NULL
+ BYTE *pCur;
+
+ for (pCur = pStart; pCur < pEnd; pCur++)
+ {
+ if (*pCur == 0)
+ break;
+ }
+
+ // If we got to the end without hitting a NULL, we have a bad version string
+ if (pCur == pEnd)
+ {
+ Debug_ReportError("Invalid MetaData storage signature - version string has not null-terminator.");
+ return PostError(CLDB_E_FILE_CORRUPT);
+ }
+ }
+
+#if !defined(FEATURE_METADATA_STANDALONE_WINRT)
+ // Only a specific version of the 0.x format is supported by this code
+ // in order to support the NT 5 beta clients which used this format.
+ if (pSig->GetMajorVer() == FILE_VER_MAJOR_v0)
+ {
+ if (pSig->GetMinorVer() < FILE_VER_MINOR_v0)
+ {
+ Debug_ReportError("Invalid MetaData storage signature - unrecognized version, should be 1.1.");
+ hr = CLDB_E_FILE_OLDVER;
+ }
+ }
+ else
+#endif // !defined(FEATURE_METADATA_STANDALONE_WINRT)
+ // There is currently no code to migrate an old format of the 1.x. This
+ // would be added only under special circumstances.
+ if ((pSig->GetMajorVer() != FILE_VER_MAJOR) || (pSig->GetMinorVer() != FILE_VER_MINOR))
+ {
+ Debug_ReportError("Invalid MetaData storage signature - unrecognized version, should be 1.1.");
+ hr = CLDB_E_FILE_OLDVER;
+ }
+
+ if (FAILED(hr))
+ hr = PostError(hr, (int)pSig->GetMajorVer(), (int)pSig->GetMinorVer());
+ return hr;
+} // MDFormat::VerifySignature
+
+//*****************************************************************************
+// Skip over the header and find the actual stream data.
+// It doesn't perform any checks for buffer overflow - use GetFirstStream_Verify
+// instead.
+//*****************************************************************************
+PSTORAGESTREAM
+MDFormat::GetFirstStream(
+ PSTORAGEHEADER pHeader, // Return copy of header struct.
+ const void *pvMd) // Pointer to the full file.
+{
+ const BYTE *pbMd;
+
+ // Header data starts after signature.
+ pbMd = (const BYTE *) pvMd;
+ pbMd += sizeof(STORAGESIGNATURE);
+ pbMd += ((STORAGESIGNATURE*)pvMd)->GetVersionStringLength();
+ PSTORAGEHEADER pHdr = (PSTORAGEHEADER) pbMd;
+ *pHeader = *pHdr;
+ pbMd += sizeof(STORAGEHEADER);
+
+ // ECMA specifies that the flags field is "reserved, must be 0".
+ if (pHdr->GetFlags() != 0)
+ return NULL;
+
+ // The pointer is now at the first stream in the list.
+ return ((PSTORAGESTREAM) pbMd);
+} // MDFormat::GetFirstStream
+
+//*****************************************************************************
+// Skip over the header and find the actual stream data. Secure version of
+// GetFirstStream method.
+// The header is supposed to be verified by VerifySignature.
+//
+// Returns pointer to the first stream (behind storage header) and the size of
+// the remaining buffer in *pcbMd (could be 0).
+// Returns NULL if there is not enough buffer for reading the headers. The *pcbMd
+// could be changed if NULL returned.
+//
+// Caller has to check available buffer size before using the first stream.
+//*****************************************************************************
+PSTORAGESTREAM
+MDFormat::GetFirstStream_Verify(
+ PSTORAGEHEADER pHeader, // Return copy of header struct.
+ const void *pvMd, // Pointer to the full file.
+ ULONG *pcbMd) // [in, out] Size of pvMd buffer (we don't want to read behind it)
+{
+ const BYTE *pbMd;
+
+ // Header data starts after signature.
+ pbMd = (const BYTE *)pvMd;
+ // Check read buffer overflow
+ if (*pcbMd < sizeof(STORAGESIGNATURE))
+ {
+ Debug_ReportError("Invalid MetaData - Storage signature doesn't fit.");
+ return NULL;
+ }
+ pbMd += sizeof(STORAGESIGNATURE);
+ *pcbMd -= sizeof(STORAGESIGNATURE);
+
+ ULONG cbVersionString = ((STORAGESIGNATURE *)pvMd)->GetVersionStringLength();
+ // Check read buffer overflow
+ if (*pcbMd < cbVersionString)
+ {
+ Debug_ReportError("Invalid MetaData storage signature - Version string doesn't fit.");
+ return NULL;
+ }
+ pbMd += cbVersionString;
+ *pcbMd -= cbVersionString;
+
+ // Is there enough space for storage header?
+ if (*pcbMd < sizeof(STORAGEHEADER))
+ {
+ Debug_ReportError("Invalid MetaData storage header - Storage header doesn't fit.");
+ return NULL;
+ }
+ PSTORAGEHEADER pHdr = (PSTORAGEHEADER) pbMd;
+ *pHeader = *pHdr;
+ pbMd += sizeof(STORAGEHEADER);
+ *pcbMd -= sizeof(STORAGEHEADER);
+
+ // ECMA specifies that the flags field is "reserved, must be 0".
+ if (pHdr->GetFlags() != 0)
+ {
+ Debug_ReportError("Invalid MetaData storage header - Flags are not 0.");
+ return NULL;
+ }
+
+ // The pointer is now at the first stream in the list.
+ return (PSTORAGESTREAM)pbMd;
+} // MDFormat::GetFirstStream