Skip to content

Commit d1b9e0e

Browse files
committed
When deserializing the parser state cache, verify the script code matches the script used to create the cache
Calculate a checksum of the script code and store it in the stream along with the parser state cache. When we try and use this parser state cache later, make sure the script we are given back matches the script we used to create the cache. If it doesn't for some reason, discard the parser state cache as it may not match the script code exactly. Fixes: https://microsoft.visualstudio.com/OS/_workitems/edit/17542547 https://microsoft.visualstudio.com/OS/_workitems/edit/17713429
1 parent e2ae16a commit d1b9e0e

File tree

8 files changed

+80
-40
lines changed

8 files changed

+80
-40
lines changed

lib/Backend/Encoder.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -997,34 +997,6 @@ void Encoder::EnsureRelocEntryIntegrity(size_t newBufferStartAddress, size_t cod
997997
}
998998
}
999999

1000-
uint Encoder::CalculateCRC(uint bufferCRC, size_t data)
1001-
{
1002-
#if defined(_WIN32) || defined(__SSE4_2__)
1003-
#if defined(_M_IX86)
1004-
if (AutoSystemInfo::Data.SSE4_2Available())
1005-
{
1006-
return _mm_crc32_u32(bufferCRC, data);
1007-
}
1008-
#elif defined(_M_X64)
1009-
if (AutoSystemInfo::Data.SSE4_2Available())
1010-
{
1011-
//CRC32 always returns a 32-bit result
1012-
return (uint)_mm_crc32_u64(bufferCRC, data);
1013-
}
1014-
#endif
1015-
#endif
1016-
return CalculateCRC32(bufferCRC, data);
1017-
}
1018-
1019-
uint Encoder::CalculateCRC(uint bufferCRC, size_t count, _In_reads_bytes_(count) void * buffer)
1020-
{
1021-
for (uint index = 0; index < count; index++)
1022-
{
1023-
bufferCRC = CalculateCRC(bufferCRC, *((BYTE*)buffer + index));
1024-
}
1025-
return bufferCRC;
1026-
}
1027-
10281000
void Encoder::ValidateCRC(uint bufferCRC, uint initialCRCSeed, _In_reads_bytes_(count) void* buffer, size_t count)
10291001
{
10301002
uint validationCRC = initialCRCSeed;

lib/Backend/Encoder.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ class Encoder
6363
void TryCopyAndAddRelocRecordsForSwitchJumpTableEntries(BYTE *codeStart, size_t codeSize, JmpTableList * jumpTableListForSwitchStatement, size_t totalJmpTableSizeInBytes);
6464

6565
void ValidateCRC(uint bufferCRC, uint initialCRCSeed, _In_reads_bytes_(count) void* buffer, size_t count);
66-
static uint CalculateCRC(uint bufferCRC, size_t count, _In_reads_bytes_(count) void * buffer);
67-
static uint CalculateCRC(uint bufferCRC, size_t data);
6866
static void EnsureRelocEntryIntegrity(size_t newBufferStartAddress, size_t codeSize, size_t oldBufferAddress, size_t relocAddress, uint offsetBytes, ptrdiff_t opndData, bool isRelativeAddr = true);
6967
#if defined(_M_IX86) || defined(_M_X64)
7068
void ValidateCRCOnFinalBuffer(_In_reads_bytes_(finalCodeSize) BYTE * finalCodeBufferStart, size_t finalCodeSize, size_t jumpTableSize, _In_reads_bytes_(finalCodeSize) BYTE * oldCodeBufferStart, uint initialCrcSeed, uint bufferCrcToValidate, BOOL isSuccessBrShortAndLoopAlign);

lib/Backend/amd64/EncoderMD.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//-------------------------------------------------------------------------------------------------------
55

66
#include "Backend.h"
7+
#include "Core/CRC.h"
78

89
#include "X64Encode.h"
910

@@ -1637,7 +1638,7 @@ EncoderMD::ApplyRelocs(size_t codeBufferAddress_, size_t codeSize, uint * buffer
16371638
}
16381639
}
16391640

