1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <iostream>
26
27 #include <endian.h>
28 #include <errno.h>
29 #include <inttypes.h>
30 #include <string.h>
31
32 #include <fcntl.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36
37 #include <base/files/file_util.h>
38 #include <base/strings/string_util.h>
39 #include <base/strings/stringprintf.h>
40 #include <openssl/sha.h>
41
42 #include "fake_avb_ops.h"
43
44 namespace avb {
45
read_from_partition(const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)46 AvbIOResult FakeAvbOps::read_from_partition(const char* partition,
47 int64_t offset,
48 size_t num_bytes,
49 void* buffer,
50 size_t* out_num_read) {
51 base::FilePath path =
52 partition_dir_.Append(std::string(partition)).AddExtension("img");
53
54 if (offset < 0) {
55 int64_t file_size;
56 if (!base::GetFileSize(path, &file_size)) {
57 fprintf(
58 stderr, "Error getting size of file '%s'\n", path.value().c_str());
59 return AVB_IO_RESULT_ERROR_IO;
60 }
61 offset = file_size - (-offset);
62 }
63
64 int fd = open(path.value().c_str(), O_RDONLY);
65 if (fd < 0) {
66 fprintf(stderr,
67 "Error opening file '%s': %s\n",
68 path.value().c_str(),
69 strerror(errno));
70 if (errno == ENOENT) {
71 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
72 } else {
73 return AVB_IO_RESULT_ERROR_IO;
74 }
75 }
76 if (lseek(fd, offset, SEEK_SET) != offset) {
77 fprintf(stderr,
78 "Error seeking to pos %zd in file %s: %s\n",
79 offset,
80 path.value().c_str(),
81 strerror(errno));
82 close(fd);
83 return AVB_IO_RESULT_ERROR_IO;
84 }
85 ssize_t num_read = read(fd, buffer, num_bytes);
86 if (num_read < 0) {
87 fprintf(stderr,
88 "Error reading %zd bytes from pos %" PRId64 " in file %s: %s\n",
89 num_bytes,
90 offset,
91 path.value().c_str(),
92 strerror(errno));
93 close(fd);
94 return AVB_IO_RESULT_ERROR_IO;
95 }
96 close(fd);
97
98 if (out_num_read != NULL) {
99 *out_num_read = num_read;
100 }
101
102 return AVB_IO_RESULT_OK;
103 }
104
write_to_partition(const char * partition,int64_t offset,size_t num_bytes,const void * buffer)105 AvbIOResult FakeAvbOps::write_to_partition(const char* partition,
106 int64_t offset,
107 size_t num_bytes,
108 const void* buffer) {
109 base::FilePath path =
110 partition_dir_.Append(std::string(partition)).AddExtension("img");
111
112 if (offset < 0) {
113 int64_t file_size;
114 if (!base::GetFileSize(path, &file_size)) {
115 fprintf(
116 stderr, "Error getting size of file '%s'\n", path.value().c_str());
117 return AVB_IO_RESULT_ERROR_IO;
118 }
119 offset = file_size - (-offset);
120 }
121
122 int fd = open(path.value().c_str(), O_WRONLY);
123 if (fd < 0) {
124 fprintf(stderr,
125 "Error opening file '%s': %s\n",
126 path.value().c_str(),
127 strerror(errno));
128 if (errno == ENOENT) {
129 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
130 } else {
131 return AVB_IO_RESULT_ERROR_IO;
132 }
133 }
134 if (lseek(fd, offset, SEEK_SET) != offset) {
135 fprintf(stderr,
136 "Error seeking to pos %zd in file %s: %s\n",
137 offset,
138 path.value().c_str(),
139 strerror(errno));
140 close(fd);
141 return AVB_IO_RESULT_ERROR_IO;
142 }
143 ssize_t num_written = write(fd, buffer, num_bytes);
144 if (num_written < 0) {
145 fprintf(stderr,
146 "Error writing %zd bytes at pos %" PRId64 " in file %s: %s\n",
147 num_bytes,
148 offset,
149 path.value().c_str(),
150 strerror(errno));
151 close(fd);
152 return AVB_IO_RESULT_ERROR_IO;
153 }
154 close(fd);
155
156 return AVB_IO_RESULT_OK;
157 }
158
validate_vbmeta_public_key(AvbOps * ops,const uint8_t * public_key_data,size_t public_key_length,const uint8_t * public_key_metadata,size_t public_key_metadata_length,bool * out_key_is_trusted)159 AvbIOResult FakeAvbOps::validate_vbmeta_public_key(
160 AvbOps* ops,
161 const uint8_t* public_key_data,
162 size_t public_key_length,
163 const uint8_t* public_key_metadata,
164 size_t public_key_metadata_length,
165 bool* out_key_is_trusted) {
166 if (out_key_is_trusted != NULL) {
167 bool pk_matches = (public_key_length == expected_public_key_.size() &&
168 (memcmp(expected_public_key_.c_str(),
169 public_key_data,
170 public_key_length) == 0));
171 bool pkmd_matches =
172 (public_key_metadata_length == expected_public_key_metadata_.size() &&
173 (memcmp(expected_public_key_metadata_.c_str(),
174 public_key_metadata,
175 public_key_metadata_length) == 0));
176 *out_key_is_trusted = pk_matches && pkmd_matches;
177 }
178 return AVB_IO_RESULT_OK;
179 }
180
read_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t * out_rollback_index)181 AvbIOResult FakeAvbOps::read_rollback_index(AvbOps* ops,
182 size_t rollback_index_location,
183 uint64_t* out_rollback_index) {
184 if (stored_rollback_indexes_.count(rollback_index_location) == 0) {
185 fprintf(stderr,
186 "No rollback index for location %zd (has %zd locations).\n",
187 rollback_index_location,
188 stored_rollback_indexes_.size());
189 return AVB_IO_RESULT_ERROR_IO;
190 }
191 *out_rollback_index = stored_rollback_indexes_[rollback_index_location];
192 return AVB_IO_RESULT_OK;
193 }
194
write_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t rollback_index)195 AvbIOResult FakeAvbOps::write_rollback_index(AvbOps* ops,
196 size_t rollback_index_location,
197 uint64_t rollback_index) {
198 if (stored_rollback_indexes_.count(rollback_index_location) == 0) {
199 fprintf(stderr,
200 "No rollback index for location %zd (has %zd locations).\n",
201 rollback_index_location,
202 stored_rollback_indexes_.size());
203 return AVB_IO_RESULT_ERROR_IO;
204 }
205 stored_rollback_indexes_[rollback_index_location] = rollback_index;
206 return AVB_IO_RESULT_OK;
207 }
208
read_is_device_unlocked(AvbOps * ops,bool * out_is_device_unlocked)209 AvbIOResult FakeAvbOps::read_is_device_unlocked(AvbOps* ops,
210 bool* out_is_device_unlocked) {
211 *out_is_device_unlocked = stored_is_device_unlocked_ ? 1 : 0;
212 return AVB_IO_RESULT_OK;
213 }
214
get_unique_guid_for_partition(AvbOps * ops,const char * partition,char * guid_buf,size_t guid_buf_size)215 AvbIOResult FakeAvbOps::get_unique_guid_for_partition(AvbOps* ops,
216 const char* partition,
217 char* guid_buf,
218 size_t guid_buf_size) {
219 // This is faking it a bit but makes testing easy. It works
220 // because avb_slot_verify.c doesn't check that the returned GUID
221 // is wellformed.
222 snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition);
223 return AVB_IO_RESULT_OK;
224 }
225
read_permanent_attributes(AvbAtxPermanentAttributes * attributes)226 AvbIOResult FakeAvbOps::read_permanent_attributes(
227 AvbAtxPermanentAttributes* attributes) {
228 *attributes = permanent_attributes_;
229 return AVB_IO_RESULT_OK;
230 }
231
read_permanent_attributes_hash(uint8_t hash[AVB_SHA256_DIGEST_SIZE])232 AvbIOResult FakeAvbOps::read_permanent_attributes_hash(
233 uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
234 if (permanent_attributes_hash_.empty()) {
235 SHA256(reinterpret_cast<const unsigned char*>(&permanent_attributes_),
236 sizeof(AvbAtxPermanentAttributes),
237 hash);
238 return AVB_IO_RESULT_OK;
239 }
240 memset(hash, 0, AVB_SHA256_DIGEST_SIZE);
241 permanent_attributes_hash_.copy(reinterpret_cast<char*>(hash),
242 AVB_SHA256_DIGEST_SIZE);
243 return AVB_IO_RESULT_OK;
244 }
245
my_ops_read_from_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)246 static AvbIOResult my_ops_read_from_partition(AvbOps* ops,
247 const char* partition,
248 int64_t offset,
249 size_t num_bytes,
250 void* buffer,
251 size_t* out_num_read) {
252 return FakeAvbOps::GetInstanceFromAvbOps(ops)
253 ->delegate()
254 ->read_from_partition(partition, offset, num_bytes, buffer, out_num_read);
255 }
256
my_ops_write_to_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,const void * buffer)257 static AvbIOResult my_ops_write_to_partition(AvbOps* ops,
258 const char* partition,
259 int64_t offset,
260 size_t num_bytes,
261 const void* buffer) {
262 return FakeAvbOps::GetInstanceFromAvbOps(ops)->delegate()->write_to_partition(
263 partition, offset, num_bytes, buffer);
264 }
265
my_ops_validate_vbmeta_public_key(AvbOps * ops,const uint8_t * public_key_data,size_t public_key_length,const uint8_t * public_key_metadata,size_t public_key_metadata_length,bool * out_key_is_trusted)266 static AvbIOResult my_ops_validate_vbmeta_public_key(
267 AvbOps* ops,
268 const uint8_t* public_key_data,
269 size_t public_key_length,
270 const uint8_t* public_key_metadata,
271 size_t public_key_metadata_length,
272 bool* out_key_is_trusted) {
273 return FakeAvbOps::GetInstanceFromAvbOps(ops)
274 ->delegate()
275 ->validate_vbmeta_public_key(ops,
276 public_key_data,
277 public_key_length,
278 public_key_metadata,
279 public_key_metadata_length,
280 out_key_is_trusted);
281 }
282
my_ops_read_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t * out_rollback_index)283 static AvbIOResult my_ops_read_rollback_index(AvbOps* ops,
284 size_t rollback_index_location,
285 uint64_t* out_rollback_index) {
286 return FakeAvbOps::GetInstanceFromAvbOps(ops)
287 ->delegate()
288 ->read_rollback_index(ops, rollback_index_location, out_rollback_index);
289 }
290
my_ops_write_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t rollback_index)291 static AvbIOResult my_ops_write_rollback_index(AvbOps* ops,
292 size_t rollback_index_location,
293 uint64_t rollback_index) {
294 return FakeAvbOps::GetInstanceFromAvbOps(ops)
295 ->delegate()
296 ->write_rollback_index(ops, rollback_index_location, rollback_index);
297 }
298
my_ops_read_is_device_unlocked(AvbOps * ops,bool * out_is_device_unlocked)299 static AvbIOResult my_ops_read_is_device_unlocked(
300 AvbOps* ops, bool* out_is_device_unlocked) {
301 return FakeAvbOps::GetInstanceFromAvbOps(ops)
302 ->delegate()
303 ->read_is_device_unlocked(ops, out_is_device_unlocked);
304 }
305
my_ops_get_unique_guid_for_partition(AvbOps * ops,const char * partition,char * guid_buf,size_t guid_buf_size)306 static AvbIOResult my_ops_get_unique_guid_for_partition(AvbOps* ops,
307 const char* partition,
308 char* guid_buf,
309 size_t guid_buf_size) {
310 return FakeAvbOps::GetInstanceFromAvbOps(ops)
311 ->delegate()
312 ->get_unique_guid_for_partition(ops, partition, guid_buf, guid_buf_size);
313 }
314
my_ops_read_permanent_attributes(AvbAtxOps * atx_ops,AvbAtxPermanentAttributes * attributes)315 static AvbIOResult my_ops_read_permanent_attributes(
316 AvbAtxOps* atx_ops, AvbAtxPermanentAttributes* attributes) {
317 return FakeAvbOps::GetInstanceFromAvbOps(atx_ops->ops)
318 ->delegate()
319 ->read_permanent_attributes(attributes);
320 }
321
my_ops_read_permanent_attributes_hash(AvbAtxOps * atx_ops,uint8_t hash[AVB_SHA256_DIGEST_SIZE])322 static AvbIOResult my_ops_read_permanent_attributes_hash(
323 AvbAtxOps* atx_ops, uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
324 return FakeAvbOps::GetInstanceFromAvbOps(atx_ops->ops)
325 ->delegate()
326 ->read_permanent_attributes_hash(hash);
327 }
328
FakeAvbOps()329 FakeAvbOps::FakeAvbOps() {
330 avb_ops_.ab_ops = &avb_ab_ops_;
331 avb_ops_.atx_ops = &avb_atx_ops_;
332 avb_ops_.user_data = this;
333 avb_ops_.read_from_partition = my_ops_read_from_partition;
334 avb_ops_.write_to_partition = my_ops_write_to_partition;
335 avb_ops_.validate_vbmeta_public_key = my_ops_validate_vbmeta_public_key;
336 avb_ops_.read_rollback_index = my_ops_read_rollback_index;
337 avb_ops_.write_rollback_index = my_ops_write_rollback_index;
338 avb_ops_.read_is_device_unlocked = my_ops_read_is_device_unlocked;
339 avb_ops_.get_unique_guid_for_partition = my_ops_get_unique_guid_for_partition;
340
341 // Just use the built-in A/B metadata read/write routines.
342 avb_ab_ops_.ops = &avb_ops_;
343 avb_ab_ops_.read_ab_metadata = avb_ab_data_read;
344 avb_ab_ops_.write_ab_metadata = avb_ab_data_write;
345
346 avb_atx_ops_.ops = &avb_ops_;
347 avb_atx_ops_.read_permanent_attributes = my_ops_read_permanent_attributes;
348 avb_atx_ops_.read_permanent_attributes_hash =
349 my_ops_read_permanent_attributes_hash;
350
351 delegate_ = this;
352 }
353
~FakeAvbOps()354 FakeAvbOps::~FakeAvbOps() {}
355
356 } // namespace avb
357