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
get_partition_names_read_from()46 std::set<std::string> FakeAvbOps::get_partition_names_read_from() {
47 return partition_names_read_from_;
48 }
49
preload_partition(const std::string & partition,const base::FilePath & path)50 bool FakeAvbOps::preload_partition(const std::string& partition,
51 const base::FilePath& path) {
52 if (preloaded_partitions_.count(partition) > 0) {
53 fprintf(stderr, "Partition '%s' already preloaded\n", partition.c_str());
54 return false;
55 }
56
57 int64_t file_size;
58 if (!base::GetFileSize(path, &file_size)) {
59 fprintf(stderr, "Error getting size of file '%s'\n", path.value().c_str());
60 return false;
61 }
62
63 int fd = open(path.value().c_str(), O_RDONLY);
64 if (fd < 0) {
65 fprintf(stderr,
66 "Error opening file '%s': %s\n",
67 path.value().c_str(),
68 strerror(errno));
69 return false;
70 }
71
72 uint8_t* buffer = static_cast<uint8_t*>(malloc(file_size));
73 ssize_t num_read = read(fd, buffer, file_size);
74 if (num_read != file_size) {
75 fprintf(stderr,
76 "Error reading %zd bytes from file '%s': %s\n",
77 file_size,
78 path.value().c_str(),
79 strerror(errno));
80 free(buffer);
81 return false;
82 }
83 close(fd);
84
85 preloaded_partitions_[partition] = buffer;
86 return true;
87 }
88
read_from_partition(const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)89 AvbIOResult FakeAvbOps::read_from_partition(const char* partition,
90 int64_t offset,
91 size_t num_bytes,
92 void* buffer,
93 size_t* out_num_read) {
94 base::FilePath path =
95 partition_dir_.Append(std::string(partition)).AddExtension("img");
96
97 partition_names_read_from_.insert(partition);
98
99 if (offset < 0) {
100 int64_t file_size;
101 if (!base::GetFileSize(path, &file_size)) {
102 fprintf(
103 stderr, "Error getting size of file '%s'\n", path.value().c_str());
104 return AVB_IO_RESULT_ERROR_IO;
105 }
106 offset = file_size - (-offset);
107 }
108
109 int fd = open(path.value().c_str(), O_RDONLY);
110 if (fd < 0) {
111 fprintf(stderr,
112 "Error opening file '%s': %s\n",
113 path.value().c_str(),
114 strerror(errno));
115 if (errno == ENOENT) {
116 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
117 } else {
118 return AVB_IO_RESULT_ERROR_IO;
119 }
120 }
121 if (lseek(fd, offset, SEEK_SET) != offset) {
122 fprintf(stderr,
123 "Error seeking to pos %zd in file %s: %s\n",
124 offset,
125 path.value().c_str(),
126 strerror(errno));
127 close(fd);
128 return AVB_IO_RESULT_ERROR_IO;
129 }
130 ssize_t num_read = read(fd, buffer, num_bytes);
131 if (num_read < 0) {
132 fprintf(stderr,
133 "Error reading %zd bytes from pos %" PRId64 " in file %s: %s\n",
134 num_bytes,
135 offset,
136 path.value().c_str(),
137 strerror(errno));
138 close(fd);
139 return AVB_IO_RESULT_ERROR_IO;
140 }
141 close(fd);
142
143 if (out_num_read != NULL) {
144 *out_num_read = num_read;
145 }
146
147 return AVB_IO_RESULT_OK;
148 }
149
get_preloaded_partition(const char * partition,size_t num_bytes,uint8_t ** out_pointer,size_t * out_num_bytes_preloaded)150 AvbIOResult FakeAvbOps::get_preloaded_partition(
151 const char* partition,
152 size_t num_bytes,
153 uint8_t** out_pointer,
154 size_t* out_num_bytes_preloaded) {
155 std::map<std::string, uint8_t*>::iterator it =
156 preloaded_partitions_.find(std::string(partition));
157 if (it == preloaded_partitions_.end()) {
158 *out_pointer = NULL;
159 *out_num_bytes_preloaded = 0;
160 return AVB_IO_RESULT_OK;
161 }
162
163 uint64_t size;
164 AvbIOResult result = get_size_of_partition(avb_ops(), partition, &size);
165 if (result != AVB_IO_RESULT_OK) {
166 return result;
167 }
168 if (size != num_bytes) {
169 return AVB_IO_RESULT_ERROR_IO;
170 }
171
172 *out_num_bytes_preloaded = num_bytes;
173 *out_pointer = it->second;
174 return AVB_IO_RESULT_OK;
175 }
176
write_to_partition(const char * partition,int64_t offset,size_t num_bytes,const void * buffer)177 AvbIOResult FakeAvbOps::write_to_partition(const char* partition,
178 int64_t offset,
179 size_t num_bytes,
180 const void* buffer) {
181 base::FilePath path =
182 partition_dir_.Append(std::string(partition)).AddExtension("img");
183
184 if (offset < 0) {
185 int64_t file_size;
186 if (!base::GetFileSize(path, &file_size)) {
187 fprintf(
188 stderr, "Error getting size of file '%s'\n", path.value().c_str());
189 return AVB_IO_RESULT_ERROR_IO;
190 }
191 offset = file_size - (-offset);
192 }
193
194 int fd = open(path.value().c_str(), O_WRONLY);
195 if (fd < 0) {
196 fprintf(stderr,
197 "Error opening file '%s': %s\n",
198 path.value().c_str(),
199 strerror(errno));
200 if (errno == ENOENT) {
201 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
202 } else {
203 return AVB_IO_RESULT_ERROR_IO;
204 }
205 }
206 if (lseek(fd, offset, SEEK_SET) != offset) {
207 fprintf(stderr,
208 "Error seeking to pos %zd in file %s: %s\n",
209 offset,
210 path.value().c_str(),
211 strerror(errno));
212 close(fd);
213 return AVB_IO_RESULT_ERROR_IO;
214 }
215 ssize_t num_written = write(fd, buffer, num_bytes);
216 if (num_written < 0) {
217 fprintf(stderr,
218 "Error writing %zd bytes at pos %" PRId64 " in file %s: %s\n",
219 num_bytes,
220 offset,
221 path.value().c_str(),
222 strerror(errno));
223 close(fd);
224 return AVB_IO_RESULT_ERROR_IO;
225 }
226 close(fd);
227
228 return AVB_IO_RESULT_OK;
229 }
230
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)231 AvbIOResult FakeAvbOps::validate_vbmeta_public_key(
232 AvbOps* ops,
233 const uint8_t* public_key_data,
234 size_t public_key_length,
235 const uint8_t* public_key_metadata,
236 size_t public_key_metadata_length,
237 bool* out_key_is_trusted) {
238 if (out_key_is_trusted != NULL) {
239 bool pk_matches = (public_key_length == expected_public_key_.size() &&
240 (memcmp(expected_public_key_.c_str(),
241 public_key_data,
242 public_key_length) == 0));
243 bool pkmd_matches =
244 (public_key_metadata_length == expected_public_key_metadata_.size() &&
245 (memcmp(expected_public_key_metadata_.c_str(),
246 public_key_metadata,
247 public_key_metadata_length) == 0));
248 *out_key_is_trusted = pk_matches && pkmd_matches;
249 }
250 return AVB_IO_RESULT_OK;
251 }
252
read_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t * out_rollback_index)253 AvbIOResult FakeAvbOps::read_rollback_index(AvbOps* ops,
254 size_t rollback_index_location,
255 uint64_t* out_rollback_index) {
256 if (stored_rollback_indexes_.count(rollback_index_location) == 0) {
257 fprintf(stderr,
258 "No rollback index for location %zd (has %zd locations).\n",
259 rollback_index_location,
260 stored_rollback_indexes_.size());
261 return AVB_IO_RESULT_ERROR_IO;
262 }
263 *out_rollback_index = stored_rollback_indexes_[rollback_index_location];
264 return AVB_IO_RESULT_OK;
265 }
266
write_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t rollback_index)267 AvbIOResult FakeAvbOps::write_rollback_index(AvbOps* ops,
268 size_t rollback_index_location,
269 uint64_t rollback_index) {
270 if (stored_rollback_indexes_.count(rollback_index_location) == 0) {
271 fprintf(stderr,
272 "No rollback index for location %zd (has %zd locations).\n",
273 rollback_index_location,
274 stored_rollback_indexes_.size());
275 return AVB_IO_RESULT_ERROR_IO;
276 }
277 stored_rollback_indexes_[rollback_index_location] = rollback_index;
278 return AVB_IO_RESULT_OK;
279 }
280
read_is_device_unlocked(AvbOps * ops,bool * out_is_device_unlocked)281 AvbIOResult FakeAvbOps::read_is_device_unlocked(AvbOps* ops,
282 bool* out_is_device_unlocked) {
283 *out_is_device_unlocked = stored_is_device_unlocked_ ? 1 : 0;
284 return AVB_IO_RESULT_OK;
285 }
286
get_unique_guid_for_partition(AvbOps * ops,const char * partition,char * guid_buf,size_t guid_buf_size)287 AvbIOResult FakeAvbOps::get_unique_guid_for_partition(AvbOps* ops,
288 const char* partition,
289 char* guid_buf,
290 size_t guid_buf_size) {
291 // This is faking it a bit but makes testing easy. It works
292 // because avb_slot_verify.c doesn't check that the returned GUID
293 // is wellformed.
294 snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition);
295 return AVB_IO_RESULT_OK;
296 }
297
get_size_of_partition(AvbOps * ops,const char * partition,uint64_t * out_size)298 AvbIOResult FakeAvbOps::get_size_of_partition(AvbOps* ops,
299 const char* partition,
300 uint64_t* out_size) {
301 base::FilePath path =
302 partition_dir_.Append(std::string(partition)).AddExtension("img");
303
304 int64_t file_size;
305 if (!base::GetFileSize(path, &file_size)) {
306 fprintf(stderr, "Error getting size of file '%s'\n", path.value().c_str());
307 return AVB_IO_RESULT_ERROR_IO;
308 }
309 *out_size = file_size;
310 return AVB_IO_RESULT_OK;
311 }
312
read_persistent_value(const char * name,size_t buffer_size,uint8_t * out_buffer,size_t * out_num_bytes_read)313 AvbIOResult FakeAvbOps::read_persistent_value(const char* name,
314 size_t buffer_size,
315 uint8_t* out_buffer,
316 size_t* out_num_bytes_read) {
317 if (out_buffer == NULL && buffer_size > 0) {
318 return AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE;
319 }
320 if (stored_values_.count(name) == 0) {
321 return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
322 }
323 if (stored_values_[name].size() > buffer_size) {
324 *out_num_bytes_read = stored_values_[name].size();
325 return AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE;
326 }
327 memcpy(out_buffer, stored_values_[name].data(), stored_values_[name].size());
328 *out_num_bytes_read = stored_values_[name].size();
329 return AVB_IO_RESULT_OK;
330 }
331
write_persistent_value(const char * name,size_t value_size,const uint8_t * value)332 AvbIOResult FakeAvbOps::write_persistent_value(const char* name,
333 size_t value_size,
334 const uint8_t* value) {
335 stored_values_[name] =
336 std::string(reinterpret_cast<const char*>(value), value_size);
337 return AVB_IO_RESULT_OK;
338 }
339
read_permanent_attributes(AvbAtxPermanentAttributes * attributes)340 AvbIOResult FakeAvbOps::read_permanent_attributes(
341 AvbAtxPermanentAttributes* attributes) {
342 *attributes = permanent_attributes_;
343 return AVB_IO_RESULT_OK;
344 }
345
read_permanent_attributes_hash(uint8_t hash[AVB_SHA256_DIGEST_SIZE])346 AvbIOResult FakeAvbOps::read_permanent_attributes_hash(
347 uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
348 if (permanent_attributes_hash_.empty()) {
349 SHA256(reinterpret_cast<const unsigned char*>(&permanent_attributes_),
350 sizeof(AvbAtxPermanentAttributes),
351 hash);
352 return AVB_IO_RESULT_OK;
353 }
354 memset(hash, 0, AVB_SHA256_DIGEST_SIZE);
355 permanent_attributes_hash_.copy(reinterpret_cast<char*>(hash),
356 AVB_SHA256_DIGEST_SIZE);
357 return AVB_IO_RESULT_OK;
358 }
359
set_key_version(size_t rollback_index_location,uint64_t key_version)360 void FakeAvbOps::set_key_version(size_t rollback_index_location,
361 uint64_t key_version) {
362 verified_rollback_indexes_[rollback_index_location] = key_version;
363 }
364
my_ops_read_from_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)365 static AvbIOResult my_ops_read_from_partition(AvbOps* ops,
366 const char* partition,
367 int64_t offset,
368 size_t num_bytes,
369 void* buffer,
370 size_t* out_num_read) {
371 return FakeAvbOps::GetInstanceFromAvbOps(ops)
372 ->delegate()
373 ->read_from_partition(partition, offset, num_bytes, buffer, out_num_read);
374 }
375
my_ops_get_preloaded_partition(AvbOps * ops,const char * partition,size_t num_bytes,uint8_t ** out_pointer,size_t * out_num_bytes_preloaded)376 static AvbIOResult my_ops_get_preloaded_partition(
377 AvbOps* ops,
378 const char* partition,
379 size_t num_bytes,
380 uint8_t** out_pointer,
381 size_t* out_num_bytes_preloaded) {
382 return FakeAvbOps::GetInstanceFromAvbOps(ops)
383 ->delegate()
384 ->get_preloaded_partition(
385 partition, num_bytes, out_pointer, out_num_bytes_preloaded);
386 }
387
my_ops_write_to_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,const void * buffer)388 static AvbIOResult my_ops_write_to_partition(AvbOps* ops,
389 const char* partition,
390 int64_t offset,
391 size_t num_bytes,
392 const void* buffer) {
393 return FakeAvbOps::GetInstanceFromAvbOps(ops)->delegate()->write_to_partition(
394 partition, offset, num_bytes, buffer);
395 }
396
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)397 static AvbIOResult my_ops_validate_vbmeta_public_key(
398 AvbOps* ops,
399 const uint8_t* public_key_data,
400 size_t public_key_length,
401 const uint8_t* public_key_metadata,
402 size_t public_key_metadata_length,
403 bool* out_key_is_trusted) {
404 return FakeAvbOps::GetInstanceFromAvbOps(ops)
405 ->delegate()
406 ->validate_vbmeta_public_key(ops,
407 public_key_data,
408 public_key_length,
409 public_key_metadata,
410 public_key_metadata_length,
411 out_key_is_trusted);
412 }
413
my_ops_read_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t * out_rollback_index)414 static AvbIOResult my_ops_read_rollback_index(AvbOps* ops,
415 size_t rollback_index_location,
416 uint64_t* out_rollback_index) {
417 return FakeAvbOps::GetInstanceFromAvbOps(ops)
418 ->delegate()
419 ->read_rollback_index(ops, rollback_index_location, out_rollback_index);
420 }
421
my_ops_write_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t rollback_index)422 static AvbIOResult my_ops_write_rollback_index(AvbOps* ops,
423 size_t rollback_index_location,
424 uint64_t rollback_index) {
425 return FakeAvbOps::GetInstanceFromAvbOps(ops)
426 ->delegate()
427 ->write_rollback_index(ops, rollback_index_location, rollback_index);
428 }
429
my_ops_read_is_device_unlocked(AvbOps * ops,bool * out_is_device_unlocked)430 static AvbIOResult my_ops_read_is_device_unlocked(
431 AvbOps* ops, bool* out_is_device_unlocked) {
432 return FakeAvbOps::GetInstanceFromAvbOps(ops)
433 ->delegate()
434 ->read_is_device_unlocked(ops, out_is_device_unlocked);
435 }
436
my_ops_get_unique_guid_for_partition(AvbOps * ops,const char * partition,char * guid_buf,size_t guid_buf_size)437 static AvbIOResult my_ops_get_unique_guid_for_partition(AvbOps* ops,
438 const char* partition,
439 char* guid_buf,
440 size_t guid_buf_size) {
441 return FakeAvbOps::GetInstanceFromAvbOps(ops)
442 ->delegate()
443 ->get_unique_guid_for_partition(ops, partition, guid_buf, guid_buf_size);
444 }
445
my_ops_get_size_of_partition(AvbOps * ops,const char * partition,uint64_t * out_size)446 static AvbIOResult my_ops_get_size_of_partition(AvbOps* ops,
447 const char* partition,
448 uint64_t* out_size) {
449 return FakeAvbOps::GetInstanceFromAvbOps(ops)
450 ->delegate()
451 ->get_size_of_partition(ops, partition, out_size);
452 }
453
my_ops_read_persistent_value(AvbOps * ops,const char * name,size_t buffer_size,uint8_t * out_buffer,size_t * out_num_bytes_read)454 static AvbIOResult my_ops_read_persistent_value(AvbOps* ops,
455 const char* name,
456 size_t buffer_size,
457 uint8_t* out_buffer,
458 size_t* out_num_bytes_read) {
459 return FakeAvbOps::GetInstanceFromAvbOps(ops)
460 ->delegate()
461 ->read_persistent_value(
462 name, buffer_size, out_buffer, out_num_bytes_read);
463 }
464
my_ops_write_persistent_value(AvbOps * ops,const char * name,size_t value_size,const uint8_t * value)465 static AvbIOResult my_ops_write_persistent_value(AvbOps* ops,
466 const char* name,
467 size_t value_size,
468 const uint8_t* value) {
469 return FakeAvbOps::GetInstanceFromAvbOps(ops)
470 ->delegate()
471 ->write_persistent_value(name, value_size, value);
472 }
473
my_ops_read_permanent_attributes(AvbAtxOps * atx_ops,AvbAtxPermanentAttributes * attributes)474 static AvbIOResult my_ops_read_permanent_attributes(
475 AvbAtxOps* atx_ops, AvbAtxPermanentAttributes* attributes) {
476 return FakeAvbOps::GetInstanceFromAvbOps(atx_ops->ops)
477 ->delegate()
478 ->read_permanent_attributes(attributes);
479 }
480
my_ops_read_permanent_attributes_hash(AvbAtxOps * atx_ops,uint8_t hash[AVB_SHA256_DIGEST_SIZE])481 static AvbIOResult my_ops_read_permanent_attributes_hash(
482 AvbAtxOps* atx_ops, uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
483 return FakeAvbOps::GetInstanceFromAvbOps(atx_ops->ops)
484 ->delegate()
485 ->read_permanent_attributes_hash(hash);
486 }
487
my_ops_set_key_version(AvbAtxOps * atx_ops,size_t rollback_index_location,uint64_t key_version)488 static void my_ops_set_key_version(AvbAtxOps* atx_ops,
489 size_t rollback_index_location,
490 uint64_t key_version) {
491 return FakeAvbOps::GetInstanceFromAvbOps(atx_ops->ops)
492 ->delegate()
493 ->set_key_version(rollback_index_location, key_version);
494 }
495
FakeAvbOps()496 FakeAvbOps::FakeAvbOps() {
497 memset(&avb_ops_, 0, sizeof(avb_ops_));
498 avb_ops_.ab_ops = &avb_ab_ops_;
499 avb_ops_.atx_ops = &avb_atx_ops_;
500 avb_ops_.user_data = this;
501 avb_ops_.read_from_partition = my_ops_read_from_partition;
502 avb_ops_.write_to_partition = my_ops_write_to_partition;
503 avb_ops_.validate_vbmeta_public_key = my_ops_validate_vbmeta_public_key;
504 avb_ops_.read_rollback_index = my_ops_read_rollback_index;
505 avb_ops_.write_rollback_index = my_ops_write_rollback_index;
506 avb_ops_.read_is_device_unlocked = my_ops_read_is_device_unlocked;
507 avb_ops_.get_unique_guid_for_partition = my_ops_get_unique_guid_for_partition;
508 avb_ops_.get_size_of_partition = my_ops_get_size_of_partition;
509 avb_ops_.read_persistent_value = my_ops_read_persistent_value;
510 avb_ops_.write_persistent_value = my_ops_write_persistent_value;
511
512 // Just use the built-in A/B metadata read/write routines.
513 avb_ab_ops_.ops = &avb_ops_;
514 avb_ab_ops_.read_ab_metadata = avb_ab_data_read;
515 avb_ab_ops_.write_ab_metadata = avb_ab_data_write;
516
517 avb_atx_ops_.ops = &avb_ops_;
518 avb_atx_ops_.read_permanent_attributes = my_ops_read_permanent_attributes;
519 avb_atx_ops_.read_permanent_attributes_hash =
520 my_ops_read_permanent_attributes_hash;
521 avb_atx_ops_.set_key_version = my_ops_set_key_version;
522
523 delegate_ = this;
524 }
525
~FakeAvbOps()526 FakeAvbOps::~FakeAvbOps() {
527 std::map<std::string, uint8_t*>::iterator it;
528 for (it = preloaded_partitions_.begin(); it != preloaded_partitions_.end();
529 it++) {
530 free(it->second);
531 }
532 }
533
enable_get_preloaded_partition()534 void FakeAvbOps::enable_get_preloaded_partition() {
535 avb_ops_.get_preloaded_partition = my_ops_get_preloaded_partition;
536 }
537
538 } // namespace avb
539