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