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 50AvbIOResult FakeAvbOps::read_from_partition(const char* partition, 51 int64_t offset, 52 size_t num_bytes, 53 void* buffer, 54 size_t* out_num_read) { 55 base::FilePath path = 56 partition_dir_.Append(std::string(partition)).AddExtension("img"); 57 58 partition_names_read_from_.insert(partition); 59 60 if (offset < 0) { 61 int64_t file_size; 62 if (!base::GetFileSize(path, &file_size)) { 63 fprintf( 64 stderr, "Error getting size of file '%s'\n", path.value().c_str()); 65 return AVB_IO_RESULT_ERROR_IO; 66 } 67 offset = file_size - (-offset); 68 } 69 70 int fd = open(path.value().c_str(), O_RDONLY); 71 if (fd < 0) { 72 fprintf(stderr, 73 "Error opening file '%s': %s\n", 74 path.value().c_str(), 75 strerror(errno)); 76 if (errno == ENOENT) { 77 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 78 } else { 79 return AVB_IO_RESULT_ERROR_IO; 80 } 81 } 82 if (lseek(fd, offset, SEEK_SET) != offset) { 83 fprintf(stderr, 84 "Error seeking to pos %zd in file %s: %s\n", 85 offset, 86 path.value().c_str(), 87 strerror(errno)); 88 close(fd); 89 return AVB_IO_RESULT_ERROR_IO; 90 } 91 ssize_t num_read = read(fd, buffer, num_bytes); 92 if (num_read < 0) { 93 fprintf(stderr, 94 "Error reading %zd bytes from pos %" PRId64 " in file %s: %s\n", 95 num_bytes, 96 offset, 97 path.value().c_str(), 98 strerror(errno)); 99 close(fd); 100 return AVB_IO_RESULT_ERROR_IO; 101 } 102 close(fd); 103 104 if (out_num_read != NULL) { 105 *out_num_read = num_read; 106 } 107 108 return AVB_IO_RESULT_OK; 109} 110 111AvbIOResult FakeAvbOps::write_to_partition(const char* partition, 112 int64_t offset, 113 size_t num_bytes, 114 const void* buffer) { 115 base::FilePath path = 116 partition_dir_.Append(std::string(partition)).AddExtension("img"); 117 118 if (offset < 0) { 119 int64_t file_size; 120 if (!base::GetFileSize(path, &file_size)) { 121 fprintf( 122 stderr, "Error getting size of file '%s'\n", path.value().c_str()); 123 return AVB_IO_RESULT_ERROR_IO; 124 } 125 offset = file_size - (-offset); 126 } 127 128 int fd = open(path.value().c_str(), O_WRONLY); 129 if (fd < 0) { 130 fprintf(stderr, 131 "Error opening file '%s': %s\n", 132 path.value().c_str(), 133 strerror(errno)); 134 if (errno == ENOENT) { 135 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 136 } else { 137 return AVB_IO_RESULT_ERROR_IO; 138 } 139 } 140 if (lseek(fd, offset, SEEK_SET) != offset) { 141 fprintf(stderr, 142 "Error seeking to pos %zd in file %s: %s\n", 143 offset, 144 path.value().c_str(), 145 strerror(errno)); 146 close(fd); 147 return AVB_IO_RESULT_ERROR_IO; 148 } 149 ssize_t num_written = write(fd, buffer, num_bytes); 150 if (num_written < 0) { 151 fprintf(stderr, 152 "Error writing %zd bytes at pos %" PRId64 " in file %s: %s\n", 153 num_bytes, 154 offset, 155 path.value().c_str(), 156 strerror(errno)); 157 close(fd); 158 return AVB_IO_RESULT_ERROR_IO; 159 } 160 close(fd); 161 162 return AVB_IO_RESULT_OK; 163} 164 165AvbIOResult FakeAvbOps::validate_vbmeta_public_key( 166 AvbOps* ops, 167 const uint8_t* public_key_data, 168 size_t public_key_length, 169 const uint8_t* public_key_metadata, 170 size_t public_key_metadata_length, 171 bool* out_key_is_trusted) { 172 if (out_key_is_trusted != NULL) { 173 bool pk_matches = (public_key_length == expected_public_key_.size() && 174 (memcmp(expected_public_key_.c_str(), 175 public_key_data, 176 public_key_length) == 0)); 177 bool pkmd_matches = 178 (public_key_metadata_length == expected_public_key_metadata_.size() && 179 (memcmp(expected_public_key_metadata_.c_str(), 180 public_key_metadata, 181 public_key_metadata_length) == 0)); 182 *out_key_is_trusted = pk_matches && pkmd_matches; 183 } 184 return AVB_IO_RESULT_OK; 185} 186 187AvbIOResult FakeAvbOps::read_rollback_index(AvbOps* ops, 188 size_t rollback_index_location, 189 uint64_t* out_rollback_index) { 190 if (stored_rollback_indexes_.count(rollback_index_location) == 0) { 191 fprintf(stderr, 192 "No rollback index for location %zd (has %zd locations).\n", 193 rollback_index_location, 194 stored_rollback_indexes_.size()); 195 return AVB_IO_RESULT_ERROR_IO; 196 } 197 *out_rollback_index = stored_rollback_indexes_[rollback_index_location]; 198 return AVB_IO_RESULT_OK; 199} 200 201AvbIOResult FakeAvbOps::write_rollback_index(AvbOps* ops, 202 size_t rollback_index_location, 203 uint64_t rollback_index) { 204 if (stored_rollback_indexes_.count(rollback_index_location) == 0) { 205 fprintf(stderr, 206 "No rollback index for location %zd (has %zd locations).\n", 207 rollback_index_location, 208 stored_rollback_indexes_.size()); 209 return AVB_IO_RESULT_ERROR_IO; 210 } 211 stored_rollback_indexes_[rollback_index_location] = rollback_index; 212 return AVB_IO_RESULT_OK; 213} 214 215AvbIOResult FakeAvbOps::read_is_device_unlocked(AvbOps* ops, 216 bool* out_is_device_unlocked) { 217 *out_is_device_unlocked = stored_is_device_unlocked_ ? 1 : 0; 218 return AVB_IO_RESULT_OK; 219} 220 221AvbIOResult FakeAvbOps::get_unique_guid_for_partition(AvbOps* ops, 222 const char* partition, 223 char* guid_buf, 224 size_t guid_buf_size) { 225 // This is faking it a bit but makes testing easy. It works 226 // because avb_slot_verify.c doesn't check that the returned GUID 227 // is wellformed. 228 snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition); 229 return AVB_IO_RESULT_OK; 230} 231 232AvbIOResult FakeAvbOps::get_size_of_partition(AvbOps* ops, 233 const char* partition, 234 uint64_t* out_size) { 235 base::FilePath path = 236 partition_dir_.Append(std::string(partition)).AddExtension("img"); 237 238 int64_t file_size; 239 if (!base::GetFileSize(path, &file_size)) { 240 fprintf(stderr, "Error getting size of file '%s'\n", path.value().c_str()); 241 return AVB_IO_RESULT_ERROR_IO; 242 } 243 *out_size = file_size; 244 return AVB_IO_RESULT_OK; 245} 246 247AvbIOResult FakeAvbOps::read_permanent_attributes( 248 AvbAtxPermanentAttributes* attributes) { 249 *attributes = permanent_attributes_; 250 return AVB_IO_RESULT_OK; 251} 252 253AvbIOResult FakeAvbOps::read_permanent_attributes_hash( 254 uint8_t hash[AVB_SHA256_DIGEST_SIZE]) { 255 if (permanent_attributes_hash_.empty()) { 256 SHA256(reinterpret_cast<const unsigned char*>(&permanent_attributes_), 257 sizeof(AvbAtxPermanentAttributes), 258 hash); 259 return AVB_IO_RESULT_OK; 260 } 261 memset(hash, 0, AVB_SHA256_DIGEST_SIZE); 262 permanent_attributes_hash_.copy(reinterpret_cast<char*>(hash), 263 AVB_SHA256_DIGEST_SIZE); 264 return AVB_IO_RESULT_OK; 265} 266 267static AvbIOResult my_ops_read_from_partition(AvbOps* ops, 268 const char* partition, 269 int64_t offset, 270 size_t num_bytes, 271 void* buffer, 272 size_t* out_num_read) { 273 return FakeAvbOps::GetInstanceFromAvbOps(ops) 274 ->delegate() 275 ->read_from_partition(partition, offset, num_bytes, buffer, out_num_read); 276} 277 278static AvbIOResult my_ops_write_to_partition(AvbOps* ops, 279 const char* partition, 280 int64_t offset, 281 size_t num_bytes, 282 const void* buffer) { 283 return FakeAvbOps::GetInstanceFromAvbOps(ops)->delegate()->write_to_partition( 284 partition, offset, num_bytes, buffer); 285} 286 287static AvbIOResult my_ops_validate_vbmeta_public_key( 288 AvbOps* ops, 289 const uint8_t* public_key_data, 290 size_t public_key_length, 291 const uint8_t* public_key_metadata, 292 size_t public_key_metadata_length, 293 bool* out_key_is_trusted) { 294 return FakeAvbOps::GetInstanceFromAvbOps(ops) 295 ->delegate() 296 ->validate_vbmeta_public_key(ops, 297 public_key_data, 298 public_key_length, 299 public_key_metadata, 300 public_key_metadata_length, 301 out_key_is_trusted); 302} 303 304static AvbIOResult my_ops_read_rollback_index(AvbOps* ops, 305 size_t rollback_index_location, 306 uint64_t* out_rollback_index) { 307 return FakeAvbOps::GetInstanceFromAvbOps(ops) 308 ->delegate() 309 ->read_rollback_index(ops, rollback_index_location, out_rollback_index); 310} 311 312static AvbIOResult my_ops_write_rollback_index(AvbOps* ops, 313 size_t rollback_index_location, 314 uint64_t rollback_index) { 315 return FakeAvbOps::GetInstanceFromAvbOps(ops) 316 ->delegate() 317 ->write_rollback_index(ops, rollback_index_location, rollback_index); 318} 319 320static AvbIOResult my_ops_read_is_device_unlocked( 321 AvbOps* ops, bool* out_is_device_unlocked) { 322 return FakeAvbOps::GetInstanceFromAvbOps(ops) 323 ->delegate() 324 ->read_is_device_unlocked(ops, out_is_device_unlocked); 325} 326 327static AvbIOResult my_ops_get_unique_guid_for_partition(AvbOps* ops, 328 const char* partition, 329 char* guid_buf, 330 size_t guid_buf_size) { 331 return FakeAvbOps::GetInstanceFromAvbOps(ops) 332 ->delegate() 333 ->get_unique_guid_for_partition(ops, partition, guid_buf, guid_buf_size); 334} 335 336static AvbIOResult my_ops_get_size_of_partition(AvbOps* ops, 337 const char* partition, 338 uint64_t* out_size) { 339 return FakeAvbOps::GetInstanceFromAvbOps(ops) 340 ->delegate() 341 ->get_size_of_partition(ops, partition, out_size); 342} 343 344static AvbIOResult my_ops_read_permanent_attributes( 345 AvbAtxOps* atx_ops, AvbAtxPermanentAttributes* attributes) { 346 return FakeAvbOps::GetInstanceFromAvbOps(atx_ops->ops) 347 ->delegate() 348 ->read_permanent_attributes(attributes); 349} 350 351static AvbIOResult my_ops_read_permanent_attributes_hash( 352 AvbAtxOps* atx_ops, uint8_t hash[AVB_SHA256_DIGEST_SIZE]) { 353 return FakeAvbOps::GetInstanceFromAvbOps(atx_ops->ops) 354 ->delegate() 355 ->read_permanent_attributes_hash(hash); 356} 357 358FakeAvbOps::FakeAvbOps() { 359 avb_ops_.ab_ops = &avb_ab_ops_; 360 avb_ops_.atx_ops = &avb_atx_ops_; 361 avb_ops_.user_data = this; 362 avb_ops_.read_from_partition = my_ops_read_from_partition; 363 avb_ops_.write_to_partition = my_ops_write_to_partition; 364 avb_ops_.validate_vbmeta_public_key = my_ops_validate_vbmeta_public_key; 365 avb_ops_.read_rollback_index = my_ops_read_rollback_index; 366 avb_ops_.write_rollback_index = my_ops_write_rollback_index; 367 avb_ops_.read_is_device_unlocked = my_ops_read_is_device_unlocked; 368 avb_ops_.get_unique_guid_for_partition = my_ops_get_unique_guid_for_partition; 369 avb_ops_.get_size_of_partition = my_ops_get_size_of_partition; 370 371 // Just use the built-in A/B metadata read/write routines. 372 avb_ab_ops_.ops = &avb_ops_; 373 avb_ab_ops_.read_ab_metadata = avb_ab_data_read; 374 avb_ab_ops_.write_ab_metadata = avb_ab_data_write; 375 376 avb_atx_ops_.ops = &avb_ops_; 377 avb_atx_ops_.read_permanent_attributes = my_ops_read_permanent_attributes; 378 avb_atx_ops_.read_permanent_attributes_hash = 379 my_ops_read_permanent_attributes_hash; 380 381 delegate_ = this; 382} 383 384FakeAvbOps::~FakeAvbOps() {} 385 386} // namespace avb 387