xref: /aosp_15_r20/external/zucchini/reloc_elf_unittest.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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/reloc_elf.h"
6 
7 #include <stdint.h>
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/numerics/safe_conversions.h"
15 #include "components/zucchini/address_translator.h"
16 #include "components/zucchini/algorithm.h"
17 #include "components/zucchini/disassembler_elf.h"
18 #include "components/zucchini/image_utils.h"
19 #include "components/zucchini/test_utils.h"
20 #include "components/zucchini/type_elf.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace zucchini {
24 
25 namespace {
26 
27 template <class Elf_Shdr>
MakeSectionDimensions(const BufferRegion & region,offset_t entry_size)28 SectionDimensionsElf MakeSectionDimensions(const BufferRegion& region,
29                                            offset_t entry_size) {
30   using sh_offset_t = decltype(Elf_Shdr::sh_offset);
31   using sh_size_t = decltype(Elf_Shdr::sh_size);
32   using sh_entsize_t = decltype(Elf_Shdr::sh_entsize);
33   return SectionDimensionsElf{Elf_Shdr{
34       0,  // sh_name
35       0,  // sh_type
36       0,  // sh_flags
37       0,  // sh_addr
38       // sh_offset
39       base::checked_cast<sh_offset_t>(region.offset),
40       // sh_size
41       base::checked_cast<sh_size_t>(region.size),
42       0,  // sh_link
43       0,  // sh_info
44       0,  // sh_addralign
45       // sh_entsize
46       base::checked_cast<sh_entsize_t>(entry_size),
47   }};
48 }
49 
50 // Helper to manipulate an image with one or more relocation tables.
51 template <class ELF_INTEL_TRAITS>
52 class FakeImageWithReloc {
53  public:
54   using ElfIntelTraits = ELF_INTEL_TRAITS;
55   struct RelocSpec {
56     offset_t start;
57     std::vector<uint8_t> data;
58   };
59 
FakeImageWithReloc(size_t image_size,rva_t base_rva,const std::vector<RelocSpec> & reloc_specs)60   FakeImageWithReloc(size_t image_size,
61                      rva_t base_rva,
62                      const std::vector<RelocSpec>& reloc_specs)
63       : image_data_(image_size, 0xFF),
64         mutable_image_(&image_data_[0], image_data_.size()) {
65     translator_.Initialize({{0, static_cast<offset_t>(image_size), base_rva,
66                              static_cast<rva_t>(image_size)}});
67     // Set up test image with reloc sections.
68     for (const RelocSpec& reloc_spec : reloc_specs) {
69       BufferRegion reloc_region = {reloc_spec.start, reloc_spec.data.size()};
70       std::copy(reloc_spec.data.begin(), reloc_spec.data.end(),
71                 image_data_.begin() + reloc_region.lo());
72       section_dimensions_.emplace_back(
73           MakeSectionDimensions<typename ElfIntelTraits::Elf_Shdr>(
74               reloc_region, ElfIntelTraits::kVAWidth));
75       reloc_regions_.push_back(reloc_region);
76     }
77   }
78 
ExtractRelocReferences()79   std::vector<Reference> ExtractRelocReferences() {
80     const size_t image_size = image_data_.size();
81     ConstBufferView image = {image_data_.data(), image_size};
82 
83     // Make RelocReaderElf.
84     auto reader = std::make_unique<RelocReaderElf>(
85         image, ElfIntelTraits::kBitness, section_dimensions_,
86         ElfIntelTraits::kRelType, 0, image_size, translator_);
87 
88     // Read all references and check.
89     std::vector<Reference> refs;
90     for (std::optional<Reference> ref = reader->GetNext(); ref.has_value();
91          ref = reader->GetNext()) {
92       refs.push_back(ref.value());
93     }
94     return refs;
95   }
96 
MakeRelocWriter()97   std::unique_ptr<RelocWriterElf> MakeRelocWriter() {
98     return std::move(std::make_unique<RelocWriterElf>(
99         mutable_image_, ElfIntelTraits::kBitness, translator_));
100   }
101 
GetRawRelocData(int reloc_index)102   std::vector<uint8_t> GetRawRelocData(int reloc_index) {
103     BufferRegion reloc_region = reloc_regions_[reloc_index];
104     return Sub(image_data_, reloc_region.lo(), reloc_region.hi());
105   }
106 
107  private:
108   std::vector<uint8_t> image_data_;
109   MutableBufferView mutable_image_;
110   std::vector<BufferRegion> reloc_regions_;
111   std::vector<SectionDimensionsElf> section_dimensions_;
112   AddressTranslator translator_;
113 };
114 
115 }  // namespace
116 
TEST(RelocElfTest,ReadWrite32)117 TEST(RelocElfTest, ReadWrite32) {
118   // Set up mock image: Size = 0x3000, .reloc at 0x600. RVA is 0x40000 + offset.
119   constexpr size_t kImageSize = 0x3000;
120   constexpr rva_t kBaseRva = 0x40000;
121 
122   constexpr offset_t kRelocStart0 = 0x600;
123   // "C0 10 04 00 08 00 00 00" represents
124   // (r_sym, r_type, r_offset) = (0x000000, 0x08, 0x000410C0).
125   // r_type = 0x08 = R_386_RELATIVE, and so |r_offset| is an RVA 0x000410C0.
126   // Zucchini does not care about |r_sym|.
127   std::vector<uint8_t> reloc_data0 = ParseHexString(
128       "C0 10 04 00 08 00 00 00 "   // R_386_RELATIVE.
129       "F8 10 04 00 08 AB CD EF "   // R_386_RELATIVE.
130       "00 10 04 00 00 AB CD EF "   // R_386_NONE.
131       "00 10 04 00 07 AB CD EF");  // R_386_JMP_SLOT.
132 
133   constexpr offset_t kRelocStart1 = 0x620;
134   std::vector<uint8_t> reloc_data1 = ParseHexString(
135       "BC 20 04 00 08 00 00 00 "   // R_386_RELATIVE.
136       "A0 20 04 00 08 AB CD EF");  // R_386_RELATIVE.
137 
138   FakeImageWithReloc<Elf32IntelTraits> fake_image(
139       kImageSize, kBaseRva,
140       {{kRelocStart0, reloc_data0}, {kRelocStart1, reloc_data1}});
141 
142   // Only R_386_RELATIVE references are extracted. Targets are translated from
143   // address (e.g., 0x000420BC) to offset (e.g., 0x20BC).
144   std::vector<Reference> exp_refs{
145       {0x600, 0x10C0}, {0x608, 0x10F8}, {0x620, 0x20BC}, {0x628, 0x20A0}};
146   EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences());
147 
148   // Write reference, extract bytes and check.
149   std::unique_ptr<RelocWriterElf> writer = fake_image.MakeRelocWriter();
150 
151   writer->PutNext({0x608, 0x1F83});
152   std::vector<uint8_t> exp_reloc_data0 = ParseHexString(
153       "C0 10 04 00 08 00 00 00 "   // R_386_RELATIVE.
154       "83 1F 04 00 08 AB CD EF "   // R_386_RELATIVE (address modified).
155       "00 10 04 00 00 AB CD EF "   // R_386_NONE.
156       "00 10 04 00 07 AB CD EF");  // R_386_JMP_SLOT.
157   EXPECT_EQ(exp_reloc_data0, fake_image.GetRawRelocData(0));
158 
159   writer->PutNext({0x628, 0x2950});
160   std::vector<uint8_t> exp_reloc_data1 = ParseHexString(
161       "BC 20 04 00 08 00 00 00 "   // R_386_RELATIVE.
162       "50 29 04 00 08 AB CD EF");  // R_386_RELATIVE (address modified).
163   EXPECT_EQ(exp_reloc_data1, fake_image.GetRawRelocData(1));
164 }
165 
TEST(RelocElfTest,Limit32)166 TEST(RelocElfTest, Limit32) {
167   constexpr size_t kImageSize = 0x3000;
168   constexpr offset_t kBaseRva = 0x40000;
169   constexpr offset_t kRelocStart = 0x600;
170   // All R_386_RELATIVE.
171   std::vector<uint8_t> reloc_data = ParseHexString(
172       // Strictly within file.
173       "00 00 04 00 08 00 00 00 "
174       "00 10 04 00 08 00 00 00 "
175       "F0 2F 04 00 08 00 00 00 "
176       "F8 2F 04 00 08 00 00 00 "
177       "FC 2F 04 00 08 00 00 00 "
178       // Straddles end of file.
179       "FD 2F 04 00 08 00 00 00 "
180       "FE 2F 04 00 08 00 00 00 "
181       "FF 2F 04 00 08 00 00 00 "
182       // Beyond end of file.
183       "00 30 04 00 08 00 00 00 "
184       "01 30 04 00 08 00 00 00 "
185       "FC FF FF 7F 08 00 00 00 "
186       "FE FF FF 7F 08 00 00 00 "
187       "00 00 00 80 08 00 00 00 "
188       "FC FF FF FF 08 00 00 00 "
189       "FF FF FF FF 08 00 00 00 "
190       // Another good reference.
191       "34 12 04 00 08 00 00 00");
192 
193   FakeImageWithReloc<Elf32IntelTraits> fake_image(kImageSize, kBaseRva,
194                                                   {{kRelocStart, reloc_data}});
195 
196   std::vector<Reference> exp_refs{{0x600, 0x0000}, {0x608, 0x1000},
197                                   {0x610, 0x2FF0}, {0x618, 0x2FF8},
198                                   {0x620, 0x2FFC}, {0x678, 0x1234}};
199   EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences());
200 }
201 
TEST(RelocElfTest,Limit64)202 TEST(RelocElfTest, Limit64) {
203   constexpr size_t kImageSize = 0x3000;
204   constexpr offset_t kBaseRva = 0x40000;
205 
206   constexpr offset_t kRelocStart = 0x600;
207   // All R_X86_64_RELATIVE.
208   std::vector<uint8_t> reloc_data = ParseHexString(
209       // Strictly within file.
210       "00 00 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
211       "00 10 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
212       "F0 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
213       "F4 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
214       "F8 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
215       // Straddles end of file.
216       "F9 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
217       "FC 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
218       "FF 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
219       // Beyond end of file.
220       "00 30 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
221       "01 30 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
222       "FC FF FF 7F 00 00 00 00 08 00 00 00 00 00 00 00 "
223       "FE FF FF 7F 00 00 00 00 08 00 00 00 00 00 00 00 "
224       "00 00 00 80 00 00 00 00 08 00 00 00 00 00 00 00 "
225       "FC FF FF FF 00 00 00 00 08 00 00 00 00 00 00 00 "
226       "FF FF FF FF 00 00 00 00 08 00 00 00 00 00 00 00 "
227       "00 00 04 00 01 00 00 00 08 00 00 00 00 00 00 00 "
228       "FF FF FF FF FF FF FF FF 08 00 00 00 00 00 00 00 "
229       "F8 FF FF FF FF FF FF FF 08 00 00 00 00 00 00 00 "
230       // Another good reference.
231       "34 12 04 00 00 00 00 00 08 00 00 00 00 00 00 00");
232 
233   FakeImageWithReloc<Elf64IntelTraits> fake_image(kImageSize, kBaseRva,
234                                                   {{kRelocStart, reloc_data}});
235 
236   std::vector<Reference> exp_refs{{0x600, 0x0000}, {0x610, 0x1000},
237                                   {0x620, 0x2FF0}, {0x630, 0x2FF4},
238                                   {0x640, 0x2FF8}, {0x720, 0x1234}};
239   EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences());
240 }
241 
242 }  // namespace zucchini
243