• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
44 namespace avb {
45 
get_partition_names_read_from()46 std::set<std::string> FakeAvbOps::get_partition_names_read_from() {
47   return partition_names_read_from_;
48 }
49 
read_from_partition(const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)50 AvbIOResult 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 
write_to_partition(const char * partition,int64_t offset,size_t num_bytes,const void * buffer)111 AvbIOResult 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 
validate_vbmeta_public_key(AvbOps * ops,const uint8_t * public_key_data,size_t public_key_length,const uint8_t * public_key_metadata,size_t public_key_metadata_length,bool * out_key_is_trusted)165 AvbIOResult 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 
read_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t * out_rollback_index)187 AvbIOResult 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 
write_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t rollback_index)201 AvbIOResult 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 
read_is_device_unlocked(AvbOps * ops,bool * out_is_device_unlocked)215 AvbIOResult 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 
get_unique_guid_for_partition(AvbOps * ops,const char * partition,char * guid_buf,size_t guid_buf_size)221 AvbIOResult 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 
get_size_of_partition(AvbOps * ops,const char * partition,uint64_t * out_size)232 AvbIOResult 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 
read_permanent_attributes(AvbAtxPermanentAttributes * attributes)247 AvbIOResult FakeAvbOps::read_permanent_attributes(
248     AvbAtxPermanentAttributes* attributes) {
249   *attributes = permanent_attributes_;
250   return AVB_IO_RESULT_OK;
251 }
252 
read_permanent_attributes_hash(uint8_t hash[AVB_SHA256_DIGEST_SIZE])253 AvbIOResult 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 
my_ops_read_from_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)267 static 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 
my_ops_write_to_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,const void * buffer)278 static 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 
my_ops_validate_vbmeta_public_key(AvbOps * ops,const uint8_t * public_key_data,size_t public_key_length,const uint8_t * public_key_metadata,size_t public_key_metadata_length,bool * out_key_is_trusted)287 static 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 
my_ops_read_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t * out_rollback_index)304 static 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 
my_ops_write_rollback_index(AvbOps * ops,size_t rollback_index_location,uint64_t rollback_index)312 static 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 
my_ops_read_is_device_unlocked(AvbOps * ops,bool * out_is_device_unlocked)320 static 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 
my_ops_get_unique_guid_for_partition(AvbOps * ops,const char * partition,char * guid_buf,size_t guid_buf_size)327 static 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 
my_ops_get_size_of_partition(AvbOps * ops,const char * partition,uint64_t * out_size)336 static 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 
my_ops_read_permanent_attributes(AvbAtxOps * atx_ops,AvbAtxPermanentAttributes * attributes)344 static 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 
my_ops_read_permanent_attributes_hash(AvbAtxOps * atx_ops,uint8_t hash[AVB_SHA256_DIGEST_SIZE])351 static 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 
FakeAvbOps()358 FakeAvbOps::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 
~FakeAvbOps()384 FakeAvbOps::~FakeAvbOps() {}
385 
386 }  // namespace avb
387