| 1 | // Licensed to the .NET Foundation under one or more agreements. | 
|---|
| 2 | // The .NET Foundation licenses this file to you under the MIT license. | 
|---|
| 3 | // See the LICENSE file in the project root for more information. | 
|---|
| 4 | //***************************************************************************** | 
|---|
| 5 | // MDFileFormat.cpp | 
|---|
| 6 | // | 
|---|
| 7 |  | 
|---|
| 8 | // | 
|---|
| 9 | // This file contains a set of helpers to verify and read the file format. | 
|---|
| 10 | // This code does not handle the paging of the data, or different types of | 
|---|
| 11 | // I/O.  See the StgTiggerStorage and StgIO code for this level of support. | 
|---|
| 12 | // | 
|---|
| 13 | //***************************************************************************** | 
|---|
| 14 |  | 
|---|
| 15 | #include "stdafx.h"                     // Standard header file. | 
|---|
| 16 | #include "mdfileformat.h"               // The format helpers. | 
|---|
| 17 | #include "posterror.h"                  // Error handling code. | 
|---|
| 18 |  | 
|---|
| 19 | //***************************************************************************** | 
|---|
| 20 | // Verify the signature at the front of the file to see what type it is. | 
|---|
| 21 | //***************************************************************************** | 
|---|
| 22 | #define STORAGE_MAGIC_OLD_SIG   0x2B4D4F43  // +MOC (old version of BSJB signature code:STORAGE_MAGIC_SIG) | 
|---|
| 23 | HRESULT | 
|---|
| 24 | MDFormat::VerifySignature( | 
|---|
| 25 | PSTORAGESIGNATURE pSig,     // The signature to check. | 
|---|
| 26 | ULONG             cbData) | 
|---|
| 27 | { | 
|---|
| 28 | HRESULT hr = S_OK; | 
|---|
| 29 |  | 
|---|
| 30 | // If signature didn't match, you shouldn't be here. | 
|---|
| 31 | ULONG dwSignature = pSig->GetSignature(); | 
|---|
| 32 | if (dwSignature == STORAGE_MAGIC_OLD_SIG) | 
|---|
| 33 | { | 
|---|
| 34 | Debug_ReportError( "Invalid MetaData storage signature - old magic signature +MOC."); | 
|---|
| 35 | return PostError(CLDB_E_FILE_OLDVER, 1, 0); | 
|---|
| 36 | } | 
|---|
| 37 | if (dwSignature != STORAGE_MAGIC_SIG) | 
|---|
| 38 | { | 
|---|
| 39 | Debug_ReportError( "Invalid MetaData storage signature - unrecognized magic signature, should be BSJB."); | 
|---|
| 40 | return PostError(CLDB_E_FILE_CORRUPT); | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | // Check for overflow | 
|---|
| 44 | ULONG lVersionString = pSig->GetVersionStringLength(); | 
|---|
| 45 | ULONG sum = sizeof(STORAGESIGNATURE) + lVersionString; | 
|---|
| 46 | if ((sum < sizeof(STORAGESIGNATURE)) || (sum < lVersionString)) | 
|---|
| 47 | { | 
|---|
| 48 | Debug_ReportError( "Invalid MetaData storage signature - version string too long, integer overflow."); | 
|---|
| 49 | return PostError(CLDB_E_FILE_CORRUPT); | 
|---|
| 50 | } | 
|---|
| 51 |  | 
|---|
| 52 | // Check for invalid version string size | 
|---|
| 53 | if ((sizeof(STORAGESIGNATURE) + lVersionString) > cbData) | 
|---|
| 54 | { | 
|---|
| 55 | Debug_ReportError( "Invalid MetaData storage signature - version string too long."); | 
|---|
| 56 | return PostError(CLDB_E_FILE_CORRUPT); | 
|---|
| 57 | } | 
|---|
| 58 |  | 
|---|
| 59 | // Check that the version string is null terminated. This string | 
|---|
| 60 | // is ANSI, so no double-null checks need to be made. | 
|---|
| 61 | { | 
|---|
| 62 | BYTE *pStart = &pSig->pVersion[0]; | 
|---|
| 63 | BYTE *pEnd = pStart + lVersionString + 1; // Account for terminating NULL | 
|---|
| 64 | BYTE *pCur; | 
|---|
| 65 |  | 
|---|
| 66 | for (pCur = pStart; pCur < pEnd; pCur++) | 
|---|
| 67 | { | 
|---|
| 68 | if (*pCur == 0) | 
|---|
| 69 | break; | 
|---|
| 70 | } | 
|---|
| 71 |  | 
|---|
| 72 | // If we got to the end without hitting a NULL, we have a bad version string | 
|---|
| 73 | if (pCur == pEnd) | 
|---|
| 74 | { | 
|---|
| 75 | Debug_ReportError( "Invalid MetaData storage signature - version string has not null-terminator."); | 
|---|
| 76 | return PostError(CLDB_E_FILE_CORRUPT); | 
|---|
| 77 | } | 
|---|
| 78 | } | 
|---|
| 79 |  | 
|---|
| 80 | // Only a specific version of the 0.x format is supported by this code | 
|---|
| 81 | // in order to support the NT 5 beta clients which used this format. | 
|---|
| 82 | if (pSig->GetMajorVer() == FILE_VER_MAJOR_v0) | 
|---|
| 83 | { | 
|---|
| 84 | if (pSig->GetMinorVer() < FILE_VER_MINOR_v0) | 
|---|
| 85 | { | 
|---|
| 86 | Debug_ReportError( "Invalid MetaData storage signature - unrecognized version, should be 1.1."); | 
|---|
| 87 | hr = CLDB_E_FILE_OLDVER; | 
|---|
| 88 | } | 
|---|
| 89 | } | 
|---|
| 90 | else | 
|---|
| 91 | // There is currently no code to migrate an old format of the 1.x.  This | 
|---|
| 92 | // would be added only under special circumstances. | 
|---|
| 93 | if ((pSig->GetMajorVer() != FILE_VER_MAJOR) || (pSig->GetMinorVer() != FILE_VER_MINOR)) | 
|---|
| 94 | { | 
|---|
| 95 | Debug_ReportError( "Invalid MetaData storage signature - unrecognized version, should be 1.1."); | 
|---|
| 96 | hr = CLDB_E_FILE_OLDVER; | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | if (FAILED(hr)) | 
|---|
| 100 | hr = PostError(hr, (int)pSig->GetMajorVer(), (int)pSig->GetMinorVer()); | 
|---|
| 101 | return hr; | 
|---|
| 102 | } // MDFormat::VerifySignature | 
|---|
| 103 |  | 
|---|
| 104 | //***************************************************************************** | 
|---|
| 105 | // Skip over the header and find the actual stream data. | 
|---|
| 106 | // It doesn't perform any checks for buffer overflow - use GetFirstStream_Verify | 
|---|
| 107 | // instead. | 
|---|
| 108 | //***************************************************************************** | 
|---|
| 109 | PSTORAGESTREAM | 
|---|
| 110 | MDFormat::( | 
|---|
| 111 | PSTORAGEHEADER ,     // Return copy of header struct. | 
|---|
| 112 | const void    *pvMd)        // Pointer to the full file. | 
|---|
| 113 | { | 
|---|
| 114 | const BYTE *pbMd; | 
|---|
| 115 |  | 
|---|
| 116 | // Header data starts after signature. | 
|---|
| 117 | pbMd = (const BYTE *) pvMd; | 
|---|
| 118 | pbMd += sizeof(STORAGESIGNATURE); | 
|---|
| 119 | pbMd += ((STORAGESIGNATURE*)pvMd)->GetVersionStringLength(); | 
|---|
| 120 | PSTORAGEHEADER pHdr = (PSTORAGEHEADER) pbMd; | 
|---|
| 121 | *pHeader = *pHdr; | 
|---|
| 122 | pbMd += sizeof(STORAGEHEADER); | 
|---|
| 123 |  | 
|---|
| 124 | // ECMA specifies that the flags field is "reserved, must be 0". | 
|---|
| 125 | if (pHdr->GetFlags() != 0) | 
|---|
| 126 | return NULL; | 
|---|
| 127 |  | 
|---|
| 128 | // The pointer is now at the first stream in the list. | 
|---|
| 129 | return ((PSTORAGESTREAM) pbMd); | 
|---|
| 130 | } // MDFormat::GetFirstStream | 
|---|
| 131 |  | 
|---|
| 132 | //***************************************************************************** | 
|---|
| 133 | // Skip over the header and find the actual stream data.  Secure version of | 
|---|
| 134 | // GetFirstStream method. | 
|---|
| 135 | // The header is supposed to be verified by VerifySignature. | 
|---|
| 136 | // | 
|---|
| 137 | // Returns pointer to the first stream (behind storage header) and the size of | 
|---|
| 138 | // the remaining buffer in *pcbMd (could be 0). | 
|---|
| 139 | // Returns NULL if there is not enough buffer for reading the headers. The *pcbMd | 
|---|
| 140 | // could be changed if NULL returned. | 
|---|
| 141 | // | 
|---|
| 142 | // Caller has to check available buffer size before using the first stream. | 
|---|
| 143 | //***************************************************************************** | 
|---|
| 144 | PSTORAGESTREAM | 
|---|
| 145 | MDFormat::( | 
|---|
| 146 | PSTORAGEHEADER ,     // Return copy of header struct. | 
|---|
| 147 | const void    *pvMd,        // Pointer to the full file. | 
|---|
| 148 | ULONG         *pcbMd)       // [in, out] Size of pvMd buffer (we don't want to read behind it) | 
|---|
| 149 | { | 
|---|
| 150 | const BYTE *pbMd; | 
|---|
| 151 |  | 
|---|
| 152 | // Header data starts after signature. | 
|---|
| 153 | pbMd = (const BYTE *)pvMd; | 
|---|
| 154 | // Check read buffer overflow | 
|---|
| 155 | if (*pcbMd < sizeof(STORAGESIGNATURE)) | 
|---|
| 156 | { | 
|---|
| 157 | Debug_ReportError( "Invalid MetaData - Storage signature doesn't fit."); | 
|---|
| 158 | return NULL; | 
|---|
| 159 | } | 
|---|
| 160 | pbMd += sizeof(STORAGESIGNATURE); | 
|---|
| 161 | *pcbMd -= sizeof(STORAGESIGNATURE); | 
|---|
| 162 |  | 
|---|
| 163 | ULONG cbVersionString = ((STORAGESIGNATURE *)pvMd)->GetVersionStringLength(); | 
|---|
| 164 | // Check read buffer overflow | 
|---|
| 165 | if (*pcbMd < cbVersionString) | 
|---|
| 166 | { | 
|---|
| 167 | Debug_ReportError( "Invalid MetaData storage signature - Version string doesn't fit."); | 
|---|
| 168 | return NULL; | 
|---|
| 169 | } | 
|---|
| 170 | pbMd += cbVersionString; | 
|---|
| 171 | *pcbMd -= cbVersionString; | 
|---|
| 172 |  | 
|---|
| 173 | // Is there enough space for storage header? | 
|---|
| 174 | if (*pcbMd < sizeof(STORAGEHEADER)) | 
|---|
| 175 | { | 
|---|
| 176 | Debug_ReportError( "Invalid MetaData storage header - Storage header doesn't fit."); | 
|---|
| 177 | return NULL; | 
|---|
| 178 | } | 
|---|
| 179 | PSTORAGEHEADER pHdr = (PSTORAGEHEADER) pbMd; | 
|---|
| 180 | *pHeader = *pHdr; | 
|---|
| 181 | pbMd += sizeof(STORAGEHEADER); | 
|---|
| 182 | *pcbMd -= sizeof(STORAGEHEADER); | 
|---|
| 183 |  | 
|---|
| 184 | // ECMA specifies that the flags field is "reserved, must be 0". | 
|---|
| 185 | if (pHdr->GetFlags() != 0) | 
|---|
| 186 | { | 
|---|
| 187 | Debug_ReportError( "Invalid MetaData storage header - Flags are not 0."); | 
|---|
| 188 | return NULL; | 
|---|
| 189 | } | 
|---|
| 190 |  | 
|---|
| 191 | // The pointer is now at the first stream in the list. | 
|---|
| 192 | return (PSTORAGESTREAM)pbMd; | 
|---|
| 193 | } // MDFormat::GetFirstStream | 
|---|
| 194 |  | 
|---|