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 #ifndef COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_
6 #define COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_
7 
8 #include <stdint.h>
9 
10 #include <algorithm>
11 #include <deque>
12 #include <memory>
13 #include <string>
14 #include <vector>
15 
16 #include "components/zucchini/address_translator.h"
17 #include "components/zucchini/buffer_view.h"
18 #include "components/zucchini/disassembler.h"
19 #include "components/zucchini/image_utils.h"
20 #include "components/zucchini/rel32_finder.h"
21 #include "components/zucchini/rel32_utils.h"
22 #include "components/zucchini/reloc_elf.h"
23 #include "components/zucchini/type_elf.h"
24 
25 namespace zucchini {
26 
27 struct ArmReferencePool {
28   enum : uint8_t {
29     kPoolReloc,
30     kPoolAbs32,
31     kPoolRel32,
32   };
33 };
34 
35 struct AArch32ReferenceType {
36   enum : uint8_t {
37     kReloc,  // kPoolReloc
38 
39     kAbs32,  // kPoolAbs32
40 
41     kRel32_A24,  // kPoolRel32
42     kRel32_T8,
43     kRel32_T11,
44     kRel32_T20,
45     kRel32_T24,
46 
47     kTypeCount
48   };
49 };
50 
51 struct AArch64ReferenceType {
52   enum : uint8_t {
53     kReloc,  // kPoolReloc
54 
55     kAbs32,  // kPoolAbs32
56 
57     kRel32_Immd14,  // kPoolRel32
58     kRel32_Immd19,
59     kRel32_Immd26,
60 
61     kTypeCount
62   };
63 };
64 
65 struct Elf32Traits {
66   static constexpr uint16_t kVersion = 1;
67   static constexpr Bitness kBitness = kBit32;
68   static constexpr elf::FileClass kIdentificationClass = elf::ELFCLASS32;
69   using Elf_Shdr = elf::Elf32_Shdr;
70   using Elf_Phdr = elf::Elf32_Phdr;
71   using Elf_Ehdr = elf::Elf32_Ehdr;
72   using Elf_Rel = elf::Elf32_Rel;
73   using Elf_Rela = elf::Elf32_Rela;
74 };
75 
76 // Architecture-specific definitions.
77 
78 struct Elf32IntelTraits : public Elf32Traits {
79   static constexpr ExecutableType kExeType = kExeTypeElfX86;
80   static const char kExeTypeString[];
81   static constexpr elf::MachineArchitecture kMachineValue = elf::EM_386;
82   static constexpr uint32_t kRelType = elf::R_386_RELATIVE;
83   enum : uint32_t { kVAWidth = 4 };
84   using Rel32FinderUse = Rel32FinderX86;
85 };
86 
87 struct ElfAArch32Traits : public Elf32Traits {
88   static constexpr ExecutableType kExeType = kExeTypeElfAArch32;
89   static const char kExeTypeString[];
90   static constexpr elf::MachineArchitecture kMachineValue = elf::EM_ARM;
91   static constexpr uint32_t kRelType = elf::R_ARM_RELATIVE;
92   enum : uint32_t { kVAWidth = 4 };
93   using ArmReferenceType = AArch32ReferenceType;
94   using Rel32FinderUse = Rel32FinderAArch32;
95 };
96 
97 struct Elf64Traits {
98   static constexpr uint16_t kVersion = 1;
99   static constexpr Bitness kBitness = kBit64;
100   static constexpr elf::FileClass kIdentificationClass = elf::ELFCLASS64;
101   using Elf_Shdr = elf::Elf64_Shdr;
102   using Elf_Phdr = elf::Elf64_Phdr;
103   using Elf_Ehdr = elf::Elf64_Ehdr;
104   using Elf_Rel = elf::Elf64_Rel;
105   using Elf_Rela = elf::Elf64_Rela;
106 };
107 
108 // Architecture-specific definitions.
109 struct Elf64IntelTraits : public Elf64Traits {
110   static constexpr ExecutableType kExeType = kExeTypeElfX64;
111   static const char kExeTypeString[];
112   static constexpr elf::MachineArchitecture kMachineValue = elf::EM_X86_64;
113   static constexpr uint32_t kRelType = elf::R_X86_64_RELATIVE;
114   enum : uint32_t { kVAWidth = 8 };
115   using Rel32FinderUse = Rel32FinderX64;
116 };
117 
118 struct ElfAArch64Traits : public Elf64Traits {
119   static constexpr ExecutableType kExeType = kExeTypeElfAArch64;
120   static const char kExeTypeString[];
121   static constexpr elf::MachineArchitecture kMachineValue = elf::EM_AARCH64;
122   // TODO(huangs): See if R_AARCH64_GLOB_DAT and R_AARCH64_JUMP_SLOT should be
123   // used.
124   static constexpr uint32_t kRelType = elf::R_AARCH64_RELATIVE;
125   enum : uint32_t { kVAWidth = 8 };
126   using ArmReferenceType = AArch64ReferenceType;
127   using Rel32FinderUse = Rel32FinderAArch64;
128 };
129 
130 // Decides whether target |offset| is covered by a section in |sorted_headers|.
131 template <class ELF_SHDR>
IsTargetOffsetInElfSectionList(const std::vector<const ELF_SHDR * > & sorted_headers,offset_t offset)132 bool IsTargetOffsetInElfSectionList(
133     const std::vector<const ELF_SHDR*>& sorted_headers,
134     offset_t offset) {
135   // Use binary search to search in a list of intervals, in a fashion similar to
136   // AddressTranslator::OffsetToUnit().
137   auto comp = [](offset_t offset, const ELF_SHDR* header) -> bool {
138     return offset < header->sh_offset;
139   };
140   auto it = std::upper_bound(sorted_headers.begin(), sorted_headers.end(),
141                              offset, comp);
142   if (it == sorted_headers.begin())
143     return false;
144   --it;
145   // Just check offset without worrying about width, since this is a target.
146   // Not using RangeCovers() because |sh_offset| and |sh_size| can be 64-bit.
147   return offset >= (*it)->sh_offset &&
148          offset - (*it)->sh_offset < (*it)->sh_size;
149 }
150 
151 // Disassembler for ELF.
152 template <class TRAITS>
153 class DisassemblerElf : public Disassembler {
154  public:
155   using Traits = TRAITS;
156   static constexpr uint16_t kVersion = Traits::kVersion;
157   // Applies quick checks to determine whether |image| *may* point to the start
158   // of an executable. Returns true iff the check passes.
159   static bool QuickDetect(ConstBufferView image);
160 
161   DisassemblerElf(const DisassemblerElf&) = delete;
162   const DisassemblerElf& operator=(const DisassemblerElf&) = delete;
163   ~DisassemblerElf() override;
164 
165   // Disassembler:
166   ExecutableType GetExeType() const override;
167   std::string GetExeTypeString() const override;
168   std::vector<ReferenceGroup> MakeReferenceGroups() const override = 0;
169 
170   // Read/Write functions that are common among different architectures.
171   std::unique_ptr<ReferenceReader> MakeReadRelocs(offset_t lo, offset_t hi);
172   std::unique_ptr<ReferenceWriter> MakeWriteRelocs(MutableBufferView image);
173 
translator()174   const AddressTranslator& translator() const { return translator_; }
175 
176  protected:
177   friend Disassembler;
178 
179   DisassemblerElf();
180 
181   bool Parse(ConstBufferView image) override;
182 
183   // Returns the supported Elf_Ehdr::e_machine enum.
supported_architecture()184   static constexpr elf::MachineArchitecture supported_architecture() {
185     return Traits::kMachineValue;
186   }
187 
188   // Returns the type to look for in the reloc section.
supported_relocation_type()189   static constexpr uint32_t supported_relocation_type() {
190     return Traits::kRelType;
191   }
192 
193   // Performs architecture-specific parsing of an executable section, to extract
194   // rel32 references.
195   virtual void ParseExecSection(const typename Traits::Elf_Shdr& section) = 0;
196 
197   // Processes rel32 data after they are extracted from executable sections.
198   virtual void PostProcessRel32() = 0;
199 
200   // Parses ELF header and section headers, and performs basic validation.
201   // Returns whether parsing was successful.
202   bool ParseHeader();
203 
204   // Extracts and stores section headers that we need.
205   void ExtractInterestingSectionHeaders();
206 
207   // Parsing functions that extract references from various sections.
208   void GetAbs32FromRelocSections();
209   void GetRel32FromCodeSections();
210   void ParseSections();
211 
212   // Main ELF header.
213   const typename Traits::Elf_Ehdr* header_ = nullptr;
214 
215   // Section header table, ordered by section id.
216   elf::Elf32_Half sections_count_ = 0;
217   const typename Traits::Elf_Shdr* sections_ = nullptr;
218 
219   // Program header table.
220   elf::Elf32_Half segments_count_ = 0;
221   const typename Traits::Elf_Phdr* segments_ = nullptr;
222 
223   // Bit fields to store the role each section may play.
224   std::vector<int> section_judgements_;
225 
226   // Translator between offsets and RVAs.
227   AddressTranslator translator_;
228 
229   // Identity translator for abs32 translation.
230   AddressTranslator identity_translator_;
231 
232   // Extracted relocation section dimensions data, sorted by file offsets.
233   std::vector<SectionDimensionsElf> reloc_section_dims_;
234 
235   // Headers of executable sections, sorted by file offsets of the data each
236   // header points to.
237   std::vector<const typename Traits::Elf_Shdr*> exec_headers_;
238 
239   // Sorted file offsets of abs32 locations.
240   std::vector<offset_t> abs32_locations_;
241 };
242 
243 // Disassembler for ELF with Intel architectures.
244 template <class TRAITS>
245 class DisassemblerElfIntel : public DisassemblerElf<TRAITS> {
246  public:
247   using Traits = TRAITS;
248   enum ReferenceType : uint8_t { kReloc, kAbs32, kRel32, kTypeCount };
249 
250   DisassemblerElfIntel();
251   DisassemblerElfIntel(const DisassemblerElfIntel&) = delete;
252   const DisassemblerElfIntel& operator=(const DisassemblerElfIntel&) = delete;
253   ~DisassemblerElfIntel() override;
254 
255   // Disassembler:
256   std::vector<ReferenceGroup> MakeReferenceGroups() const override;
257 
258   // DisassemblerElf:
259   void ParseExecSection(const typename Traits::Elf_Shdr& section) override;
260   void PostProcessRel32() override;
261 
262   // Specialized Read/Write functions.
263   std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
264   std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
265   std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lo, offset_t hi);
266   std::unique_ptr<ReferenceWriter> MakeWriteRel32(MutableBufferView image);
267 
268  private:
269   // Sorted file offsets of rel32 locations.
270   // Using std::deque to reduce peak memory footprint.
271   std::deque<offset_t> rel32_locations_;
272 };
273 
274 using DisassemblerElfX86 = DisassemblerElfIntel<Elf32IntelTraits>;
275 using DisassemblerElfX64 = DisassemblerElfIntel<Elf64IntelTraits>;
276 
277 // Disassembler for ELF with ARM architectures.
278 template <class TRAITS>
279 class DisassemblerElfArm : public DisassemblerElf<TRAITS> {
280  public:
281   using Traits = TRAITS;
282   DisassemblerElfArm();
283   DisassemblerElfArm(const DisassemblerElfArm&) = delete;
284   const DisassemblerElfArm& operator=(const DisassemblerElfArm&) = delete;
285   ~DisassemblerElfArm() override;
286 
287   // Determines whether target |offset| is in an executable section.
288   bool IsTargetOffsetInExecSection(offset_t offset) const;
289 
290   // Creates an architecture-specific Rel32Finder for ParseExecSection.
291   virtual std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
292       const typename Traits::Elf_Shdr& section) = 0;
293 
294   // DisassemblerElf:
295   void ParseExecSection(const typename Traits::Elf_Shdr& section) override;
296   void PostProcessRel32() override;
297 
298   // Specialized Read/Write functions.
299   std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
300   std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
301 
302   // Specialized Read/Write functions for different rel32 address types.
303   template <class ADDR_TRAITS>
304   std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lower,
305                                                  offset_t upper);
306   template <class ADDR_TRAITS>
307   std::unique_ptr<ReferenceWriter> MakeWriteRel32(MutableBufferView image);
308 
309  protected:
310   // Sorted file offsets of rel32 locations for each rel32 address type.
311   std::deque<offset_t>
312       rel32_locations_table_[Traits::ArmReferenceType::kTypeCount];
313 };
314 
315 // Disassembler for ELF with AArch32 (AKA ARM32).
316 class DisassemblerElfAArch32 : public DisassemblerElfArm<ElfAArch32Traits> {
317  public:
318   DisassemblerElfAArch32();
319   DisassemblerElfAArch32(const DisassemblerElfAArch32&) = delete;
320   const DisassemblerElfAArch32& operator=(const DisassemblerElfAArch32&) =
321       delete;
322   ~DisassemblerElfAArch32() override;
323 
324   // Disassembler:
325   std::vector<ReferenceGroup> MakeReferenceGroups() const override;
326 
327   // DisassemblerElfArm:
328   std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
329       const typename Traits::Elf_Shdr& section) override;
330 
331   // Under the naive assumption that an executable section is entirely ARM mode
332   // or THUMB2 mode, this function implements heuristics to distinguish between
333   // the two. Returns true if section is THUMB2 mode; otherwise return false.
334   bool IsExecSectionThumb2(const typename Traits::Elf_Shdr& section) const;
335 };
336 
337 // Disassembler for ELF with AArch64 (AKA ARM64).
338 class DisassemblerElfAArch64 : public DisassemblerElfArm<ElfAArch64Traits> {
339  public:
340   DisassemblerElfAArch64();
341   DisassemblerElfAArch64(const DisassemblerElfAArch64&) = delete;
342   const DisassemblerElfAArch64& operator=(const DisassemblerElfAArch64&) =
343       delete;
344   ~DisassemblerElfAArch64() override;
345 
346   // Disassembler:
347   std::vector<ReferenceGroup> MakeReferenceGroups() const override;
348 
349   // DisassemblerElfArm:
350   std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
351       const typename Traits::Elf_Shdr& section) override;
352 };
353 
354 }  // namespace zucchini
355 
356 #endif  // COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_
357