1640-
*bufferCRC = Encoder::CalculateCRC(*bufferCRC, pcrel);
1641+
*bufferCRC = CalculateCRC(*bufferCRC, pcrel);
16411642

16421643
break;
16431644
}
@@ -1658,7 +1659,7 @@ EncoderMD::ApplyRelocs(size_t codeBufferAddress_, size_t codeSize, uint * buffer
16581659
{
16591660
Encoder::EnsureRelocEntryIntegrity(codeBufferAddress_, codeSize, (size_t)m_encoder->m_encodeBuffer, (size_t)relocAddress, sizeof(size_t), targetAddress, false);
16601661
}
1661-
*bufferCRC = Encoder::CalculateCRC(*bufferCRC, offset);
1662+
*bufferCRC = CalculateCRC(*bufferCRC, offset);
16621663
break;
16631664
}
16641665
case RelocTypeLabel:

lib/Backend/i386/EncoderMD.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//-------------------------------------------------------------------------------------------------------
55

66
#include "Backend.h"
7+
#include "Core/CRC.h"
78

89
#include "X86Encode.h"
910

@@ -1431,7 +1432,7 @@ EncoderMD::ApplyRelocs(uint32 codeBufferAddress, size_t codeSize, uint * bufferC
14311432
Assert(*(uint32 *)relocAddress == 0);
14321433
*(uint32 *)relocAddress = offset;
14331434
}
1434-
*bufferCRC = Encoder::CalculateCRC(*bufferCRC, offset);
1435+
*bufferCRC = CalculateCRC(*bufferCRC, offset);
14351436
break;
14361437
}
14371438
case RelocTypeBranch:
@@ -1466,7 +1467,7 @@ EncoderMD::ApplyRelocs(uint32 codeBufferAddress, size_t codeSize, uint * bufferC
14661467
Encoder::EnsureRelocEntryIntegrity(codeBufferAddress, codeSize, (size_t)m_encoder->m_encodeBuffer, (size_t)relocAddress, sizeof(uint32), (ptrdiff_t)labelInstr->GetPC() - ((ptrdiff_t)reloc->m_ptr + 4));
14671468
}
14681469
}
1469-
*bufferCRC = Encoder::CalculateCRC(*bufferCRC, pcrel);
1470+
*bufferCRC = CalculateCRC(*bufferCRC, pcrel);
14701471
break;
14711472
}
14721473
case RelocTypeLabelUse:
@@ -1484,7 +1485,7 @@ EncoderMD::ApplyRelocs(uint32 codeBufferAddress, size_t codeSize, uint * bufferC
14841485
{
14851486
Encoder::EnsureRelocEntryIntegrity(codeBufferAddress, codeSize, (size_t)m_encoder->m_encodeBuffer, (size_t)relocAddress, sizeof(size_t), targetAddress, false);
14861487
}
1487-
*bufferCRC = Encoder::CalculateCRC(*bufferCRC, offset);
1488+
*bufferCRC = CalculateCRC(*bufferCRC, offset);
14881489
break;
14891490
}
14901491
case RelocTypeLabel:

lib/Common/Core/CRC.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,31 @@ unsigned int CalculateCRC32(const char* in)
2525
}
2626
return crc ^ (unsigned int)-1;
2727
}
28+
29+
uint CalculateCRC(uint bufferCRC, size_t data)
30+
{
31+
#if defined(_WIN32) || defined(__SSE4_2__)
32+
#if defined(_M_IX86)
33+
if (AutoSystemInfo::Data.SSE4_2Available())
34+
{
35+
return _mm_crc32_u32(bufferCRC, data);
36+
}
37+
#elif defined(_M_X64)
38+
if (AutoSystemInfo::Data.SSE4_2Available())
39+
{
40+
//CRC32 always returns a 32-bit result
41+
return (uint)_mm_crc32_u64(bufferCRC, data);
42+
}
43+
#endif
44+
#endif
45+
return CalculateCRC32(bufferCRC, data);
46+
}
47+
48+
uint CalculateCRC(uint bufferCRC, size_t count, _In_reads_bytes_(count) void * buffer)
49+
{
50+
for (uint index = 0; index < count; index++)
51+
{
52+
bufferCRC = CalculateCRC(bufferCRC, *((BYTE*)buffer + index));
53+
}
54+
return bufferCRC;
55+
}

