blob: 4b38dcc642d06c93747da790440bbb7874d9c5ab [file] [log] [blame]
David Zeuthen8b6973b2016-09-20 12:39:49 -04001/*
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>
Darren Krahn147b08d2016-12-20 16:38:29 -080040#include <openssl/sha.h>
David Zeuthen8b6973b2016-09-20 12:39:49 -040041
42#include "fake_avb_ops.h"
43
Darren Krahn72d57902016-12-12 18:34:08 -080044namespace avb {
45
David Zeuthen01ca9962017-05-23 15:28:17 -040046std::set<std::string> FakeAvbOps::get_partition_names_read_from() {
47 return partition_names_read_from_;
48}
49
David Zeuthen8b6973b2016-09-20 12:39:49 -040050AvbIOResult FakeAvbOps::read_from_partition(const char* partition,
David Zeuthen4b6a6342017-01-03 15:19:56 -050051 int64_t offset,
52 size_t num_bytes,
David Zeuthen8b6973b2016-09-20 12:39:49 -040053 void* buffer,
54 size_t* out_num_read) {
55 base::FilePath path =
56 partition_dir_.Append(std::string(partition)).AddExtension("img");
57
David Zeuthen01ca9962017-05-23 15:28:17 -040058 partition_names_read_from_.insert(partition);
59
David Zeuthen8b6973b2016-09-20 12:39:49 -040060 if (offset < 0) {
61 int64_t file_size;
62 if (!base::GetFileSize(path, &file_size)) {
David Zeuthen4b6a6342017-01-03 15:19:56 -050063 fprintf(
64 stderr, "Error getting size of file '%s'\n", path.value().c_str());
David Zeuthen8b6973b2016-09-20 12:39:49 -040065 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) {
David Zeuthen4b6a6342017-01-03 15:19:56 -050072 fprintf(stderr,
73 "Error opening file '%s': %s\n",
74 path.value().c_str(),
David Zeuthen8b6973b2016-09-20 12:39:49 -040075 strerror(errno));
David Zeuthena5fd3a42017-02-27 16:38:54 -050076 if (errno == ENOENT) {
77 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
78 } else {
79 return AVB_IO_RESULT_ERROR_IO;
80 }
David Zeuthen8b6973b2016-09-20 12:39:49 -040081 }
82 if (lseek(fd, offset, SEEK_SET) != offset) {
David Zeuthen4b6a6342017-01-03 15:19:56 -050083 fprintf(stderr,
84 "Error seeking to pos %zd in file %s: %s\n",
85 offset,
86 path.value().c_str(),
87 strerror(errno));
David Zeuthen8b6973b2016-09-20 12:39:49 -040088 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",
David Zeuthen4b6a6342017-01-03 15:19:56 -050095 num_bytes,
96 offset,
97 path.value().c_str(),
98 strerror(errno));
David Zeuthen8b6973b2016-09-20 12:39:49 -040099 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,
David Zeuthen4b6a6342017-01-03 15:19:56 -0500112 int64_t offset,
113 size_t num_bytes,
David Zeuthen8b6973b2016-09-20 12:39:49 -0400114 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)) {
David Zeuthen4b6a6342017-01-03 15:19:56 -0500121 fprintf(
122 stderr, "Error getting size of file '%s'\n", path.value().c_str());
David Zeuthen8b6973b2016-09-20 12:39:49 -0400123 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) {
David Zeuthen4b6a6342017-01-03 15:19:56 -0500130 fprintf(stderr,
131 "Error opening file '%s': %s\n",
132 path.value().c_str(),
David Zeuthen8b6973b2016-09-20 12:39:49 -0400133 strerror(errno));
David Zeuthena5fd3a42017-02-27 16:38:54 -0500134 if (errno == ENOENT) {
135 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
136 } else {
137 return AVB_IO_RESULT_ERROR_IO;
138 }
David Zeuthen8b6973b2016-09-20 12:39:49 -0400139 }
140 if (lseek(fd, offset, SEEK_SET) != offset) {
David Zeuthen4b6a6342017-01-03 15:19:56 -0500141 fprintf(stderr,
142 "Error seeking to pos %zd in file %s: %s\n",
143 offset,
144 path.value().c_str(),
145 strerror(errno));
David Zeuthen8b6973b2016-09-20 12:39:49 -0400146 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",
David Zeuthen4b6a6342017-01-03 15:19:56 -0500153 num_bytes,
154 offset,
155 path.value().c_str(),
156 strerror(errno));
David Zeuthen8b6973b2016-09-20 12:39:49 -0400157 close(fd);
158 return AVB_IO_RESULT_ERROR_IO;
159 }
160 close(fd);
161
162 return AVB_IO_RESULT_OK;
163}
164
David Zeuthen507752b2016-09-29 16:31:18 -0400165AvbIOResult FakeAvbOps::validate_vbmeta_public_key(
David Zeuthen4b6a6342017-01-03 15:19:56 -0500166 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,
David Zeuthen507752b2016-09-29 16:31:18 -0400171 bool* out_key_is_trusted) {
172 if (out_key_is_trusted != NULL) {
David Zeuthen18666ab2016-11-15 11:18:05 -0500173 bool pk_matches = (public_key_length == expected_public_key_.size() &&
David Zeuthen4b6a6342017-01-03 15:19:56 -0500174 (memcmp(expected_public_key_.c_str(),
175 public_key_data,
David Zeuthen18666ab2016-11-15 11:18:05 -0500176 public_key_length) == 0));
177 bool pkmd_matches =
178 (public_key_metadata_length == expected_public_key_metadata_.size() &&
David Zeuthen4b6a6342017-01-03 15:19:56 -0500179 (memcmp(expected_public_key_metadata_.c_str(),
180 public_key_metadata,
David Zeuthen18666ab2016-11-15 11:18:05 -0500181 public_key_metadata_length) == 0));
182 *out_key_is_trusted = pk_matches && pkmd_matches;
David Zeuthen507752b2016-09-29 16:31:18 -0400183 }
184 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400185}
186
David Zeuthen507752b2016-09-29 16:31:18 -0400187AvbIOResult FakeAvbOps::read_rollback_index(AvbOps* ops,
David Zeuthen40ee1da2016-11-23 15:14:49 -0500188 size_t rollback_index_location,
David Zeuthen507752b2016-09-29 16:31:18 -0400189 uint64_t* out_rollback_index) {
Darren Krahn72d57902016-12-12 18:34:08 -0800190 if (stored_rollback_indexes_.count(rollback_index_location) == 0) {
David Zeuthen4b6a6342017-01-03 15:19:56 -0500191 fprintf(stderr,
192 "No rollback index for location %zd (has %zd locations).\n",
193 rollback_index_location,
194 stored_rollback_indexes_.size());
David Zeuthen507752b2016-09-29 16:31:18 -0400195 return AVB_IO_RESULT_ERROR_IO;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400196 }
David Zeuthen40ee1da2016-11-23 15:14:49 -0500197 *out_rollback_index = stored_rollback_indexes_[rollback_index_location];
David Zeuthen507752b2016-09-29 16:31:18 -0400198 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400199}
200
David Zeuthen507752b2016-09-29 16:31:18 -0400201AvbIOResult FakeAvbOps::write_rollback_index(AvbOps* ops,
David Zeuthen40ee1da2016-11-23 15:14:49 -0500202 size_t rollback_index_location,
David Zeuthen507752b2016-09-29 16:31:18 -0400203 uint64_t rollback_index) {
Darren Krahn72d57902016-12-12 18:34:08 -0800204 if (stored_rollback_indexes_.count(rollback_index_location) == 0) {
David Zeuthen4b6a6342017-01-03 15:19:56 -0500205 fprintf(stderr,
206 "No rollback index for location %zd (has %zd locations).\n",
207 rollback_index_location,
208 stored_rollback_indexes_.size());
David Zeuthen507752b2016-09-29 16:31:18 -0400209 return AVB_IO_RESULT_ERROR_IO;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400210 }
David Zeuthen40ee1da2016-11-23 15:14:49 -0500211 stored_rollback_indexes_[rollback_index_location] = rollback_index;
David Zeuthen507752b2016-09-29 16:31:18 -0400212 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400213}
214
David Zeuthen507752b2016-09-29 16:31:18 -0400215AvbIOResult FakeAvbOps::read_is_device_unlocked(AvbOps* ops,
216 bool* out_is_device_unlocked) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400217 *out_is_device_unlocked = stored_is_device_unlocked_ ? 1 : 0;
David Zeuthen507752b2016-09-29 16:31:18 -0400218 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400219}
220
David Zeuthen507752b2016-09-29 16:31:18 -0400221AvbIOResult FakeAvbOps::get_unique_guid_for_partition(AvbOps* ops,
222 const char* partition,
223 char* guid_buf,
224 size_t guid_buf_size) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400225 // 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);
David Zeuthen507752b2016-09-29 16:31:18 -0400229 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400230}
231
David Zeuthen27a291f2017-04-27 18:18:33 -0400232AvbIOResult 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
Darren Krahn147b08d2016-12-20 16:38:29 -0800247AvbIOResult 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
David Zeuthen8b6973b2016-09-20 12:39:49 -0400267static AvbIOResult my_ops_read_from_partition(AvbOps* ops,
268 const char* partition,
Darren Krahn72d57902016-12-12 18:34:08 -0800269 int64_t offset,
270 size_t num_bytes,
David Zeuthen8b6973b2016-09-20 12:39:49 -0400271 void* buffer,
272 size_t* out_num_read) {
Darren Krahn72d57902016-12-12 18:34:08 -0800273 return FakeAvbOps::GetInstanceFromAvbOps(ops)
274 ->delegate()
275 ->read_from_partition(partition, offset, num_bytes, buffer, out_num_read);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400276}
277
Darren Krahn72d57902016-12-12 18:34:08 -0800278static AvbIOResult my_ops_write_to_partition(AvbOps* ops,
279 const char* partition,
280 int64_t offset,
281 size_t num_bytes,
David Zeuthen8b6973b2016-09-20 12:39:49 -0400282 const void* buffer) {
David Zeuthen4b6a6342017-01-03 15:19:56 -0500283 return FakeAvbOps::GetInstanceFromAvbOps(ops)->delegate()->write_to_partition(
284 partition, offset, num_bytes, buffer);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400285}
286
David Zeuthen507752b2016-09-29 16:31:18 -0400287static AvbIOResult my_ops_validate_vbmeta_public_key(
Darren Krahn72d57902016-12-12 18:34:08 -0800288 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,
David Zeuthen507752b2016-09-29 16:31:18 -0400293 bool* out_key_is_trusted) {
Darren Krahn72d57902016-12-12 18:34:08 -0800294 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);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400302}
303
David Zeuthen507752b2016-09-29 16:31:18 -0400304static AvbIOResult my_ops_read_rollback_index(AvbOps* ops,
David Zeuthen40ee1da2016-11-23 15:14:49 -0500305 size_t rollback_index_location,
David Zeuthen507752b2016-09-29 16:31:18 -0400306 uint64_t* out_rollback_index) {
Darren Krahn72d57902016-12-12 18:34:08 -0800307 return FakeAvbOps::GetInstanceFromAvbOps(ops)
308 ->delegate()
309 ->read_rollback_index(ops, rollback_index_location, out_rollback_index);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400310}
311
David Zeuthen507752b2016-09-29 16:31:18 -0400312static AvbIOResult my_ops_write_rollback_index(AvbOps* ops,
David Zeuthen40ee1da2016-11-23 15:14:49 -0500313 size_t rollback_index_location,
David Zeuthen507752b2016-09-29 16:31:18 -0400314 uint64_t rollback_index) {
Darren Krahn72d57902016-12-12 18:34:08 -0800315 return FakeAvbOps::GetInstanceFromAvbOps(ops)
316 ->delegate()
317 ->write_rollback_index(ops, rollback_index_location, rollback_index);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400318}
319
David Zeuthen507752b2016-09-29 16:31:18 -0400320static AvbIOResult my_ops_read_is_device_unlocked(
321 AvbOps* ops, bool* out_is_device_unlocked) {
Darren Krahn72d57902016-12-12 18:34:08 -0800322 return FakeAvbOps::GetInstanceFromAvbOps(ops)
323 ->delegate()
324 ->read_is_device_unlocked(ops, out_is_device_unlocked);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400325}
326
David Zeuthen507752b2016-09-29 16:31:18 -0400327static AvbIOResult my_ops_get_unique_guid_for_partition(AvbOps* ops,
328 const char* partition,
329 char* guid_buf,
330 size_t guid_buf_size) {
Darren Krahn72d57902016-12-12 18:34:08 -0800331 return FakeAvbOps::GetInstanceFromAvbOps(ops)
332 ->delegate()
333 ->get_unique_guid_for_partition(ops, partition, guid_buf, guid_buf_size);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400334}
335
David Zeuthen27a291f2017-04-27 18:18:33 -0400336static 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
Darren Krahn147b08d2016-12-20 16:38:29 -0800344static 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
David Zeuthen8b6973b2016-09-20 12:39:49 -0400358FakeAvbOps::FakeAvbOps() {
David Zeuthen574ed992017-01-05 15:43:11 -0500359 avb_ops_.ab_ops = &avb_ab_ops_;
Darren Krahn147b08d2016-12-20 16:38:29 -0800360 avb_ops_.atx_ops = &avb_atx_ops_;
David Zeuthen574ed992017-01-05 15:43:11 -0500361 avb_ops_.user_data = this;
Darren Krahn72d57902016-12-12 18:34:08 -0800362 avb_ops_.read_from_partition = my_ops_read_from_partition;
363 avb_ops_.write_to_partition = my_ops_write_to_partition;
David Zeuthen4b6a6342017-01-03 15:19:56 -0500364 avb_ops_.validate_vbmeta_public_key = my_ops_validate_vbmeta_public_key;
Darren Krahn72d57902016-12-12 18:34:08 -0800365 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;
David Zeuthen4b6a6342017-01-03 15:19:56 -0500368 avb_ops_.get_unique_guid_for_partition = my_ops_get_unique_guid_for_partition;
David Zeuthen27a291f2017-04-27 18:18:33 -0400369 avb_ops_.get_size_of_partition = my_ops_get_size_of_partition;
Darren Krahn72d57902016-12-12 18:34:08 -0800370
David Zeuthen4cc96522016-10-28 15:22:42 -0400371 // Just use the built-in A/B metadata read/write routines.
David Zeuthen574ed992017-01-05 15:43:11 -0500372 avb_ab_ops_.ops = &avb_ops_;
Darren Krahn72d57902016-12-12 18:34:08 -0800373 avb_ab_ops_.read_ab_metadata = avb_ab_data_read;
374 avb_ab_ops_.write_ab_metadata = avb_ab_data_write;
375
Darren Krahn147b08d2016-12-20 16:38:29 -0800376 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
Darren Krahn72d57902016-12-12 18:34:08 -0800381 delegate_ = this;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400382}
383
Darren Krahn72d57902016-12-12 18:34:08 -0800384FakeAvbOps::~FakeAvbOps() {}
385
Darren Krahn72d57902016-12-12 18:34:08 -0800386} // namespace avb