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