1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/zucchini/disassembler_elf.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "base/logging.h"
13 #include "base/numerics/checked_math.h"
14 #include "base/numerics/safe_conversions.h"
15 #include "components/zucchini/abs32_utils.h"
16 #include "components/zucchini/algorithm.h"
17 #include "components/zucchini/buffer_source.h"
18 
19 namespace zucchini {
20 
21 namespace {
22 
23 constexpr uint64_t kElfImageBase = 0;
24 constexpr size_t kSizeBound = 0x7FFF0000;
25 
26 // Bit fields for JudgeSection() return value.
27 enum SectionJudgement : int {
28   // Bit: Section does not invalidate ELF, but may or may not be useful.
29   SECTION_BIT_SAFE = 1 << 0,
30   // Bit: Section useful for AddressTranslator, to map between offsets and RVAs.
31   SECTION_BIT_USEFUL_FOR_ADDRESS_TRANSLATOR = 1 << 1,
32   // Bit: Section useful for |offset_bound|, to estimate ELF size.
33   SECTION_BIT_USEFUL_FOR_OFFSET_BOUND = 1 << 2,
34   // Bit: Section potentially useful for pointer extraction.
35   SECTION_BIT_MAYBE_USEFUL_FOR_POINTERS = 1 << 3,
36 
37   // The following are verdicts from combining bits, to improve semantics.
38   // Default value: A section is malformed and invalidates ELF.
39   SECTION_IS_MALFORMED = 0,
40   // Section does not invalidate ELF, but is also not used for anything.
41   SECTION_IS_USELESS = SECTION_BIT_SAFE,
42 };
43 
44 // Decides how a section affects ELF parsing, and returns a bit field composed
45 // from SectionJudgement values.
46 template <class Traits>
JudgeSection(size_t image_size,const typename Traits::Elf_Shdr * section)47 int JudgeSection(size_t image_size, const typename Traits::Elf_Shdr* section) {
48   // BufferRegion uses |size_t| this can be 32-bit in some cases. For Elf64
49   // |sh_addr|, |sh_offset| and |sh_size| are 64-bit this can result in
50   // overflows in the subsequent validation steps.
51   if (!base::IsValueInRangeForNumericType<size_t>(section->sh_addr) ||
52       !base::IsValueInRangeForNumericType<size_t>(section->sh_offset) ||
53       !base::IsValueInRangeForNumericType<size_t>(section->sh_size)) {
54     return SECTION_IS_MALFORMED;
55   }
56 
57   // Examine RVA range: Reject if numerical overflow may happen.
58   if (!BufferRegion{section->sh_addr, section->sh_size}.FitsIn(kSizeBound))
59     return SECTION_IS_MALFORMED;
60 
61   // Examine offset range: If section takes up |image| data then be stricter.
62   size_t offset_bound =
63       (section->sh_type == elf::SHT_NOBITS) ? kSizeBound : image_size;
64   if (!BufferRegion{section->sh_offset, section->sh_size}.FitsIn(offset_bound))
65     return SECTION_IS_MALFORMED;
66 
67   // Empty sections don't contribute to offset-RVA mapping. For consistency, it
68   // should also not affect |offset_bounds|.
69   if (section->sh_size == 0)
70     return SECTION_IS_USELESS;
71 
72   // Sections with |sh_addr == 0| are ignored because these tend to duplicates
73   // (can cause problems for lookup) and uninteresting. For consistency, it
74   // should also not affect |offset_bounds|.
75   if (section->sh_addr == 0)
76     return SECTION_IS_USELESS;
77 
78   if (section->sh_type == elf::SHT_NOBITS) {
79     // Special case for .tbss sections: These should be ignored because they may
80     // have offset-RVA map that don't match other sections.
81     if (section->sh_flags & elf::SHF_TLS)
82       return SECTION_IS_USELESS;
83 
84     // Section is useful for offset-RVA translation, but does not affect
85     // |offset_bounds| since it can have large virtual size (e.g., .bss).
86     return SECTION_BIT_SAFE | SECTION_BIT_USEFUL_FOR_ADDRESS_TRANSLATOR;
87   }
88 
89   return SECTION_BIT_SAFE | SECTION_BIT_USEFUL_FOR_ADDRESS_TRANSLATOR |
90          SECTION_BIT_USEFUL_FOR_OFFSET_BOUND |
91          SECTION_BIT_MAYBE_USEFUL_FOR_POINTERS;
92 }
93 
94 // Determines whether |section| is a reloc section.
95 template <class Traits>
IsRelocSection(const typename Traits::Elf_Shdr & section)96 bool IsRelocSection(const typename Traits::Elf_Shdr& section) {
97   DCHECK_GT(section.sh_size, 0U);
98   if (section.sh_type == elf::SHT_REL) {
99     // Also validate |section.sh_entsize|, which gets used later.
100     return section.sh_entsize == sizeof(typename Traits::Elf_Rel);
101   }
102   if (section.sh_type == elf::SHT_RELA)
103     return section.sh_entsize == sizeof(typename Traits::Elf_Rela);
104   return false;
105 }
106 
107 // Determines whether |section| is a section with executable code.
108 template <class Traits>
IsExecSection(const typename Traits::Elf_Shdr & section)109 bool IsExecSection(const typename Traits::Elf_Shdr& section) {
110   DCHECK_GT(section.sh_size, 0U);
111   return section.sh_type == elf::SHT_PROGBITS &&
112          (section.sh_flags & elf::SHF_EXECINSTR) != 0;
113 }
114 
115 }  // namespace
116 
117 /******** Elf32Traits ********/
118 
119 // static
120 constexpr Bitness Elf32Traits::kBitness;
121 constexpr elf::FileClass Elf32Traits::kIdentificationClass;
122 
123 /******** Elf32IntelTraits ********/
124 
125 // static
126 constexpr ExecutableType Elf32IntelTraits::kExeType;
127 const char Elf32IntelTraits::kExeTypeString[] = "ELF x86";
128 constexpr elf::MachineArchitecture Elf32IntelTraits::kMachineValue;
129 constexpr uint32_t Elf32IntelTraits::kRelType;
130 
131 /******** Elf64Traits ********/
132 
133 // static
134 constexpr Bitness Elf64Traits::kBitness;
135 constexpr elf::FileClass Elf64Traits::kIdentificationClass;
136 
137 /******** Elf64IntelTraits ********/
138 
139 // static
140 constexpr ExecutableType Elf64IntelTraits::kExeType;
141 const char Elf64IntelTraits::kExeTypeString[] = "ELF x64";
142 constexpr elf::MachineArchitecture Elf64IntelTraits::kMachineValue;
143 constexpr uint32_t Elf64IntelTraits::kRelType;
144 
145 /******** DisassemblerElf ********/
146 
147 // static.
148 template <class Traits>
QuickDetect(ConstBufferView image)149 bool DisassemblerElf<Traits>::QuickDetect(ConstBufferView image) {
150   BufferSource source(image);
151 
152   // Do not consume the bytes for the magic value, as they are part of the
153   // header.
154   if (!source.CheckNextBytes({0x7F, 'E', 'L', 'F'}))
155     return false;
156 
157   auto* header = source.GetPointer<typename Traits::Elf_Ehdr>();
158   if (!header)
159     return false;
160 
161   if (header->e_ident[elf::EI_CLASS] != Traits::kIdentificationClass)
162     return false;
163 
164   if (header->e_ident[elf::EI_DATA] != 1)  // Only ELFDATA2LSB is supported.
165     return false;
166 
167   if (header->e_type != elf::ET_EXEC && header->e_type != elf::ET_DYN)
168     return false;
169 
170   if (header->e_version != 1 || header->e_ident[elf::EI_VERSION] != 1)
171     return false;
172 
173   if (header->e_machine != supported_architecture())
174     return false;
175 
176   if (header->e_shentsize != sizeof(typename Traits::Elf_Shdr))
177     return false;
178 
179   return true;
180 }
181 
182 template <class Traits>
183 DisassemblerElf<Traits>::~DisassemblerElf() = default;
184 
185 template <class Traits>
GetExeType() const186 ExecutableType DisassemblerElf<Traits>::GetExeType() const {
187   return Traits::kExeType;
188 }
189 
190 template <class Traits>
GetExeTypeString() const191 std::string DisassemblerElf<Traits>::GetExeTypeString() const {
192   return Traits::kExeTypeString;
193 }
194 
195 // |num_equivalence_iterations_| = 2 for reloc -> abs32.
196 template <class Traits>
DisassemblerElf()197 DisassemblerElf<Traits>::DisassemblerElf() : Disassembler(2) {}
198 
199 template <class Traits>
Parse(ConstBufferView image)200 bool DisassemblerElf<Traits>::Parse(ConstBufferView image) {
201   image_ = image;
202   if (!ParseHeader())
203     return false;
204   ParseSections();
205   return true;
206 }
207 
208 template <class Traits>
MakeReadRelocs(offset_t lo,offset_t hi)209 std::unique_ptr<ReferenceReader> DisassemblerElf<Traits>::MakeReadRelocs(
210     offset_t lo,
211     offset_t hi) {
212   DCHECK_LE(lo, hi);
213   DCHECK_LE(hi, image_.size());
214 
215   if (reloc_section_dims_.empty())
216     return std::make_unique<EmptyReferenceReader>();
217 
218   return std::make_unique<RelocReaderElf>(
219       image_, Traits::kBitness, reloc_section_dims_,
220       supported_relocation_type(), lo, hi, translator_);
221 }
222 
223 template <class Traits>
MakeWriteRelocs(MutableBufferView image)224 std::unique_ptr<ReferenceWriter> DisassemblerElf<Traits>::MakeWriteRelocs(
225     MutableBufferView image) {
226   return std::make_unique<RelocWriterElf>(image, Traits::kBitness, translator_);
227 }
228 
229 template <class Traits>
ParseHeader()230 bool DisassemblerElf<Traits>::ParseHeader() {
231   BufferSource source(image_);
232   // Ensure any offsets will fit within the |image_|'s bounds.
233   if (!base::IsValueInRangeForNumericType<offset_t>(image_.size()))
234     return false;
235 
236   // Ensures |header_| is valid later on.
237   if (!QuickDetect(image_))
238     return false;
239 
240   header_ = source.GetPointer<typename Traits::Elf_Ehdr>();
241 
242   sections_count_ = header_->e_shnum;
243   source = std::move(BufferSource(image_).Skip(header_->e_shoff));
244   sections_ = source.GetArray<typename Traits::Elf_Shdr>(sections_count_);
245   if (!sections_)
246     return false;
247   offset_t section_table_end =
248       base::checked_cast<offset_t>(source.begin() - image_.begin());
249 
250   segments_count_ = header_->e_phnum;
251   source = std::move(BufferSource(image_).Skip(header_->e_phoff));
252   segments_ = source.GetArray<typename Traits::Elf_Phdr>(segments_count_);
253   if (!segments_)
254     return false;
255   offset_t segment_table_end =
256       base::checked_cast<offset_t>(source.begin() - image_.begin());
257 
258   // Check string section -- even though we've stopped using them.
259   elf::Elf32_Half string_section_id = header_->e_shstrndx;
260   if (string_section_id >= sections_count_)
261     return false;
262   size_t section_names_size = sections_[string_section_id].sh_size;
263   if (section_names_size > 0) {
264     // If nonempty, then last byte of string section must be null.
265     const char* section_names = nullptr;
266     source = std::move(
267         BufferSource(image_).Skip(sections_[string_section_id].sh_offset));
268     section_names = source.GetArray<char>(section_names_size);
269     if (!section_names || section_names[section_names_size - 1] != '\0')
270       return false;
271   }
272 
273   // Establish bound on encountered offsets.
274   offset_t offset_bound = std::max(section_table_end, segment_table_end);
275 
276   // Visits |segments_| to get estimate on |offset_bound|.
277   for (const typename Traits::Elf_Phdr* segment = segments_;
278        segment != segments_ + segments_count_; ++segment) {
279     // |image_.covers()| is a sufficient check except when size_t is 32 bit and
280     // parsing ELF64. In such cases a value-in-range check is needed on the
281     // segment. This fixes crbug/1035603.
282     offset_t segment_end;
283     base::CheckedNumeric<offset_t> checked_segment_end = segment->p_offset;
284     checked_segment_end += segment->p_filesz;
285     if (!checked_segment_end.AssignIfValid(&segment_end) ||
286         !image_.covers({segment->p_offset, segment->p_filesz})) {
287       return false;
288     }
289     offset_bound = std::max(offset_bound, segment_end);
290   }
291 
292   // Visit and validate each section; add address translation data to |units|.
293   std::vector<AddressTranslator::Unit> units;
294   units.reserve(sections_count_);
295   section_judgements_.reserve(sections_count_);
296 
297   for (int i = 0; i < sections_count_; ++i) {
298     const typename Traits::Elf_Shdr* section = &sections_[i];
299     int judgement = JudgeSection<Traits>(image_.size(), section);
300     section_judgements_.push_back(judgement);
301     if ((judgement & SECTION_BIT_SAFE) == 0)
302       return false;
303 
304     uint32_t sh_size = base::checked_cast<uint32_t>(section->sh_size);
305     offset_t sh_offset = base::checked_cast<offset_t>(section->sh_offset);
306     rva_t sh_addr = base::checked_cast<rva_t>(section->sh_addr);
307     if ((judgement & SECTION_BIT_USEFUL_FOR_ADDRESS_TRANSLATOR) != 0) {
308       // Store mappings between RVA and offset.
309       units.push_back({sh_offset, sh_size, sh_addr, sh_size});
310     }
311     if ((judgement & SECTION_BIT_USEFUL_FOR_OFFSET_BOUND) != 0) {
312       offset_t section_end = base::checked_cast<offset_t>(sh_offset + sh_size);
313       offset_bound = std::max(offset_bound, section_end);
314     }
315   }
316 
317   // Initialize |translator_| for offset-RVA translations. Any inconsistency
318   // (e.g., 2 offsets correspond to the same RVA) would invalidate the ELF file.
319   if (translator_.Initialize(std::move(units)) != AddressTranslator::kSuccess)
320     return false;
321 
322   DCHECK_LE(offset_bound, image_.size());
323   image_.shrink(offset_bound);
324   return true;
325 }
326 
327 template <class Traits>
ExtractInterestingSectionHeaders()328 void DisassemblerElf<Traits>::ExtractInterestingSectionHeaders() {
329   DCHECK(reloc_section_dims_.empty());
330   DCHECK(exec_headers_.empty());
331   for (elf::Elf32_Half i = 0; i < sections_count_; ++i) {
332     const typename Traits::Elf_Shdr* section = sections_ + i;
333     if ((section_judgements_[i] & SECTION_BIT_MAYBE_USEFUL_FOR_POINTERS) != 0) {
334       if (IsRelocSection<Traits>(*section))
335         reloc_section_dims_.emplace_back(*section);
336       else if (IsExecSection<Traits>(*section))
337         exec_headers_.push_back(section);
338     }
339   }
340   auto comp = [](const typename Traits::Elf_Shdr* a,
341                  const typename Traits::Elf_Shdr* b) {
342     return a->sh_offset < b->sh_offset;
343   };
344   std::sort(reloc_section_dims_.begin(), reloc_section_dims_.end());
345   std::sort(exec_headers_.begin(), exec_headers_.end(), comp);
346 }
347 
348 template <class Traits>
GetAbs32FromRelocSections()349 void DisassemblerElf<Traits>::GetAbs32FromRelocSections() {
350   constexpr int kAbs32Width = Traits::kVAWidth;
351   DCHECK(abs32_locations_.empty());
352 
353   // Read reloc targets to get preliminary abs32 locations.
354   std::unique_ptr<ReferenceReader> relocs = MakeReadRelocs(0, offset_t(size()));
355   for (auto ref = relocs->GetNext(); ref.has_value(); ref = relocs->GetNext())
356     abs32_locations_.push_back(ref->target);
357 
358   std::sort(abs32_locations_.begin(), abs32_locations_.end());
359 
360   // Abs32 references must have targets translatable to offsets. Remove those
361   // that are unable to do so.
362   size_t num_untranslatable =
363       RemoveUntranslatableAbs32(image_, {Traits::kBitness, kElfImageBase},
364                                 translator_, &abs32_locations_);
365   LOG_IF(WARNING, num_untranslatable) << "Removed " << num_untranslatable
366                                       << " untranslatable abs32 references.";
367 
368   // Abs32 reference bodies must not overlap. If found, simply remove them.
369   size_t num_overlapping =
370       RemoveOverlappingAbs32Locations(kAbs32Width, &abs32_locations_);
371   LOG_IF(WARNING, num_overlapping)
372       << "Removed " << num_overlapping
373       << " abs32 references with overlapping bodies.";
374 
375   abs32_locations_.shrink_to_fit();
376 }
377 
378 template <class Traits>
GetRel32FromCodeSections()379 void DisassemblerElf<Traits>::GetRel32FromCodeSections() {
380   for (const typename Traits::Elf_Shdr* section : exec_headers_)
381     ParseExecSection(*section);
382   PostProcessRel32();
383 }
384 
385 template <class Traits>
ParseSections()386 void DisassemblerElf<Traits>::ParseSections() {
387   ExtractInterestingSectionHeaders();
388   GetAbs32FromRelocSections();
389   GetRel32FromCodeSections();
390 }
391 
392 /******** DisassemblerElfIntel ********/
393 
394 template <class Traits>
395 DisassemblerElfIntel<Traits>::DisassemblerElfIntel() = default;
396 
397 template <class Traits>
398 DisassemblerElfIntel<Traits>::~DisassemblerElfIntel() = default;
399 
400 template <class Traits>
MakeReferenceGroups() const401 std::vector<ReferenceGroup> DisassemblerElfIntel<Traits>::MakeReferenceGroups()
402     const {
403   return {
404       {ReferenceTypeTraits{sizeof(Traits::Elf_Rel::r_offset), TypeTag(kReloc),
405                            PoolTag(kReloc)},
406        &DisassemblerElfIntel<Traits>::MakeReadRelocs,
407        &DisassemblerElfIntel<Traits>::MakeWriteRelocs},
408       {ReferenceTypeTraits{Traits::kVAWidth, TypeTag(kAbs32), PoolTag(kAbs32)},
409        &DisassemblerElfIntel<Traits>::MakeReadAbs32,
410        &DisassemblerElfIntel<Traits>::MakeWriteAbs32},
411       // N.B.: Rel32 |width| is 4 bytes, even for x64.
412       {ReferenceTypeTraits{4, TypeTag(kRel32), PoolTag(kRel32)},
413        &DisassemblerElfIntel<Traits>::MakeReadRel32,
414        &DisassemblerElfIntel<Traits>::MakeWriteRel32}};
415 }
416 
417 template <class Traits>
ParseExecSection(const typename Traits::Elf_Shdr & section)418 void DisassemblerElfIntel<Traits>::ParseExecSection(
419     const typename Traits::Elf_Shdr& section) {
420   ConstBufferView& image_ = this->image_;
421   auto& abs32_locations_ = this->abs32_locations_;
422 
423   std::ptrdiff_t from_offset_to_rva = section.sh_addr - section.sh_offset;
424 
425   // Range of values was ensured in ParseHeader().
426   rva_t start_rva = base::checked_cast<rva_t>(section.sh_addr);
427   rva_t end_rva = base::checked_cast<rva_t>(start_rva + section.sh_size);
428 
429   AddressTranslator::RvaToOffsetCache target_rva_checker(this->translator_);
430 
431   ConstBufferView region(image_.begin() + section.sh_offset, section.sh_size);
432   Abs32GapFinder gap_finder(image_, region, abs32_locations_, 4);
433   typename Traits::Rel32FinderUse finder;
434   for (auto gap = gap_finder.GetNext(); gap.has_value();
435        gap = gap_finder.GetNext()) {
436     finder.SetRegion(gap.value());
437     for (auto rel32 = finder.GetNext(); rel32.has_value();
438          rel32 = finder.GetNext()) {
439       offset_t rel32_offset =
440           base::checked_cast<offset_t>(rel32->location - image_.begin());
441       rva_t rel32_rva = rva_t(rel32_offset + from_offset_to_rva);
442       DCHECK_NE(rel32_rva, kInvalidRva);
443       rva_t target_rva = rel32_rva + 4 + image_.read<uint32_t>(rel32_offset);
444       if (target_rva_checker.IsValid(target_rva) &&
445           (rel32->can_point_outside_section ||
446            (start_rva <= target_rva && target_rva < end_rva))) {
447         finder.Accept();
448         rel32_locations_.push_back(rel32_offset);
449       }
450     }
451   }
452 }
453 
454 template <class Traits>
PostProcessRel32()455 void DisassemblerElfIntel<Traits>::PostProcessRel32() {
456   rel32_locations_.shrink_to_fit();
457   std::sort(rel32_locations_.begin(), rel32_locations_.end());
458 }
459 
460 template <class Traits>
MakeReadAbs32(offset_t lo,offset_t hi)461 std::unique_ptr<ReferenceReader> DisassemblerElfIntel<Traits>::MakeReadAbs32(
462     offset_t lo,
463     offset_t hi) {
464   // TODO(huangs): Don't use Abs32RvaExtractorWin32 here; use new class that
465   // caters to different ELF architectures.
466   Abs32RvaExtractorWin32 abs_rva_extractor(
467       this->image_, AbsoluteAddress(Traits::kBitness, kElfImageBase),
468       this->abs32_locations_, lo, hi);
469   return std::make_unique<Abs32ReaderWin32>(std::move(abs_rva_extractor),
470                                             this->translator_);
471 }
472 
473 template <class Traits>
MakeWriteAbs32(MutableBufferView image)474 std::unique_ptr<ReferenceWriter> DisassemblerElfIntel<Traits>::MakeWriteAbs32(
475     MutableBufferView image) {
476   return std::make_unique<Abs32WriterWin32>(
477       image, AbsoluteAddress(Traits::kBitness, kElfImageBase),
478       this->translator_);
479 }
480 
481 template <class Traits>
MakeReadRel32(offset_t lo,offset_t hi)482 std::unique_ptr<ReferenceReader> DisassemblerElfIntel<Traits>::MakeReadRel32(
483     offset_t lo,
484     offset_t hi) {
485   return std::make_unique<Rel32ReaderX86>(this->image_, lo, hi,
486                                           &rel32_locations_, this->translator_);
487 }
488 
489 template <class Traits>
MakeWriteRel32(MutableBufferView image)490 std::unique_ptr<ReferenceWriter> DisassemblerElfIntel<Traits>::MakeWriteRel32(
491     MutableBufferView image) {
492   return std::make_unique<Rel32WriterX86>(image, this->translator_);
493 }
494 
495 // Explicit instantiation for supported classes.
496 template class DisassemblerElfIntel<Elf32IntelTraits>;
497 template class DisassemblerElfIntel<Elf64IntelTraits>;
498 template bool DisassemblerElf<Elf32IntelTraits>::QuickDetect(
499     ConstBufferView image);
500 template bool DisassemblerElf<Elf64IntelTraits>::QuickDetect(
501     ConstBufferView image);
502 
503 }  // namespace zucchini
504