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