blob: 8a1b932522313ffc1332f494ce26b337822cdb9d [file] [log] [blame]
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +00001// 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>
Samuel Huang21bbdef2020-01-23 15:58:26 +000011#include <utility>
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +000012#include <vector>
13
14#include "base/numerics/safe_conversions.h"
15#include "components/zucchini/address_translator.h"
16#include "components/zucchini/algorithm.h"
Samuel Huang21bbdef2020-01-23 15:58:26 +000017#include "components/zucchini/disassembler_elf.h"
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +000018#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
23namespace zucchini {
24
25namespace {
26
27template <class Elf_Shdr>
28SectionDimensionsElf 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
Samuel Huang21bbdef2020-01-23 15:58:26 +000050// Helper to manipulate an image with one or more relocation tables.
Samuel Huang3e1f64d2021-08-04 00:58:50 +000051template <class ELF_INTEL_TRAITS>
Samuel Huang21bbdef2020-01-23 15:58:26 +000052class FakeImageWithReloc {
53 public:
Samuel Huang3e1f64d2021-08-04 00:58:50 +000054 using ElfIntelTraits = ELF_INTEL_TRAITS;
Samuel Huang21bbdef2020-01-23 15:58:26 +000055 struct RelocSpec {
56 offset_t start;
57 std::vector<uint8_t> data;
58 };
59
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()) {
Peter Kasting3865f0b2021-06-09 19:27:03 +000065 translator_.Initialize({{0, static_cast<offset_t>(image_size), base_rva,
66 static_cast<rva_t>(image_size)}});
Samuel Huang21bbdef2020-01-23 15:58:26 +000067 // 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
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;
Anton Bikineev1a965512021-05-15 22:35:36 +000090 for (absl::optional<Reference> ref = reader->GetNext(); ref.has_value();
Samuel Huang21bbdef2020-01-23 15:58:26 +000091 ref = reader->GetNext()) {
92 refs.push_back(ref.value());
93 }
94 return refs;
95 }
96
97 std::unique_ptr<RelocWriterElf> MakeRelocWriter() {
98 return std::move(std::make_unique<RelocWriterElf>(
99 mutable_image_, ElfIntelTraits::kBitness, translator_));
100 }
101
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
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000115} // namespace
116
117TEST(RelocElfTest, ReadWrite32) {
118 // Set up mock image: Size = 0x3000, .reloc at 0x600. RVA is 0x40000 + offset.
Samuel Huang21bbdef2020-01-23 15:58:26 +0000119 constexpr size_t kImageSize = 0x3000;
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000120 constexpr rva_t kBaseRva = 0x40000;
Samuel Huang21bbdef2020-01-23 15:58:26 +0000121
122 constexpr offset_t kRelocStart0 = 0x600;
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000123 // "C0 10 04 00 08 00 00 00" represents
124 // (r_sym, r_type, r_offset) = (0x000000, 0x08, 0x000410C0).
Samuel Huang21bbdef2020-01-23 15:58:26 +0000125 // 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(
Samuel Huang2dedd302019-01-08 18:37:09 +0000128 "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.
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000132
Samuel Huang21bbdef2020-01-23 15:58:26 +0000133 constexpr offset_t kRelocStart1 = 0x620;
134 std::vector<uint8_t> reloc_data1 = ParseHexString(
Samuel Huang2dedd302019-01-08 18:37:09 +0000135 "BC 20 04 00 08 00 00 00 " // R_386_RELATIVE.
136 "A0 20 04 00 08 AB CD EF"); // R_386_RELATIVE.
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000137
Samuel Huang21bbdef2020-01-23 15:58:26 +0000138 FakeImageWithReloc<Elf32IntelTraits> fake_image(
139 kImageSize, kBaseRva,
140 {{kRelocStart0, reloc_data0}, {kRelocStart1, reloc_data1}});
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000141
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000142 // 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}};
Samuel Huang21bbdef2020-01-23 15:58:26 +0000146 EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences());
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000147
148 // Write reference, extract bytes and check.
Samuel Huang21bbdef2020-01-23 15:58:26 +0000149 std::unique_ptr<RelocWriterElf> writer = fake_image.MakeRelocWriter();
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000150
151 writer->PutNext({0x608, 0x1F83});
Samuel Huang21bbdef2020-01-23 15:58:26 +0000152 std::vector<uint8_t> exp_reloc_data0 = ParseHexString(
Samuel Huang2dedd302019-01-08 18:37:09 +0000153 "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.
Samuel Huang21bbdef2020-01-23 15:58:26 +0000157 EXPECT_EQ(exp_reloc_data0, fake_image.GetRawRelocData(0));
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000158
159 writer->PutNext({0x628, 0x2950});
Samuel Huang21bbdef2020-01-23 15:58:26 +0000160 std::vector<uint8_t> exp_reloc_data1 = ParseHexString(
Samuel Huang2dedd302019-01-08 18:37:09 +0000161 "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).
Samuel Huang21bbdef2020-01-23 15:58:26 +0000163 EXPECT_EQ(exp_reloc_data1, fake_image.GetRawRelocData(1));
164}
165
166TEST(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
202TEST(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());
Etienne Pierre-Doraya88cad02018-07-25 20:16:02 +0000240}
241
242} // namespace zucchini