lib/Common/Core/CRC.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,7 @@ static const unsigned int crc_32_tab[] =
5151
unsigned int CalculateCRC32(unsigned int bufferCRC, size_t data);
5252

5353
unsigned int CalculateCRC32(const char* in);
54+
55+
uint CalculateCRC(uint bufferCRC, size_t data);
56+
57+
uint CalculateCRC(uint bufferCRC, size_t count, _In_reads_bytes_(count) void * buffer);

lib/Runtime/Base/ScriptContext.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#include "ByteCode/ByteCodeSerializer.h"
4141
#include "Language/SimpleDataCacheWrapper.h"
42+
#include "Core/CRC.h"
4243

4344
namespace Js
4445
{
@@ -2119,6 +2120,7 @@ namespace Js
21192120

21202121
HRESULT ScriptContext::TryDeserializeParserState(
21212122
_In_ ULONG grfscr,
2123+
_In_ uint sourceCRC,
21222124
_In_ charcount_t cchLength,
21232125
_In_ SRCINFO *srcInfo,
21242126
_In_ Js::Utf8SourceInfo* utf8SourceInfo,
@@ -2143,18 +2145,37 @@ namespace Js
21432145

21442146
#ifdef ENABLE_WININET_PROFILE_DATA_CACHE
21452147
// Find the parser state block in the read stream and get the size of the block in bytes.
2146-
ULONG byteCount = 0;
2148+
ULONG blockByteCount = 0;
21472149
DebugOnly(auto url = !srcInfo->sourceContextInfo->isHostDynamicDocument ? srcInfo->sourceContextInfo->url : this->GetUrl());
21482150

21492151
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Trying to read parser state cache for '%s'\n"), url);
21502152

2151-
hr = pDataCache->SeekReadStreamToBlock(SimpleDataCacheWrapper::BlockType_ParserState, &byteCount);
2153+
hr = pDataCache->SeekReadStreamToBlock(SimpleDataCacheWrapper::BlockType_ParserState, &blockByteCount);
21522154
if (FAILED(hr))
21532155
{
21542156
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Failed to find parser state cache in the stream (hr = 0x%08lx) for '%s'\n"), hr, url);
21552157
return hr;
21562158
}
21572159

2160+
uint expectedCRC = 0;
2161+
hr = pDataCache->Read(&expectedCRC);
2162+
if (FAILED(hr))
2163+
{
2164+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Failed to read CRC value (hr = 0x%08lx) for '%s'\n"), hr, url);
2165+
return hr;
2166+
}
2167+
2168+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Computed CRC value = 0x%08lx (expected CRC value = 0x%08lx) for '%s'\n"), sourceCRC, expectedCRC, url);
2169+
2170+
if (expectedCRC != sourceCRC)
2171+
{
2172+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Fail CRC check, discarding parser state cache for '%s'\n"), url);
2173+
return E_FAIL;
2174+
}
2175+
2176+
// The block includes a 4-byte CRC before the parser state cache.
2177+
ULONG byteCount = blockByteCount - sizeof(uint);
2178+
21582179
// The contract for this bytecode buffer is that it is available as long as we have this ScriptContext.
21592180
// We will use this buffer as the string table needed to back the deferred stubs as well as bytecode
21602181
// for defer deserialized functions.
@@ -2213,6 +2234,7 @@ namespace Js
22132234
}
22142235

22152236
HRESULT ScriptContext::TrySerializeParserState(
2237+
_In_ uint sourceCRC,
22162238
_In_ LPCUTF8 pszSrc,
22172239
_In_ size_t cbLength,
22182240
_In_ SRCINFO *srcInfo,
@@ -2263,14 +2285,24 @@ namespace Js
22632285

22642286
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Trying to write parser state cache (%lu bytes) to stream for '%s'\n"), serializeParserStateCacheSize, url);
22652287

2266-
hr = pDataCache->StartBlock(Js::SimpleDataCacheWrapper::BlockType_ParserState, serializeParserStateCacheSize);
2288+
hr = pDataCache->StartBlock(Js::SimpleDataCacheWrapper::BlockType_ParserState, serializeParserStateCacheSize + sizeof(uint));
22672289

22682290
if (FAILED(hr))
22692291
{
22702292
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Failed to write a block to the parser state cache data stream (hr = 0x%08lx) for '%s'\n"), hr, url);
22712293
return hr;
22722294
}
22732295

2296+
hr = pDataCache->Write(sourceCRC);
2297+
2298+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Computed CRC value = 0x%08lx for '%s'\n"), sourceCRC, url);
2299+
2300+
if (FAILED(hr))
2301+
{
2302+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Failed to write CRC data to the data stream (hr = 0x%08lx) for '%s'\n"), hr, url);
2303+
return hr;
2304+
}
2305+
22742306
hr = pDataCache->WriteArray(serializeParserStateCacheBuffer, serializeParserStateCacheSize);
22752307

22762308
if (FAILED(hr))
@@ -2314,10 +2346,12 @@ namespace Js
23142346
&& !this->IsScriptContextInDebugMode();
23152347
byte* parserStateCacheBuffer = nullptr;
23162348
DWORD parserStateCacheByteCount = 0;
2349+
uint computedSourceCRC = 0;
23172350

23182351
if (fUseParserStateCache)
23192352
{
2320-
hr = TryDeserializeParserState(grfscr, cchLength, srcInfo, utf8SourceInfo, sourceIndex, isCesu8, nullptr, func, &parserStateCacheBuffer, &parserStateCacheByteCount, pDataCache);
2353+
computedSourceCRC = CalculateCRC(0, cbLength, (void*)pszSrc);
2354+
hr = TryDeserializeParserState(grfscr, computedSourceCRC, cchLength, srcInfo, utf8SourceInfo, sourceIndex, isCesu8, nullptr, func, &parserStateCacheBuffer, &parserStateCacheByteCount, pDataCache);
23212355
#ifdef ENABLE_WININET_PROFILE_DATA_CACHE
23222356
// ERROR_WRITE_PROTECT indicates we cannot cache this script for whatever reason.
23232357
// Disable generating and serializing the parser state cache.
@@ -2366,7 +2400,7 @@ namespace Js
23662400
if (fUseParserStateCache)
23672401
{
23682402
Assert(*func != nullptr);
2369-
TrySerializeParserState(pszSrc, cbLength, srcInfo, *func, parserStateCacheBuffer, parserStateCacheByteCount, pDataCache);
2403+
TrySerializeParserState(computedSourceCRC, pszSrc, cbLength, srcInfo, *func, parserStateCacheBuffer, parserStateCacheByteCount, pDataCache);
23702404
}
23712405
}
23722406
#ifdef ENABLE_SCRIPT_DEBUGGING

lib/Runtime/Base/ScriptContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,7 @@ namespace Js
12911291

12921292
HRESULT TryDeserializeParserState(
12931293
_In_ ULONG grfscr,
1294+
_In_ uint sourceCRC,
12941295
_In_ charcount_t cchLength,
12951296
_In_ SRCINFO *srcInfo,
12961297
_In_ Js::Utf8SourceInfo* utf8SourceInfo,
@@ -1303,6 +1304,7 @@ namespace Js
13031304
_In_ Js::SimpleDataCacheWrapper* pDataCache);
13041305

13051306
HRESULT TrySerializeParserState(
1307+
_In_ uint sourceCRC,
13061308
_In_ LPCUTF8 pszSrc,
13071309
_In_ size_t cbLength,
13081310
_In_ SRCINFO *srcInfo,

0 commit comments

Comments
 (0)