diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/components/zucchini | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) | |
download | qtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/zucchini')
-rw-r--r-- | chromium/components/zucchini/BUILD.gn | 6 | ||||
-rw-r--r-- | chromium/components/zucchini/disassembler_elf.cc | 25 | ||||
-rw-r--r-- | chromium/components/zucchini/fuzzers/BUILD.gn | 46 | ||||
-rw-r--r-- | chromium/components/zucchini/reloc_elf.cc | 8 | ||||
-rw-r--r-- | chromium/components/zucchini/reloc_elf_unittest.cc | 203 |
5 files changed, 204 insertions, 84 deletions
diff --git a/chromium/components/zucchini/BUILD.gn b/chromium/components/zucchini/BUILD.gn index 00bacd8d19a..54b06ab6500 100644 --- a/chromium/components/zucchini/BUILD.gn +++ b/chromium/components/zucchini/BUILD.gn @@ -207,9 +207,7 @@ test("zucchini_unittests") { } test("zucchini_integration_test") { - sources = [ - "integration_test.cc", - ] + sources = [ "integration_test.cc" ] deps = [ ":zucchini_lib", @@ -218,6 +216,8 @@ test("zucchini_integration_test") { "//base/test:test_support", "//testing/gtest", ] + + data = [ "testdata" ] } # Group to build and depend on all the Zucchini related fuzzers. diff --git a/chromium/components/zucchini/disassembler_elf.cc b/chromium/components/zucchini/disassembler_elf.cc index fdc104f2c14..4727d1cf697 100644 --- a/chromium/components/zucchini/disassembler_elf.cc +++ b/chromium/components/zucchini/disassembler_elf.cc @@ -10,6 +10,7 @@ #include <utility> #include "base/logging.h" +#include "base/numerics/checked_math.h" #include "base/numerics/safe_conversions.h" #include "components/zucchini/abs32_utils.h" #include "components/zucchini/algorithm.h" @@ -44,6 +45,15 @@ enum SectionJudgement : int { // from SectionJudgement values. template <class Traits> int JudgeSection(size_t image_size, const typename Traits::Elf_Shdr* section) { + // BufferRegion uses |size_t| this can be 32-bit in some cases. For Elf64 + // |sh_addr|, |sh_offset| and |sh_size| are 64-bit this can result in + // overflows in the subsequent validation steps. + if (!base::IsValueInRangeForNumericType<size_t>(section->sh_addr) || + !base::IsValueInRangeForNumericType<size_t>(section->sh_offset) || + !base::IsValueInRangeForNumericType<size_t>(section->sh_size)) { + return SECTION_IS_MALFORMED; + } + // Examine RVA range: Reject if numerical overflow may happen. if (!BufferRegion{section->sh_addr, section->sh_size}.FitsIn(kSizeBound)) return SECTION_IS_MALFORMED; @@ -219,6 +229,9 @@ std::unique_ptr<ReferenceWriter> DisassemblerElf<Traits>::MakeWriteRelocs( template <class Traits> bool DisassemblerElf<Traits>::ParseHeader() { BufferSource source(image_); + // Ensure any offsets will fit within the |image_|'s bounds. + if (!base::IsValueInRangeForNumericType<offset_t>(image_.size())) + return false; // Ensures |header_| is valid later on. if (!QuickDetect(image_)) @@ -263,10 +276,16 @@ bool DisassemblerElf<Traits>::ParseHeader() { // Visits |segments_| to get estimate on |offset_bound|. for (const typename Traits::Elf_Phdr* segment = segments_; segment != segments_ + segments_count_; ++segment) { - if (!image_.covers({segment->p_offset, segment->p_filesz})) + // |image_.covers()| is a sufficient check except when size_t is 32 bit and + // parsing ELF64. In such cases a value-in-range check is needed on the + // segment. This fixes crbug/1035603. + offset_t segment_end; + base::CheckedNumeric<offset_t> checked_segment_end = segment->p_offset; + checked_segment_end += segment->p_filesz; + if (!checked_segment_end.AssignIfValid(&segment_end) || + !image_.covers({segment->p_offset, segment->p_filesz})) { return false; - offset_t segment_end = - base::checked_cast<offset_t>(segment->p_offset + segment->p_filesz); + } offset_bound = std::max(offset_bound, segment_end); } diff --git a/chromium/components/zucchini/fuzzers/BUILD.gn b/chromium/components/zucchini/fuzzers/BUILD.gn index effc22daadb..90c436e8aca 100644 --- a/chromium/components/zucchini/fuzzers/BUILD.gn +++ b/chromium/components/zucchini/fuzzers/BUILD.gn @@ -21,9 +21,7 @@ static_library("zucchini_fuzz_utils") { # gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_dex_fuzzer \ # components/zucchini/fuzzing/testdata/disassembler_dex_fuzzer/ fuzzer_test("zucchini_disassembler_dex_fuzzer") { - sources = [ - "disassembler_dex_fuzzer.cc", - ] + sources = [ "disassembler_dex_fuzzer.cc" ] deps = [ "//base", "//components/zucchini:zucchini_lib", @@ -35,9 +33,7 @@ fuzzer_test("zucchini_disassembler_dex_fuzzer") { # gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_win32_fuzzer \ # components/zucchini/fuzzing/testdata/disassembler_win32_fuzzer/ fuzzer_test("zucchini_disassembler_win32_fuzzer") { - sources = [ - "disassembler_win32_fuzzer.cc", - ] + sources = [ "disassembler_win32_fuzzer.cc" ] deps = [ ":zucchini_fuzz_utils", "//base", @@ -50,9 +46,7 @@ fuzzer_test("zucchini_disassembler_win32_fuzzer") { # gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_elf_fuzzer \ # components/zucchini/fuzzing/testdata/disassembler_elf_fuzzer/ fuzzer_test("zucchini_disassembler_elf_fuzzer") { - sources = [ - "disassembler_elf_fuzzer.cc", - ] + sources = [ "disassembler_elf_fuzzer.cc" ] deps = [ ":zucchini_fuzz_utils", "//base", @@ -61,9 +55,7 @@ fuzzer_test("zucchini_disassembler_elf_fuzzer") { } fuzzer_test("zucchini_patch_fuzzer") { - sources = [ - "patch_fuzzer.cc", - ] + sources = [ "patch_fuzzer.cc" ] deps = [ "//base", "//components/zucchini:zucchini_lib", @@ -72,9 +64,7 @@ fuzzer_test("zucchini_patch_fuzzer") { } proto_library("zucchini_file_pair_proto") { - sources = [ - "file_pair.proto", - ] + sources = [ "file_pair.proto" ] } # Ensure protoc is available. @@ -108,9 +98,8 @@ if (current_toolchain == host_toolchain && !is_win) { ] # Outputs: necessary for validation. - outputs = [ - "$target_gen_dir/testdata/apply_fuzzer/raw_apply_seed_proto.bin", - ] + outputs = + [ "$target_gen_dir/testdata/apply_fuzzer/raw_apply_seed_proto.bin" ] deps = [ "//components/zucchini:zucchini", "//third_party/protobuf:protoc", @@ -144,9 +133,8 @@ if (current_toolchain == host_toolchain && !is_win) { ] # Outputs: necessary for validation. - outputs = [ - "$target_gen_dir/testdata/apply_fuzzer/ztf_apply_seed_proto.bin", - ] + outputs = + [ "$target_gen_dir/testdata/apply_fuzzer/ztf_apply_seed_proto.bin" ] deps = [ "//components/zucchini:zucchini", "//third_party/protobuf:protoc", @@ -155,9 +143,7 @@ if (current_toolchain == host_toolchain && !is_win) { # Apply Fuzzer: fuzzer_test("zucchini_apply_fuzzer") { - sources = [ - "apply_fuzzer.cc", - ] + sources = [ "apply_fuzzer.cc" ] deps = [ ":zucchini_file_pair_proto", "//base", @@ -180,9 +166,7 @@ if (current_toolchain == host_toolchain && !is_win) { # <new file>: testdata/new.ztf # <out file>: testdata/raw_or_ztf_gen_fuzzer/seed.asciipb fuzzer_test("zucchini_raw_gen_fuzzer") { - sources = [ - "raw_gen_fuzzer.cc", - ] + sources = [ "raw_gen_fuzzer.cc" ] deps = [ ":zucchini_file_pair_proto", "//base", @@ -197,9 +181,7 @@ if (current_toolchain == host_toolchain && !is_win) { # <new file>: testdata/new.ztf # <out file>: testdata/raw_or_ztf_gen_fuzzer/seed.asciipb fuzzer_test("zucchini_ztf_gen_fuzzer") { - sources = [ - "ztf_gen_fuzzer.cc", - ] + sources = [ "ztf_gen_fuzzer.cc" ] deps = [ ":zucchini_file_pair_proto", "//base", @@ -216,9 +198,7 @@ if (current_toolchain == host_toolchain && !is_win) { # <imposed>: 17+420=388+347,452+420=27+347 # This is a mapping of regions old_offset+old_size=new_offset+new_size,... fuzzer_test("zucchini_imposed_ensemble_matcher_fuzzer") { - sources = [ - "imposed_ensemble_matcher_fuzzer.cc", - ] + sources = [ "imposed_ensemble_matcher_fuzzer.cc" ] deps = [ ":zucchini_file_pair_proto", "//base", diff --git a/chromium/components/zucchini/reloc_elf.cc b/chromium/components/zucchini/reloc_elf.cc index eef1c96b1e8..d4857e86c47 100644 --- a/chromium/components/zucchini/reloc_elf.cc +++ b/chromium/components/zucchini/reloc_elf.cc @@ -119,10 +119,14 @@ base::Optional<Reference> RelocReaderElf::GetNext() { } if (target_rva == kInvalidRva) continue; + // TODO(huangs): Make the check more strict: The reference body should not + // straddle section boundary. + offset_t target = target_rva_to_offset_.Convert(target_rva); + if (target == kInvalidOffset) + continue; // |target| will be used to obtain abs32 references, so we must ensure that // it lies inside |image_|. - offset_t target = target_rva_to_offset_.Convert(target_rva); - if (target == kInvalidOffset || !image_.covers({target, sizeof(offset_t)})) + if (!image_.covers({target, WidthOf(bitness_)})) continue; offset_t location = cursor_; cursor_ += cur_entry_size; diff --git a/chromium/components/zucchini/reloc_elf_unittest.cc b/chromium/components/zucchini/reloc_elf_unittest.cc index 5f34ca74e05..acbc1863c9f 100644 --- a/chromium/components/zucchini/reloc_elf_unittest.cc +++ b/chromium/components/zucchini/reloc_elf_unittest.cc @@ -8,11 +8,13 @@ #include <algorithm> #include <memory> +#include <utility> #include <vector> #include "base/numerics/safe_conversions.h" #include "components/zucchini/address_translator.h" #include "components/zucchini/algorithm.h" +#include "components/zucchini/disassembler_elf.h" #include "components/zucchini/image_utils.h" #include "components/zucchini/test_utils.h" #include "components/zucchini/type_elf.h" @@ -45,79 +47,194 @@ SectionDimensionsElf MakeSectionDimensions(const BufferRegion& region, }}; } +// Helper to manipulate an image with one or more relocation tables. +template <class ElfIntelTraits> +class FakeImageWithReloc { + public: + struct RelocSpec { + offset_t start; + std::vector<uint8_t> data; + }; + + FakeImageWithReloc(size_t image_size, + rva_t base_rva, + const std::vector<RelocSpec>& reloc_specs) + : image_data_(image_size, 0xFF), + mutable_image_(&image_data_[0], image_data_.size()) { + translator_.Initialize({{0, image_size, base_rva, image_size}}); + // Set up test image with reloc sections. + for (const RelocSpec& reloc_spec : reloc_specs) { + BufferRegion reloc_region = {reloc_spec.start, reloc_spec.data.size()}; + std::copy(reloc_spec.data.begin(), reloc_spec.data.end(), + image_data_.begin() + reloc_region.lo()); + section_dimensions_.emplace_back( + MakeSectionDimensions<typename ElfIntelTraits::Elf_Shdr>( + reloc_region, ElfIntelTraits::kVAWidth)); + reloc_regions_.push_back(reloc_region); + } + } + + std::vector<Reference> ExtractRelocReferences() { + const size_t image_size = image_data_.size(); + ConstBufferView image = {image_data_.data(), image_size}; + + // Make RelocReaderElf. + auto reader = std::make_unique<RelocReaderElf>( + image, ElfIntelTraits::kBitness, section_dimensions_, + ElfIntelTraits::kRelType, 0, image_size, translator_); + + // Read all references and check. + std::vector<Reference> refs; + for (base::Optional<Reference> ref = reader->GetNext(); ref.has_value(); + ref = reader->GetNext()) { + refs.push_back(ref.value()); + } + return refs; + } + + std::unique_ptr<RelocWriterElf> MakeRelocWriter() { + return std::move(std::make_unique<RelocWriterElf>( + mutable_image_, ElfIntelTraits::kBitness, translator_)); + } + + std::vector<uint8_t> GetRawRelocData(int reloc_index) { + BufferRegion reloc_region = reloc_regions_[reloc_index]; + return Sub(image_data_, reloc_region.lo(), reloc_region.hi()); + } + + private: + std::vector<uint8_t> image_data_; + MutableBufferView mutable_image_; + std::vector<BufferRegion> reloc_regions_; + std::vector<SectionDimensionsElf> section_dimensions_; + AddressTranslator translator_; +}; + } // namespace TEST(RelocElfTest, ReadWrite32) { // Set up mock image: Size = 0x3000, .reloc at 0x600. RVA is 0x40000 + offset. + constexpr size_t kImageSize = 0x3000; constexpr rva_t kBaseRva = 0x40000; - std::vector<uint8_t> image_data(0x3000, 0xFF); + + constexpr offset_t kRelocStart0 = 0x600; // "C0 10 04 00 08 00 00 00" represents // (r_sym, r_type, r_offset) = (0x000000, 0x08, 0x000410C0). - // r_type = 0x08 = R_386_RELATIVE, and under this r_offset is an RVA - // 0x000410C0. Zucchini does not care about r_sym. - std::vector<uint8_t> reloc_data1 = ParseHexString( + // r_type = 0x08 = R_386_RELATIVE, and so |r_offset| is an RVA 0x000410C0. + // Zucchini does not care about |r_sym|. + std::vector<uint8_t> reloc_data0 = ParseHexString( "C0 10 04 00 08 00 00 00 " // R_386_RELATIVE. "F8 10 04 00 08 AB CD EF " // R_386_RELATIVE. "00 10 04 00 00 AB CD EF " // R_386_NONE. "00 10 04 00 07 AB CD EF"); // R_386_JMP_SLOT. - BufferRegion reloc_region1 = {0x600, reloc_data1.size()}; - std::copy(reloc_data1.begin(), reloc_data1.end(), - image_data.begin() + reloc_region1.lo()); - std::vector<uint8_t> reloc_data2 = ParseHexString( + constexpr offset_t kRelocStart1 = 0x620; + std::vector<uint8_t> reloc_data1 = ParseHexString( "BC 20 04 00 08 00 00 00 " // R_386_RELATIVE. "A0 20 04 00 08 AB CD EF"); // R_386_RELATIVE. - BufferRegion reloc_region2 = {0x620, reloc_data2.size()}; - std::copy(reloc_data2.begin(), reloc_data2.end(), - image_data.begin() + reloc_region2.lo()); - - ConstBufferView image = {image_data.data(), image_data.size()}; - offset_t image_size = base::checked_cast<offset_t>(image_data.size()); - - AddressTranslator translator; - translator.Initialize({{0, image_size, kBaseRva, image_size}}); - - std::vector<SectionDimensionsElf> section_dimensions{ - MakeSectionDimensions<elf::Elf32_Shdr>(reloc_region1, 8), - MakeSectionDimensions<elf::Elf32_Shdr>(reloc_region2, 8)}; - - // Make RelocReaderElf. - auto reader = std::make_unique<RelocReaderElf>( - image, kBit32, section_dimensions, elf::R_386_RELATIVE, 0, image_size, - translator); - - // Read all references and check. - std::vector<Reference> refs; - for (base::Optional<Reference> ref = reader->GetNext(); ref.has_value(); - ref = reader->GetNext()) { - refs.push_back(ref.value()); - } + + FakeImageWithReloc<Elf32IntelTraits> fake_image( + kImageSize, kBaseRva, + {{kRelocStart0, reloc_data0}, {kRelocStart1, reloc_data1}}); + // Only R_386_RELATIVE references are extracted. Targets are translated from // address (e.g., 0x000420BC) to offset (e.g., 0x20BC). std::vector<Reference> exp_refs{ {0x600, 0x10C0}, {0x608, 0x10F8}, {0x620, 0x20BC}, {0x628, 0x20A0}}; - EXPECT_EQ(exp_refs, refs); + EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences()); // Write reference, extract bytes and check. - MutableBufferView mutable_image(&image_data[0], image_data.size()); - auto writer = - std::make_unique<RelocWriterElf>(mutable_image, kBit32, translator); + std::unique_ptr<RelocWriterElf> writer = fake_image.MakeRelocWriter(); writer->PutNext({0x608, 0x1F83}); - std::vector<uint8_t> exp_reloc_data1 = ParseHexString( + std::vector<uint8_t> exp_reloc_data0 = ParseHexString( "C0 10 04 00 08 00 00 00 " // R_386_RELATIVE. "83 1F 04 00 08 AB CD EF " // R_386_RELATIVE (address modified). "00 10 04 00 00 AB CD EF " // R_386_NONE. "00 10 04 00 07 AB CD EF"); // R_386_JMP_SLOT. - EXPECT_EQ(exp_reloc_data1, - Sub(image_data, reloc_region1.lo(), reloc_region1.hi())); + EXPECT_EQ(exp_reloc_data0, fake_image.GetRawRelocData(0)); writer->PutNext({0x628, 0x2950}); - std::vector<uint8_t> exp_reloc_data2 = ParseHexString( + std::vector<uint8_t> exp_reloc_data1 = ParseHexString( "BC 20 04 00 08 00 00 00 " // R_386_RELATIVE. "50 29 04 00 08 AB CD EF"); // R_386_RELATIVE (address modified). - EXPECT_EQ(exp_reloc_data2, - Sub(image_data, reloc_region2.lo(), reloc_region2.hi())); + EXPECT_EQ(exp_reloc_data1, fake_image.GetRawRelocData(1)); +} + +TEST(RelocElfTest, Limit32) { + constexpr size_t kImageSize = 0x3000; + constexpr offset_t kBaseRva = 0x40000; + constexpr offset_t kRelocStart = 0x600; + // All R_386_RELATIVE. + std::vector<uint8_t> reloc_data = ParseHexString( + // Strictly within file. + "00 00 04 00 08 00 00 00 " + "00 10 04 00 08 00 00 00 " + "F0 2F 04 00 08 00 00 00 " + "F8 2F 04 00 08 00 00 00 " + "FC 2F 04 00 08 00 00 00 " + // Straddles end of file. + "FD 2F 04 00 08 00 00 00 " + "FE 2F 04 00 08 00 00 00 " + "FF 2F 04 00 08 00 00 00 " + // Beyond end of file. + "00 30 04 00 08 00 00 00 " + "01 30 04 00 08 00 00 00 " + "FC FF FF 7F 08 00 00 00 " + "FE FF FF 7F 08 00 00 00 " + "00 00 00 80 08 00 00 00 " + "FC FF FF FF 08 00 00 00 " + "FF FF FF FF 08 00 00 00 " + // Another good reference. + "34 12 04 00 08 00 00 00"); + + FakeImageWithReloc<Elf32IntelTraits> fake_image(kImageSize, kBaseRva, + {{kRelocStart, reloc_data}}); + + std::vector<Reference> exp_refs{{0x600, 0x0000}, {0x608, 0x1000}, + {0x610, 0x2FF0}, {0x618, 0x2FF8}, + {0x620, 0x2FFC}, {0x678, 0x1234}}; + EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences()); +} + +TEST(RelocElfTest, Limit64) { + constexpr size_t kImageSize = 0x3000; + constexpr offset_t kBaseRva = 0x40000; + + constexpr offset_t kRelocStart = 0x600; + // All R_X86_64_RELATIVE. + std::vector<uint8_t> reloc_data = ParseHexString( + // Strictly within file. + "00 00 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + "00 10 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + "F0 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + "F4 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + "F8 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + // Straddles end of file. + "F9 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + "FC 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + "FF 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + // Beyond end of file. + "00 30 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + "01 30 04 00 00 00 00 00 08 00 00 00 00 00 00 00 " + "FC FF FF 7F 00 00 00 00 08 00 00 00 00 00 00 00 " + "FE FF FF 7F 00 00 00 00 08 00 00 00 00 00 00 00 " + "00 00 00 80 00 00 00 00 08 00 00 00 00 00 00 00 " + "FC FF FF FF 00 00 00 00 08 00 00 00 00 00 00 00 " + "FF FF FF FF 00 00 00 00 08 00 00 00 00 00 00 00 " + "00 00 04 00 01 00 00 00 08 00 00 00 00 00 00 00 " + "FF FF FF FF FF FF FF FF 08 00 00 00 00 00 00 00 " + "F8 FF FF FF FF FF FF FF 08 00 00 00 00 00 00 00 " + // Another good reference. + "34 12 04 00 00 00 00 00 08 00 00 00 00 00 00 00"); + + FakeImageWithReloc<Elf64IntelTraits> fake_image(kImageSize, kBaseRva, + {{kRelocStart, reloc_data}}); + + std::vector<Reference> exp_refs{{0x600, 0x0000}, {0x610, 0x1000}, + {0x620, 0x2FF0}, {0x630, 0x2FF4}, + {0x640, 0x2FF8}, {0x720, 0x1234}}; + EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences()); } } // namespace zucchini |