bound tilde stream row-count read in dotnet_parse_tilde_2 (#2224)

dotnet_parse_tilde computes tilde_stream_end and checks each row-count
read against it since #2196 (fits_in_pe was only checking the read
against the whole PE buffer, not the #~ stream's own declared Size).
dotnet_parse_tilde_2 is called right after with the same tilde_header
and streams, but it independently re-reads the identical row-count
array using the pre-#2196 fits_in_pe check - the #2196 fix never
touched this function.

tilde_stream_end is derived from streams->tilde->Offset and Size,
which are read straight from the stream header with no bound against
pe->data_size (dotnet_parse_stream_headers only validates the header
struct itself fits in the PE, not the Offset/Size values it stores).
So tilde_stream_end can point past the real buffer.

dotnet_parse_tilde stays safe despite this because it first does a
whole-array fits_in_pe(pe, row_offset, valid_count * sizeof(uint32_t))
before the loop, and only uses tilde_stream_end afterward as a
secondary restriction on top of that already-verified range.
dotnet_parse_tilde_2 has no such preceding fits_in_pe over the row
array, so swapping its per-row fits_in_pe check for a tilde_stream_end-only
check (as this PR did originally) would have made tilde_stream_end the
sole bound on the read, which is unsafe since it's an unclamped,
file-controlled pointer.

Keep the fits_in_pe check and add the tilde_stream_end check on top,
matching the two-layer approach dotnet_parse_tilde already uses.

Built locally and ran make test-dotnet, passes clean.
This commit is contained in:
Cole Munz
2026-07-22 08:56:47 +02:00
committed by GitHub
parent f66f730881
commit 3a68d1cd23
+6 -1
View File
@@ -1917,6 +1917,10 @@ void dotnet_parse_tilde_2(
const uint8_t* string_offset;
const uint8_t* blob_offset;
const uint8_t* tilde_stream_end = pe->data + metadata_root +
yr_le32toh(streams->tilde->Offset) +
yr_le32toh(streams->tilde->Size);
uint32_t num_rows = 0;
uint32_t valid_rows = 0;
uint32_t* row_offset = NULL;
@@ -1992,7 +1996,8 @@ void dotnet_parse_tilde_2(
if (!((yr_le64toh(tilde_header->Valid) >> bit_check) & 0x01))
continue;
if (!fits_in_pe(pe, row_offset + matched_bits, sizeof(uint32_t)))
if (!fits_in_pe(pe, row_offset + matched_bits, sizeof(uint32_t)) ||
(uint8_t*) (row_offset + matched_bits + 1) > tilde_stream_end)
return;
num_rows = yr_le32toh(*(row_offset + matched_bits));