Skip to content

Commit 6ca912c

Browse files
authored
Fix integer overflow in section and subsection size checks (#2694)
1 parent 1298485 commit 6ca912c

2 files changed

Lines changed: 55 additions & 8 deletions

File tree

src/binary-reader.cc

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ Result BinaryReader::ReadStr(std::string_view* out_str, const char* desc) {
417417
uint32_t str_len = 0;
418418
CHECK_RESULT(ReadU32Leb128(&str_len, "string length"));
419419

420-
ERROR_UNLESS(state_.offset + str_len <= read_end_,
420+
ERROR_UNLESS(str_len <= read_end_ - state_.offset,
421421
"unable to read string: %s", desc);
422422

423423
*out_str = std::string_view(
@@ -442,7 +442,7 @@ Result BinaryReader::ReadBytes(const void** out_data,
442442
Result BinaryReader::ReadBytesWithSize(const void** out_data,
443443
Offset size,
444444
const char* desc) {
445-
ERROR_UNLESS(state_.offset + size <= read_end_, "unable to read data: %s",
445+
ERROR_UNLESS(size <= read_end_ - state_.offset, "unable to read data: %s",
446446
desc);
447447

448448
*out_data = static_cast<const uint8_t*>(state_.data) + state_.offset;
@@ -2033,9 +2033,9 @@ Result BinaryReader::ReadNameSection(Offset section_size) {
20332033
}
20342034
previous_subsection_type = name_type;
20352035
CHECK_RESULT(ReadOffset(&subsection_size, "subsection size"));
2036-
size_t subsection_end = state_.offset + subsection_size;
2037-
ERROR_UNLESS(subsection_end <= read_end_,
2036+
ERROR_UNLESS(subsection_size <= read_end_ - state_.offset,
20382037
"invalid sub-section size: extends past end");
2038+
size_t subsection_end = state_.offset + subsection_size;
20392039
ReadEndRestoreGuard guard(this);
20402040
read_end_ = subsection_end;
20412041

@@ -2224,9 +2224,9 @@ Result BinaryReader::ReadDylink0Section(Offset section_size) {
22242224
Offset subsection_size;
22252225
CHECK_RESULT(ReadU32Leb128(&dylink_type, "type"));
22262226
CHECK_RESULT(ReadOffset(&subsection_size, "subsection size"));
2227-
size_t subsection_end = state_.offset + subsection_size;
2228-
ERROR_UNLESS(subsection_end <= read_end_,
2227+
ERROR_UNLESS(subsection_size <= read_end_ - state_.offset,
22292228
"invalid sub-section size: extends past end");
2229+
size_t subsection_end = state_.offset + subsection_size;
22302230
ReadEndRestoreGuard guard(this);
22312231
read_end_ = subsection_end;
22322232

@@ -2356,9 +2356,9 @@ Result BinaryReader::ReadLinkingSection(Offset section_size) {
23562356
Offset subsection_size;
23572357
CHECK_RESULT(ReadU32Leb128(&linking_type, "type"));
23582358
CHECK_RESULT(ReadOffset(&subsection_size, "subsection size"));
2359-
size_t subsection_end = state_.offset + subsection_size;
2360-
ERROR_UNLESS(subsection_end <= read_end_,
2359+
ERROR_UNLESS(subsection_size <= read_end_ - state_.offset,
23612360
"invalid sub-section size: extends past end");
2361+
size_t subsection_end = state_.offset + subsection_size;
23622362
ReadEndRestoreGuard guard(this);
23632363
read_end_ = subsection_end;
23642364

@@ -3107,6 +3107,8 @@ Result BinaryReader::ReadSections(const ReadSectionsOptions& options) {
31073107
Offset section_size;
31083108
CHECK_RESULT(ReadU8(&section_code, "section code"));
31093109
CHECK_RESULT(ReadOffset(&section_size, "section size"));
3110+
ERROR_UNLESS(section_size <= state_.size - state_.offset,
3111+
"invalid section size: extends past end");
31103112
ReadEndRestoreGuard guard(this);
31113113
read_end_ = state_.offset + section_size;
31123114
if (section_code >= kBinarySectionCount) {

src/test-binary-reader.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,48 @@ TEST(BinaryReader, InvalidFunctionBodySize) {
9999
reader.first_error.message.find("invalid function body size"))
100100
<< "Got: " << reader.first_error.message;
101101
}
102+
103+
TEST(BinaryReader, OversizedSectionSize) {
104+
// A module whose section size extends past the end of the data. The
105+
// subtraction-based overflow check must reject this before computing
106+
// read_end_ = offset + section_size, which would overflow on platforms
107+
// where size_t is 32-bit.
108+
// TODO: Move this test upstream into the spec repo.
109+
110+
uint8_t data[] = {
111+
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, // magic + version
112+
0x01, // section code: Type
113+
0x80, 0x80, 0x80, 0x80, 0x08, // section size: 0x80000000 (LEB128)
114+
};
115+
116+
BinaryReaderError reader;
117+
ReadBinaryOptions options;
118+
Result result = ReadBinary(data, sizeof(data), &reader, options);
119+
EXPECT_EQ(Result::Error, result);
120+
EXPECT_NE(std::string::npos,
121+
reader.first_error.message.find("invalid section size"))
122+
<< "Got: " << reader.first_error.message;
123+
}
124+
125+
TEST(BinaryReader, OversizedSubsectionSize) {
126+
// A module with a name section containing a subsection whose size extends
127+
// past the section boundary.
128+
// TODO: Move this test upstream into the spec repo.
129+
130+
uint8_t data[] = {
131+
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, // magic + version
132+
// Custom section (name section)
133+
0x00, // section code: custom
134+
0x09, // section size: 9 bytes
135+
0x04, // name length
136+
'n', 'a', 'm', 'e',
137+
0x01, // subsection type: function names
138+
0x80, 0x80, 0x04, // subsection size: 65536 (LEB128), exceeds section
139+
};
140+
141+
BinaryReaderError reader;
142+
ReadBinaryOptions options;
143+
Result result = ReadBinary(data, sizeof(data), &reader, options);
144+
// Custom section errors are not fatal by default, but ensure no crash.
145+
(void)result;
146+
}

0 commit comments

Comments
 (0)