1 // Copyright 2017 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/abs32_utils.h"
6
7 #include <algorithm>
8 #include <type_traits>
9 #include <utility>
10
11 #include "base/check_op.h"
12 #include "components/zucchini/io_utils.h"
13
14 namespace zucchini {
15
16 namespace {
17
18 // Templated helper for AbsoluteAddress::Read().
19 template <typename T>
ReadAbs(ConstBufferView image,offset_t offset,uint64_t * value)20 bool ReadAbs(ConstBufferView image, offset_t offset, uint64_t* value) {
21 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
22 if (!image.can_access<T>(offset))
23 return false;
24 *value = static_cast<uint64_t>(image.read<T>(offset));
25 return true;
26 }
27
28 // Templated helper for AbsoluteAddress::Write().
29 template <typename T>
WriteAbs(offset_t offset,T value,MutableBufferView * image)30 bool WriteAbs(offset_t offset, T value, MutableBufferView* image) {
31 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
32 if (!image->can_access<T>(offset))
33 return false;
34 image->write<T>(offset, value);
35 return true;
36 }
37
38 } // namespace
39
40 /******** AbsoluteAddress ********/
41
AbsoluteAddress(Bitness bitness,uint64_t image_base)42 AbsoluteAddress::AbsoluteAddress(Bitness bitness, uint64_t image_base)
43 : bitness_(bitness), image_base_(image_base), value_(image_base) {
44 CHECK(bitness_ == kBit64 || image_base_ < 0x100000000ULL);
45 }
46
47 AbsoluteAddress::AbsoluteAddress(AbsoluteAddress&&) = default;
48
49 AbsoluteAddress::~AbsoluteAddress() = default;
50
FromRva(rva_t rva)51 bool AbsoluteAddress::FromRva(rva_t rva) {
52 if (rva >= kRvaBound)
53 return false;
54 uint64_t value = image_base_ + rva;
55 // Check overflow, which manifests as |value| "wrapping around", resulting in
56 // |value| less than |image_base_| (preprocessing needed for 32-bit).
57 if (((bitness_ == kBit32) ? (value & 0xFFFFFFFFU) : value) < image_base_)
58 return false;
59 value_ = value;
60 return true;
61 }
62
ToRva() const63 rva_t AbsoluteAddress::ToRva() const {
64 if (value_ < image_base_)
65 return kInvalidRva;
66 uint64_t raw_rva = value_ - image_base_;
67 if (raw_rva >= kRvaBound)
68 return kInvalidRva;
69 return static_cast<rva_t>(raw_rva);
70 }
71
Read(offset_t offset,const ConstBufferView & image)72 bool AbsoluteAddress::Read(offset_t offset, const ConstBufferView& image) {
73 // Read raw data; |value_| is not guaranteed to represent a valid RVA.
74 if (bitness_ == kBit32)
75 return ReadAbs<uint32_t>(image, offset, &value_);
76 DCHECK_EQ(kBit64, bitness_);
77 return ReadAbs<uint64_t>(image, offset, &value_);
78 }
79
Write(offset_t offset,MutableBufferView * image)80 bool AbsoluteAddress::Write(offset_t offset, MutableBufferView* image) {
81 if (bitness_ == kBit32)
82 return WriteAbs<uint32_t>(offset, static_cast<uint32_t>(value_), image);
83 DCHECK_EQ(kBit64, bitness_);
84 return WriteAbs<uint64_t>(offset, value_, image);
85 }
86
87 /******** Abs32RvaExtractorWin32 ********/
88
Abs32RvaExtractorWin32(ConstBufferView image,AbsoluteAddress && addr,const std::vector<offset_t> & abs32_locations,offset_t lo,offset_t hi)89 Abs32RvaExtractorWin32::Abs32RvaExtractorWin32(
90 ConstBufferView image,
91 AbsoluteAddress&& addr,
92 const std::vector<offset_t>& abs32_locations,
93 offset_t lo,
94 offset_t hi)
95 : image_(image), addr_(std::move(addr)) {
96 CHECK_LE(lo, hi);
97 auto find_and_check = [this](const std::vector<offset_t>& locations,
98 offset_t offset) {
99 auto it = std::lower_bound(locations.begin(), locations.end(), offset);
100 // Ensure that |offset| does not straddle a reference body.
101 CHECK(it == locations.begin() || offset - *(it - 1) >= addr_.width());
102 return it;
103 };
104 cur_abs32_ = find_and_check(abs32_locations, lo);
105 end_abs32_ = find_and_check(abs32_locations, hi);
106 }
107
108 Abs32RvaExtractorWin32::Abs32RvaExtractorWin32(Abs32RvaExtractorWin32&&) =
109 default;
110
111 Abs32RvaExtractorWin32::~Abs32RvaExtractorWin32() = default;
112
GetNext()113 std::optional<Abs32RvaExtractorWin32::Unit> Abs32RvaExtractorWin32::GetNext() {
114 while (cur_abs32_ < end_abs32_) {
115 offset_t location = *(cur_abs32_++);
116 if (!addr_.Read(location, image_))
117 continue;
118 rva_t target_rva = addr_.ToRva();
119 if (target_rva == kInvalidRva)
120 continue;
121 return Unit{location, target_rva};
122 }
123 return std::nullopt;
124 }
125
126 /******** Abs32ReaderWin32 ********/
127
Abs32ReaderWin32(Abs32RvaExtractorWin32 && abs32_rva_extractor,const AddressTranslator & translator)128 Abs32ReaderWin32::Abs32ReaderWin32(Abs32RvaExtractorWin32&& abs32_rva_extractor,
129 const AddressTranslator& translator)
130 : abs32_rva_extractor_(std::move(abs32_rva_extractor)),
131 target_rva_to_offset_(translator) {}
132
133 Abs32ReaderWin32::~Abs32ReaderWin32() = default;
134
GetNext()135 std::optional<Reference> Abs32ReaderWin32::GetNext() {
136 for (auto unit = abs32_rva_extractor_.GetNext(); unit.has_value();
137 unit = abs32_rva_extractor_.GetNext()) {
138 offset_t location = unit->location;
139 offset_t unsafe_target = target_rva_to_offset_.Convert(unit->target_rva);
140 if (unsafe_target != kInvalidOffset)
141 return Reference{location, unsafe_target};
142 }
143 return std::nullopt;
144 }
145
146 /******** Abs32WriterWin32 ********/
147
Abs32WriterWin32(MutableBufferView image,AbsoluteAddress && addr,const AddressTranslator & translator)148 Abs32WriterWin32::Abs32WriterWin32(MutableBufferView image,
149 AbsoluteAddress&& addr,
150 const AddressTranslator& translator)
151 : image_(image),
152 addr_(std::move(addr)),
153 target_offset_to_rva_(translator) {}
154
155 Abs32WriterWin32::~Abs32WriterWin32() = default;
156
PutNext(Reference ref)157 void Abs32WriterWin32::PutNext(Reference ref) {
158 rva_t target_rva = target_offset_to_rva_.Convert(ref.target);
159 if (target_rva != kInvalidRva) {
160 addr_.FromRva(target_rva);
161 addr_.Write(ref.location, &image_);
162 }
163 }
164
165 /******** Exported Functions ********/
166
RemoveUntranslatableAbs32(ConstBufferView image,AbsoluteAddress && addr,const AddressTranslator & translator,std::vector<offset_t> * locations)167 size_t RemoveUntranslatableAbs32(ConstBufferView image,
168 AbsoluteAddress&& addr,
169 const AddressTranslator& translator,
170 std::vector<offset_t>* locations) {
171 AddressTranslator::RvaToOffsetCache target_rva_checker(translator);
172 Abs32RvaExtractorWin32 extractor(image, std::move(addr), *locations, 0,
173 image.size());
174 Abs32ReaderWin32 reader(std::move(extractor), translator);
175 std::vector<offset_t>::iterator write_it = locations->begin();
176 // |reader| reads |locations| while |write_it| modifies it. However, there's
177 // no conflict since read occurs before write, and can skip ahead.
178 for (auto ref = reader.GetNext(); ref.has_value(); ref = reader.GetNext())
179 *(write_it++) = ref->location;
180 DCHECK(write_it <= locations->end());
181 size_t num_removed = locations->end() - write_it;
182 locations->erase(write_it, locations->end());
183 return num_removed;
184 }
185
RemoveOverlappingAbs32Locations(uint32_t width,std::vector<offset_t> * locations)186 size_t RemoveOverlappingAbs32Locations(uint32_t width,
187 std::vector<offset_t>* locations) {
188 if (locations->size() <= 1)
189 return 0;
190
191 auto slow = locations->begin();
192 auto fast = locations->begin() + 1;
193 for (;;) {
194 // Find next good location.
195 while (fast != locations->end() && *fast - *slow < width)
196 ++fast;
197 // Advance |slow|. For the last iteration this becomes the new sentinel.
198 ++slow;
199 if (fast == locations->end())
200 break;
201 // Compactify good locations (potentially overwrite bad locations).
202 if (slow != fast)
203 *slow = *fast;
204 ++fast;
205 }
206 size_t num_removed = locations->end() - slow;
207 locations->erase(slow, locations->end());
208 return num_removed;
209 }
210
211 } // namespace zucchini
212