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