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 44namespace avb { 45 46std::set<std::string> FakeAvbOps::get_partition_names_read_from() { 47 return partition_names_read_from_; 48} 49 50bool 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 89AvbIOResult 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 150AvbIOResult 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 177AvbIOResult 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 231AvbIOResult 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 253AvbIOResult 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 267AvbIOResult 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 281AvbIOResult 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 287AvbIOResult 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 298AvbIOResult 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 313AvbIOResult 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 332AvbIOResult 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 340AvbIOResult FakeAvbOps::read_permanent_attributes( 341 AvbAtxPermanentAttributes* attributes) { 342 *attributes = permanent_attributes_; 343 return AVB_IO_RESULT_OK; 344} 345 346AvbIOResult 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 360void 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 365static 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 376static 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 388static 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 397static 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 414static 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 422static 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 430static 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 437static 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 446static 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 454static 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 465static 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 474static 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 481static 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 488static 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 496FakeAvbOps::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 526FakeAvbOps::~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 534void FakeAvbOps::enable_get_preloaded_partition() { 535 avb_ops_.get_preloaded_partition = my_ops_get_preloaded_partition; 536} 537 538} // namespace avb 539