Commit af28e08a9b96267c1e70cf8713b20bbff04892da
Committed by
zhang sanshan
1 parent
6471b146da
Exists in
smarc-imx_v2017.03_o8.1.0_1.3.0_8m
and in
1 other branch
MA-11362 [Android] Update AVB lib in u-boot
This commit did: 1. Sync the AVB lib with external/avb with commit head: commit 8a8103513dea5c47037200beabad2a307f09ecc8 Merge: 2ee8dbe 852858e Author: David Zeuthen <zeuthen@google.com> Date: Fri Jun 30 16:08:03 2017 +0000 Revert "avbtool: Avoid using $(ANDROID_VERITY_MODE) for now." am: 1b2f7a64e2 am: 852858e2ed 2. Fix build error and implement ops function fsl_get_size_of_partition(). Change-Id: I3d1a04c320b8ea89e9fe28124cf866bd62282e78 Signed-off-by: Luo Ji <ji.luo@nxp.com>
Showing 13 changed files with 762 additions and 312 deletions Side-by-side Diff
- drivers/usb/gadget/f_fastboot.c
- include/fsl_avb.h
- lib/avb/fsl/fsl_avb.c
- lib/avb/libavb/avb_crc32.c
- lib/avb/libavb/avb_ops.h
- lib/avb/libavb/avb_rsa.c
- lib/avb/libavb/avb_slot_verify.c
- lib/avb/libavb/avb_slot_verify.h
- lib/avb/libavb/avb_sysdeps.h
- lib/avb/libavb/avb_vbmeta_image.h
- lib/avb/libavb/avb_version.h
- lib/avb/libavb_ab/avb_ab_flow.c
- lib/avb/libavb_ab/avb_ab_flow.h
drivers/usb/gadget/f_fastboot.c
... | ... | @@ -1304,7 +1304,8 @@ |
1304 | 1304 | .read_rollback_index = fsl_read_rollback_index_rpmb, |
1305 | 1305 | .write_rollback_index = fsl_write_rollback_index_rpmb, |
1306 | 1306 | .read_is_device_unlocked = fsl_read_is_device_unlocked, |
1307 | - .get_unique_guid_for_partition = fsl_get_unique_guid_for_partition | |
1307 | + .get_unique_guid_for_partition = fsl_get_unique_guid_for_partition, | |
1308 | + .get_size_of_partition = fsl_get_size_of_partition | |
1308 | 1309 | }; |
1309 | 1310 | #endif |
1310 | 1311 | |
... | ... | @@ -1555,7 +1556,8 @@ |
1555 | 1556 | bool allow_fail = (lock_status == FASTBOOT_UNLOCK ? true : false); |
1556 | 1557 | avb_metric = get_timer(0); |
1557 | 1558 | /* if in lock state, do avb verify */ |
1558 | - avb_result = avb_ab_flow_fast(&fsl_avb_ab_ops, requested_partitions, allow_fail, &avb_out_data); | |
1559 | + avb_result = avb_ab_flow_fast(&fsl_avb_ab_ops, requested_partitions, allow_fail, | |
1560 | + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &avb_out_data); | |
1559 | 1561 | /* get the duration of avb */ |
1560 | 1562 | metrics.avb = get_timer(avb_metric); |
1561 | 1563 |
include/fsl_avb.h
... | ... | @@ -139,6 +139,14 @@ |
139 | 139 | char* guid_buf, |
140 | 140 | size_t guid_buf_size); |
141 | 141 | |
142 | +/* Gets the size of a partition with the name in |partition| | |
143 | + * (NUL-terminated UTF-8 string). Returns the value in | |
144 | + * |out_size_num_bytes|. | |
145 | + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. | |
146 | + */ | |
147 | +AvbIOResult fsl_get_size_of_partition(AvbOps* ops, | |
148 | + const char* partition, | |
149 | + uint64_t* out_size_num_bytes); | |
142 | 150 | /* check if the fastboot getvar cmd is for query [avb] bootctl's slot var |
143 | 151 | * cmd is the fastboot getvar's cmd in |
144 | 152 | * return true if it is a bootctl related cmd, false if it's not. |
lib/avb/fsl/fsl_avb.c
... | ... | @@ -410,5 +410,24 @@ |
410 | 410 | #else |
411 | 411 | return AVB_IO_RESULT_ERROR_IO; |
412 | 412 | #endif |
413 | + | |
414 | +} | |
415 | +/* Gets the size of a partition with the name in |partition| | |
416 | + * (NUL-terminated UTF-8 string). Returns the value in | |
417 | + * |out_size_num_bytes|. | |
418 | + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. | |
419 | + */ | |
420 | +AvbIOResult fsl_get_size_of_partition(AvbOps* ops, | |
421 | + const char* partition, | |
422 | + uint64_t* out_size_num_bytes) | |
423 | +{ | |
424 | + struct fastboot_ptentry *pte; | |
425 | + pte = fastboot_flash_find_ptn(partition); | |
426 | + if (!pte) { | |
427 | + ERR("no %s partition\n", partition); | |
428 | + return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; | |
429 | + } | |
430 | + *out_size_num_bytes = (uint64_t)(pte->length * 512); | |
431 | + return AVB_IO_RESULT_OK; | |
413 | 432 | } |
lib/avb/libavb/avb_crc32.c
... | ... | @@ -43,10 +43,11 @@ |
43 | 43 | */ |
44 | 44 | |
45 | 45 | #include "avb_sysdeps.h" |
46 | +#include "avb_util.h" | |
46 | 47 | |
47 | 48 | /* Code taken from FreeBSD 8 */ |
48 | 49 | |
49 | -static uint32_t crc32_tab[] = { | |
50 | +static uint32_t iavb_crc32_tab[] = { | |
50 | 51 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, |
51 | 52 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, |
52 | 53 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, |
53 | 54 | |
54 | 55 | |
... | ... | @@ -98,17 +99,17 @@ |
98 | 99 | * in sys/libkern.h, where it can be inlined. |
99 | 100 | */ |
100 | 101 | |
101 | -static uint32_t _crc32(uint32_t crc_in, const uint8_t* buf, int size) { | |
102 | +static uint32_t iavb_crc32(uint32_t crc_in, const uint8_t* buf, int size) { | |
102 | 103 | const uint8_t* p = buf; |
103 | 104 | uint32_t crc; |
104 | 105 | |
105 | 106 | crc = crc_in ^ ~0U; |
106 | 107 | while (size--) |
107 | - crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); | |
108 | + crc = iavb_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); | |
108 | 109 | return crc ^ ~0U; |
109 | 110 | } |
110 | 111 | |
111 | 112 | uint32_t avb_crc32(const uint8_t* buf, size_t size) { |
112 | - return _crc32(0, buf, size); | |
113 | + return iavb_crc32(0, buf, size); | |
113 | 114 | } |
lib/avb/libavb/avb_ops.h
... | ... | @@ -71,6 +71,10 @@ |
71 | 71 | |
72 | 72 | /* High-level operations/functions/methods that are platform |
73 | 73 | * dependent. |
74 | + * | |
75 | + * Operations may be added in the future so when implementing it | |
76 | + * always make sure to zero out sizeof(AvbOps) bytes of the struct to | |
77 | + * ensure that unimplemented operations are set to NULL. | |
74 | 78 | */ |
75 | 79 | struct AvbOps { |
76 | 80 | /* This pointer can be used by the application/bootloader using |
... | ... | @@ -205,6 +209,16 @@ |
205 | 209 | const char* partition, |
206 | 210 | char* guid_buf, |
207 | 211 | size_t guid_buf_size); |
212 | + | |
213 | + /* Gets the size of a partition with the name in |partition| | |
214 | + * (NUL-terminated UTF-8 string). Returns the value in | |
215 | + * |out_size_num_bytes|. | |
216 | + * | |
217 | + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. | |
218 | + */ | |
219 | + AvbIOResult (*get_size_of_partition)(AvbOps* ops, | |
220 | + const char* partition, | |
221 | + uint64_t* out_size_num_bytes); | |
208 | 222 | }; |
209 | 223 | |
210 | 224 | #ifdef __cplusplus |
lib/avb/libavb/avb_rsa.c
... | ... | @@ -37,16 +37,16 @@ |
37 | 37 | #include "avb_util.h" |
38 | 38 | #include "avb_vbmeta_image.h" |
39 | 39 | |
40 | -typedef struct Key { | |
40 | +typedef struct IAvbKey { | |
41 | 41 | unsigned int len; /* Length of n[] in number of uint32_t */ |
42 | 42 | uint32_t n0inv; /* -1 / n[0] mod 2^32 */ |
43 | 43 | uint32_t* n; /* modulus as array (host-byte order) */ |
44 | 44 | uint32_t* rr; /* R^2 as array (host-byte order) */ |
45 | -} Key; | |
45 | +} IAvbKey; | |
46 | 46 | |
47 | -Key* parse_key_data(const uint8_t* data, size_t length) { | |
47 | +static IAvbKey* iavb_parse_key_data(const uint8_t* data, size_t length) { | |
48 | 48 | AvbRSAPublicKeyHeader h; |
49 | - Key* key = NULL; | |
49 | + IAvbKey* key = NULL; | |
50 | 50 | size_t expected_length; |
51 | 51 | unsigned int i; |
52 | 52 | const uint8_t* n; |
53 | 53 | |
... | ... | @@ -76,14 +76,14 @@ |
76 | 76 | /* Store n and rr following the key header so we only have to do one |
77 | 77 | * allocation. |
78 | 78 | */ |
79 | - key = (Key*)(avb_malloc(sizeof(Key) + 2 * h.key_num_bits / 8)); | |
79 | + key = (IAvbKey*)(avb_malloc(sizeof(IAvbKey) + 2 * h.key_num_bits / 8)); | |
80 | 80 | if (key == NULL) { |
81 | 81 | goto fail; |
82 | 82 | } |
83 | 83 | |
84 | 84 | key->len = h.key_num_bits / 32; |
85 | 85 | key->n0inv = h.n0inv; |
86 | - key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(Key) bytes. */ | |
86 | + key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(IAvbKey) bytes. */ | |
87 | 87 | key->rr = key->n + key->len; |
88 | 88 | |
89 | 89 | /* Crypto-code below (modpowF4() and friends) expects the key in |
90 | 90 | |
... | ... | @@ -103,12 +103,12 @@ |
103 | 103 | return NULL; |
104 | 104 | } |
105 | 105 | |
106 | -void free_parsed_key(Key* key) { | |
106 | +static void iavb_free_parsed_key(IAvbKey* key) { | |
107 | 107 | avb_free(key); |
108 | 108 | } |
109 | 109 | |
110 | 110 | /* a[] -= mod */ |
111 | -static void subM(const Key* key, uint32_t* a) { | |
111 | +static void subM(const IAvbKey* key, uint32_t* a) { | |
112 | 112 | int64_t A = 0; |
113 | 113 | uint32_t i; |
114 | 114 | for (i = 0; i < key->len; ++i) { |
... | ... | @@ -119,7 +119,7 @@ |
119 | 119 | } |
120 | 120 | |
121 | 121 | /* return a[] >= mod */ |
122 | -static int geM(const Key* key, uint32_t* a) { | |
122 | +static int geM(const IAvbKey* key, uint32_t* a) { | |
123 | 123 | uint32_t i; |
124 | 124 | for (i = key->len; i;) { |
125 | 125 | --i; |
... | ... | @@ -134,7 +134,7 @@ |
134 | 134 | } |
135 | 135 | |
136 | 136 | /* montgomery c[] += a * b[] / R % mod */ |
137 | -static void montMulAdd(const Key* key, | |
137 | +static void montMulAdd(const IAvbKey* key, | |
138 | 138 | uint32_t* c, |
139 | 139 | const uint32_t a, |
140 | 140 | const uint32_t* b) { |
... | ... | @@ -159,7 +159,7 @@ |
159 | 159 | } |
160 | 160 | |
161 | 161 | /* montgomery c[] = a[] * b[] / R % mod */ |
162 | -static void montMul(const Key* key, uint32_t* c, uint32_t* a, uint32_t* b) { | |
162 | +static void montMul(const IAvbKey* key, uint32_t* c, uint32_t* a, uint32_t* b) { | |
163 | 163 | uint32_t i; |
164 | 164 | for (i = 0; i < key->len; ++i) { |
165 | 165 | c[i] = 0; |
... | ... | @@ -172,7 +172,7 @@ |
172 | 172 | /* In-place public exponentiation. (65537} |
173 | 173 | * Input and output big-endian byte array in inout. |
174 | 174 | */ |
175 | -static void modpowF4(const Key* key, uint8_t* inout) { | |
175 | +static void modpowF4(const IAvbKey* key, uint8_t* inout) { | |
176 | 176 | uint32_t* a = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t)); |
177 | 177 | uint32_t* aR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t)); |
178 | 178 | uint32_t* aaR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t)); |
... | ... | @@ -237,7 +237,7 @@ |
237 | 237 | const uint8_t* padding, |
238 | 238 | size_t padding_num_bytes) { |
239 | 239 | uint8_t* buf = NULL; |
240 | - Key* parsed_key = NULL; | |
240 | + IAvbKey* parsed_key = NULL; | |
241 | 241 | bool success = false; |
242 | 242 | |
243 | 243 | if (key == NULL || sig == NULL || hash == NULL || padding == NULL) { |
... | ... | @@ -245,7 +245,7 @@ |
245 | 245 | goto out; |
246 | 246 | } |
247 | 247 | |
248 | - parsed_key = parse_key_data(key, key_num_bytes); | |
248 | + parsed_key = iavb_parse_key_data(key, key_num_bytes); | |
249 | 249 | if (parsed_key == NULL) { |
250 | 250 | avb_error("Error parsing key.\n"); |
251 | 251 | goto out; |
... | ... | @@ -290,7 +290,7 @@ |
290 | 290 | |
291 | 291 | out: |
292 | 292 | if (parsed_key != NULL) { |
293 | - free_parsed_key(parsed_key); | |
293 | + iavb_free_parsed_key(parsed_key); | |
294 | 294 | } |
295 | 295 | if (buf != NULL) { |
296 | 296 | avb_free(buf); |
lib/avb/libavb/avb_slot_verify.c
... | ... | @@ -58,6 +58,7 @@ |
58 | 58 | case AVB_SLOT_VERIFY_RESULT_ERROR_IO: |
59 | 59 | case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: |
60 | 60 | case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: |
61 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: | |
61 | 62 | return false; |
62 | 63 | |
63 | 64 | case AVB_SLOT_VERIFY_RESULT_OK: |
... | ... | @@ -91,6 +92,7 @@ |
91 | 92 | uint8_t* digest; |
92 | 93 | size_t digest_len; |
93 | 94 | const char* found; |
95 | + uint64_t image_size; | |
94 | 96 | |
95 | 97 | if (!avb_hash_descriptor_validate_and_byteswap( |
96 | 98 | (const AvbHashDescriptor*)descriptor, &hash_desc)) { |
... | ... | @@ -109,6 +111,17 @@ |
109 | 111 | goto out; |
110 | 112 | } |
111 | 113 | |
114 | + /* Don't bother loading or validating unless the partition was | |
115 | + * requested in the first place. | |
116 | + */ | |
117 | + found = avb_strv_find_str(requested_partitions, | |
118 | + (const char*)desc_partition_name, | |
119 | + hash_desc.partition_name_len); | |
120 | + if (found == NULL) { | |
121 | + ret = AVB_SLOT_VERIFY_RESULT_OK; | |
122 | + goto out; | |
123 | + } | |
124 | + | |
112 | 125 | if (!avb_str_concat(part_name, |
113 | 126 | sizeof part_name, |
114 | 127 | (const char*)desc_partition_name, |
... | ... | @@ -120,6 +133,36 @@ |
120 | 133 | goto out; |
121 | 134 | } |
122 | 135 | |
136 | + /* If we're allowing verification errors then hash_desc.image_size | |
137 | + * may no longer match what's in the partition... so in this case | |
138 | + * just load the entire partition. | |
139 | + * | |
140 | + * For example, this can happen if a developer does 'fastboot flash | |
141 | + * boot /path/to/new/and/bigger/boot.img'. We want this to work | |
142 | + * since it's such a common workflow. | |
143 | + */ | |
144 | + image_size = hash_desc.image_size; | |
145 | + if (allow_verification_error) { | |
146 | + if (ops->get_size_of_partition == NULL) { | |
147 | + avb_errorv(part_name, | |
148 | + ": The get_size_of_partition() operation is " | |
149 | + "not implemented so we may not load the entire partition. " | |
150 | + "Please implement.", | |
151 | + NULL); | |
152 | + } else { | |
153 | + io_ret = ops->get_size_of_partition(ops, part_name, &image_size); | |
154 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
155 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
156 | + goto out; | |
157 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
158 | + avb_errorv(part_name, ": Error determining partition size.\n", NULL); | |
159 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
160 | + goto out; | |
161 | + } | |
162 | + avb_debugv(part_name, ": Loading entire partition.\n", NULL); | |
163 | + } | |
164 | + } | |
165 | + | |
123 | 166 | /* If we are going to load bootimage, load it to |
124 | 167 | * hdr->kernel_addr - hdr->page_size address directly, |
125 | 168 | * so we don't need to copy it again!*/ |
... | ... | @@ -152,12 +195,8 @@ |
152 | 195 | } |
153 | 196 | } |
154 | 197 | |
155 | - io_ret = ops->read_from_partition(ops, | |
156 | - part_name, | |
157 | - 0 /* offset */, | |
158 | - hash_desc.image_size, | |
159 | - image_buf, | |
160 | - &part_num_read); | |
198 | + io_ret = ops->read_from_partition( | |
199 | + ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read); | |
161 | 200 | if (io_ret == AVB_IO_RESULT_ERROR_OOM) { |
162 | 201 | ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; |
163 | 202 | goto out; |
... | ... | @@ -166,7 +205,7 @@ |
166 | 205 | ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; |
167 | 206 | goto out; |
168 | 207 | } |
169 | - if (part_num_read != hash_desc.image_size) { | |
208 | + if (part_num_read != image_size) { | |
170 | 209 | avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL); |
171 | 210 | ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; |
172 | 211 | goto out; |
173 | 212 | |
... | ... | @@ -211,25 +250,21 @@ |
211 | 250 | |
212 | 251 | out: |
213 | 252 | |
214 | - if (ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) { | |
215 | - /* If this is the requested partition, copy to slot_data. */ | |
216 | - found = avb_strv_find_str(requested_partitions, | |
217 | - (const char*)desc_partition_name, | |
218 | - hash_desc.partition_name_len); | |
219 | - if (found != NULL) { | |
220 | - AvbPartitionData* loaded_partition; | |
221 | - if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) { | |
222 | - avb_errorv(part_name, ": Too many loaded partitions.\n", NULL); | |
223 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
224 | - goto fail; | |
225 | - } | |
226 | - loaded_partition = | |
227 | - &slot_data->loaded_partitions[slot_data->num_loaded_partitions++]; | |
228 | - loaded_partition->partition_name = avb_strdup(found); | |
229 | - loaded_partition->data_size = hash_desc.image_size; | |
230 | - loaded_partition->data = image_buf; | |
231 | - image_buf = NULL; | |
253 | + /* If it worked and something was loaded, copy to slot_data. */ | |
254 | + if ((ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) && | |
255 | + image_buf != NULL) { | |
256 | + AvbPartitionData* loaded_partition; | |
257 | + if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) { | |
258 | + avb_errorv(part_name, ": Too many loaded partitions.\n", NULL); | |
259 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
260 | + goto fail; | |
232 | 261 | } |
262 | + loaded_partition = | |
263 | + &slot_data->loaded_partitions[slot_data->num_loaded_partitions++]; | |
264 | + loaded_partition->partition_name = avb_strdup(found); | |
265 | + loaded_partition->data_size = image_size; | |
266 | + loaded_partition->data = image_buf; | |
267 | + image_buf = NULL; | |
233 | 268 | } |
234 | 269 | |
235 | 270 | fail: |
... | ... | @@ -239,6 +274,99 @@ |
239 | 274 | return ret; |
240 | 275 | } |
241 | 276 | |
277 | +static AvbSlotVerifyResult load_requested_partitions( | |
278 | + AvbOps* ops, | |
279 | + const char* const* requested_partitions, | |
280 | + const char* ab_suffix, | |
281 | + AvbSlotVerifyData* slot_data) { | |
282 | + AvbSlotVerifyResult ret; | |
283 | + uint8_t* image_buf = NULL; | |
284 | + size_t n; | |
285 | + | |
286 | + if (ops->get_size_of_partition == NULL) { | |
287 | + avb_error("get_size_of_partition() not implemented.\n"); | |
288 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT; | |
289 | + goto out; | |
290 | + } | |
291 | + | |
292 | + for (n = 0; requested_partitions[n] != NULL; n++) { | |
293 | + char part_name[PART_NAME_MAX_SIZE]; | |
294 | + AvbIOResult io_ret; | |
295 | + uint64_t image_size; | |
296 | + size_t part_num_read; | |
297 | + AvbPartitionData* loaded_partition; | |
298 | + | |
299 | + if (!avb_str_concat(part_name, | |
300 | + sizeof part_name, | |
301 | + requested_partitions[n], | |
302 | + avb_strlen(requested_partitions[n]), | |
303 | + ab_suffix, | |
304 | + avb_strlen(ab_suffix))) { | |
305 | + avb_error("Partition name and suffix does not fit.\n"); | |
306 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
307 | + goto out; | |
308 | + } | |
309 | + | |
310 | + io_ret = ops->get_size_of_partition(ops, part_name, &image_size); | |
311 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
312 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
313 | + goto out; | |
314 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
315 | + avb_errorv(part_name, ": Error determining partition size.\n", NULL); | |
316 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
317 | + goto out; | |
318 | + } | |
319 | + avb_debugv(part_name, ": Loading entire partition.\n", NULL); | |
320 | + | |
321 | + image_buf = avb_malloc(image_size); | |
322 | + if (image_buf == NULL) { | |
323 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
324 | + goto out; | |
325 | + } | |
326 | + | |
327 | + io_ret = ops->read_from_partition( | |
328 | + ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read); | |
329 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
330 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
331 | + goto out; | |
332 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
333 | + avb_errorv(part_name, ": Error loading data from partition.\n", NULL); | |
334 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
335 | + goto out; | |
336 | + } | |
337 | + if (part_num_read != image_size) { | |
338 | + avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL); | |
339 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
340 | + goto out; | |
341 | + } | |
342 | + | |
343 | + /* Move to slot_data. */ | |
344 | + if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) { | |
345 | + avb_errorv(part_name, ": Too many loaded partitions.\n", NULL); | |
346 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
347 | + goto out; | |
348 | + } | |
349 | + loaded_partition = | |
350 | + &slot_data->loaded_partitions[slot_data->num_loaded_partitions++]; | |
351 | + loaded_partition->partition_name = avb_strdup(requested_partitions[n]); | |
352 | + if (loaded_partition->partition_name == NULL) { | |
353 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
354 | + goto out; | |
355 | + } | |
356 | + loaded_partition->data_size = image_size; | |
357 | + loaded_partition->data = image_buf; | |
358 | + image_buf = NULL; | |
359 | + } | |
360 | + | |
361 | + ret = AVB_SLOT_VERIFY_RESULT_OK; | |
362 | + | |
363 | +out: | |
364 | + if (image_buf != NULL) { | |
365 | + avb_free(image_buf); | |
366 | + } | |
367 | + return ret; | |
368 | +} | |
369 | + | |
242 | 370 | static AvbSlotVerifyResult load_and_verify_vbmeta( |
243 | 371 | AvbOps* ops, |
244 | 372 | const char* const* requested_partitions, |
... | ... | @@ -471,7 +599,7 @@ |
471 | 599 | } |
472 | 600 | } |
473 | 601 | } else { |
474 | - bool key_is_trusted = true; | |
602 | + bool key_is_trusted = false; | |
475 | 603 | const uint8_t* pk_metadata = NULL; |
476 | 604 | size_t pk_metadata_len = 0; |
477 | 605 | |
... | ... | @@ -556,6 +684,27 @@ |
556 | 684 | vbmeta_header.auxiliary_data_block_size; |
557 | 685 | vbmeta_image_data->verify_result = vbmeta_ret; |
558 | 686 | |
687 | + /* If verification has been disabled by setting a bit in the image, | |
688 | + * we're done... except that we need to load the entirety of the | |
689 | + * requested partitions. | |
690 | + */ | |
691 | + if (vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) { | |
692 | + AvbSlotVerifyResult sub_ret; | |
693 | + avb_debugv( | |
694 | + full_partition_name, ": VERIFICATION_DISABLED bit is set.\n", NULL); | |
695 | + /* If load_requested_partitions() fail it is always a fatal | |
696 | + * failure (e.g. ERROR_INVALID_ARGUMENT, ERROR_OOM, etc.) rather | |
697 | + * than recoverable (e.g. one where result_should_continue() | |
698 | + * returns true) and we want to convey that error. | |
699 | + */ | |
700 | + sub_ret = load_requested_partitions( | |
701 | + ops, requested_partitions, ab_suffix, slot_data); | |
702 | + if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { | |
703 | + ret = sub_ret; | |
704 | + } | |
705 | + goto out; | |
706 | + } | |
707 | + | |
559 | 708 | /* Now go through all descriptors and take the appropriate action: |
560 | 709 | * |
561 | 710 | * - hash descriptor: Load data from partition, calculate hash, and |
562 | 711 | |
563 | 712 | |
564 | 713 | |
565 | 714 | |
566 | 715 | |
... | ... | @@ -949,21 +1098,208 @@ |
949 | 1098 | return ret; |
950 | 1099 | } |
951 | 1100 | |
1101 | +static AvbSlotVerifyResult append_options( | |
1102 | + AvbOps* ops, | |
1103 | + AvbSlotVerifyData* slot_data, | |
1104 | + AvbVBMetaImageHeader* toplevel_vbmeta, | |
1105 | + AvbAlgorithmType algorithm_type, | |
1106 | + AvbHashtreeErrorMode hashtree_error_mode) { | |
1107 | + AvbSlotVerifyResult ret; | |
1108 | + const char* verity_mode = "enforcing"; | |
1109 | + bool is_device_unlocked; | |
1110 | + AvbIOResult io_ret; | |
1111 | + | |
1112 | + /* Add androidboot.vbmeta.device option. */ | |
1113 | + if (!cmdline_append_option(slot_data, | |
1114 | + "androidboot.vbmeta.device", | |
1115 | + "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { | |
1116 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1117 | + goto out; | |
1118 | + } | |
1119 | + | |
1120 | + /* Add androidboot.vbmeta.avb_version option. */ | |
1121 | + if (!cmdline_append_version(slot_data, | |
1122 | + "androidboot.vbmeta.avb_version", | |
1123 | + AVB_VERSION_MAJOR, | |
1124 | + AVB_VERSION_MINOR)) { | |
1125 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1126 | + goto out; | |
1127 | + } | |
1128 | + | |
1129 | + /* Set androidboot.avb.device_state to "locked" or "unlocked". */ | |
1130 | + io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); | |
1131 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
1132 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1133 | + goto out; | |
1134 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
1135 | + avb_error("Error getting device state.\n"); | |
1136 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
1137 | + goto out; | |
1138 | + } | |
1139 | + if (!cmdline_append_option(slot_data, | |
1140 | + "androidboot.vbmeta.device_state", | |
1141 | + is_device_unlocked ? "unlocked" : "locked")) { | |
1142 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1143 | + goto out; | |
1144 | + } | |
1145 | + | |
1146 | + /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash | |
1147 | + * function as is used to sign vbmeta. | |
1148 | + */ | |
1149 | + switch (algorithm_type) { | |
1150 | + /* Explicit fallthrough. */ | |
1151 | + case AVB_ALGORITHM_TYPE_NONE: | |
1152 | + case AVB_ALGORITHM_TYPE_SHA256_RSA2048: | |
1153 | + case AVB_ALGORITHM_TYPE_SHA256_RSA4096: | |
1154 | + case AVB_ALGORITHM_TYPE_SHA256_RSA8192: { | |
1155 | + AvbSHA256Ctx ctx; | |
1156 | + size_t n, total_size = 0; | |
1157 | + avb_sha256_init(&ctx); | |
1158 | + for (n = 0; n < slot_data->num_vbmeta_images; n++) { | |
1159 | + avb_sha256_update(&ctx, | |
1160 | + slot_data->vbmeta_images[n].vbmeta_data, | |
1161 | + slot_data->vbmeta_images[n].vbmeta_size); | |
1162 | + total_size += slot_data->vbmeta_images[n].vbmeta_size; | |
1163 | + } | |
1164 | + if (!cmdline_append_option( | |
1165 | + slot_data, "androidboot.vbmeta.hash_alg", "sha256") || | |
1166 | + !cmdline_append_uint64_base10( | |
1167 | + slot_data, "androidboot.vbmeta.size", total_size) || | |
1168 | + !cmdline_append_hex(slot_data, | |
1169 | + "androidboot.vbmeta.digest", | |
1170 | + avb_sha256_final(&ctx), | |
1171 | + AVB_SHA256_DIGEST_SIZE)) { | |
1172 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1173 | + goto out; | |
1174 | + } | |
1175 | + } break; | |
1176 | + /* Explicit fallthrough. */ | |
1177 | + case AVB_ALGORITHM_TYPE_SHA512_RSA2048: | |
1178 | + case AVB_ALGORITHM_TYPE_SHA512_RSA4096: | |
1179 | + case AVB_ALGORITHM_TYPE_SHA512_RSA8192: { | |
1180 | + AvbSHA512Ctx ctx; | |
1181 | + size_t n, total_size = 0; | |
1182 | + avb_sha512_init(&ctx); | |
1183 | + for (n = 0; n < slot_data->num_vbmeta_images; n++) { | |
1184 | + avb_sha512_update(&ctx, | |
1185 | + slot_data->vbmeta_images[n].vbmeta_data, | |
1186 | + slot_data->vbmeta_images[n].vbmeta_size); | |
1187 | + total_size += slot_data->vbmeta_images[n].vbmeta_size; | |
1188 | + } | |
1189 | + if (!cmdline_append_option( | |
1190 | + slot_data, "androidboot.vbmeta.hash_alg", "sha512") || | |
1191 | + !cmdline_append_uint64_base10( | |
1192 | + slot_data, "androidboot.vbmeta.size", total_size) || | |
1193 | + !cmdline_append_hex(slot_data, | |
1194 | + "androidboot.vbmeta.digest", | |
1195 | + avb_sha512_final(&ctx), | |
1196 | + AVB_SHA512_DIGEST_SIZE)) { | |
1197 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1198 | + goto out; | |
1199 | + } | |
1200 | + } break; | |
1201 | + case _AVB_ALGORITHM_NUM_TYPES: | |
1202 | + avb_assert_not_reached(); | |
1203 | + break; | |
1204 | + } | |
1205 | + | |
1206 | + /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */ | |
1207 | + if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) { | |
1208 | + verity_mode = "disabled"; | |
1209 | + } else { | |
1210 | + const char* dm_verity_mode = "restart_on_corruption"; | |
1211 | + char* new_ret; | |
1212 | + | |
1213 | + switch (hashtree_error_mode) { | |
1214 | + case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE: | |
1215 | + if (!cmdline_append_option( | |
1216 | + slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) { | |
1217 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1218 | + goto out; | |
1219 | + } | |
1220 | + verity_mode = "enforcing"; | |
1221 | + dm_verity_mode = "restart_on_corruption"; | |
1222 | + break; | |
1223 | + case AVB_HASHTREE_ERROR_MODE_RESTART: | |
1224 | + verity_mode = "enforcing"; | |
1225 | + dm_verity_mode = "restart_on_corruption"; | |
1226 | + break; | |
1227 | + case AVB_HASHTREE_ERROR_MODE_EIO: | |
1228 | + verity_mode = "eio"; | |
1229 | + /* For now there's no option to specify the EIO mode. So | |
1230 | + * just use 'ignore_zero_blocks' since that's already set | |
1231 | + * and dm-verity-target.c supports specifying this multiple | |
1232 | + * times. | |
1233 | + */ | |
1234 | + dm_verity_mode = "ignore_zero_blocks"; | |
1235 | + break; | |
1236 | + case AVB_HASHTREE_ERROR_MODE_LOGGING: | |
1237 | + verity_mode = "logging"; | |
1238 | + dm_verity_mode = "ignore_corruption"; | |
1239 | + break; | |
1240 | + } | |
1241 | + new_ret = avb_replace( | |
1242 | + slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode); | |
1243 | + avb_free(slot_data->cmdline); | |
1244 | + slot_data->cmdline = new_ret; | |
1245 | + if (slot_data->cmdline == NULL) { | |
1246 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1247 | + goto out; | |
1248 | + } | |
1249 | + } | |
1250 | + if (!cmdline_append_option( | |
1251 | + slot_data, "androidboot.veritymode", verity_mode)) { | |
1252 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1253 | + goto out; | |
1254 | + } | |
1255 | + | |
1256 | + ret = AVB_SLOT_VERIFY_RESULT_OK; | |
1257 | + | |
1258 | +out: | |
1259 | + | |
1260 | + return ret; | |
1261 | +} | |
1262 | + | |
952 | 1263 | AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, |
953 | 1264 | const char* const* requested_partitions, |
954 | 1265 | const char* ab_suffix, |
955 | - bool allow_verification_error, | |
1266 | + AvbSlotVerifyFlags flags, | |
1267 | + AvbHashtreeErrorMode hashtree_error_mode, | |
956 | 1268 | AvbSlotVerifyData** out_data) { |
957 | 1269 | AvbSlotVerifyResult ret; |
958 | 1270 | AvbSlotVerifyData* slot_data = NULL; |
959 | 1271 | AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE; |
960 | - AvbIOResult io_ret; | |
961 | 1272 | bool using_boot_for_vbmeta = false; |
1273 | + AvbVBMetaImageHeader toplevel_vbmeta; | |
1274 | + bool allow_verification_error = | |
1275 | + (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); | |
962 | 1276 | |
1277 | + /* Fail early if we're missing the AvbOps needed for slot verification. | |
1278 | + * | |
1279 | + * For now, handle get_size_of_partition() not being implemented. In | |
1280 | + * a later release we may change that. | |
1281 | + */ | |
1282 | + avb_assert(ops->read_is_device_unlocked != NULL); | |
1283 | + avb_assert(ops->read_from_partition != NULL); | |
1284 | + avb_assert(ops->validate_vbmeta_public_key != NULL); | |
1285 | + avb_assert(ops->read_rollback_index != NULL); | |
1286 | + avb_assert(ops->get_unique_guid_for_partition != NULL); | |
1287 | + /* avb_assert(ops->get_size_of_partition != NULL); */ | |
1288 | + | |
963 | 1289 | if (out_data != NULL) { |
964 | 1290 | *out_data = NULL; |
965 | 1291 | } |
966 | 1292 | |
1293 | + /* Allowing dm-verity errors defeats the purpose of verified boot so | |
1294 | + * only allow this if set up to allow verification errors | |
1295 | + * (e.g. typically only UNLOCKED mode). | |
1296 | + */ | |
1297 | + if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_LOGGING && | |
1298 | + !allow_verification_error) { | |
1299 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT; | |
1300 | + goto fail; | |
1301 | + } | |
1302 | + | |
967 | 1303 | slot_data = avb_calloc(sizeof(AvbSlotVerifyData)); |
968 | 1304 | if (slot_data == NULL) { |
969 | 1305 | ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; |
970 | 1306 | |
... | ... | @@ -998,14 +1334,19 @@ |
998 | 1334 | goto fail; |
999 | 1335 | } |
1000 | 1336 | |
1001 | - if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) { | |
1002 | - avb_assert(avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == | |
1003 | - 0); | |
1004 | - using_boot_for_vbmeta = true; | |
1005 | - } | |
1006 | - | |
1007 | 1337 | /* If things check out, mangle the kernel command-line as needed. */ |
1008 | 1338 | if (result_should_continue(ret)) { |
1339 | + if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) { | |
1340 | + avb_assert( | |
1341 | + avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0); | |
1342 | + using_boot_for_vbmeta = true; | |
1343 | + } | |
1344 | + | |
1345 | + /* Byteswap top-level vbmeta header since we'll need it below. */ | |
1346 | + avb_vbmeta_image_header_to_host_byte_order( | |
1347 | + (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data, | |
1348 | + &toplevel_vbmeta); | |
1349 | + | |
1009 | 1350 | /* Fill in |ab_suffix| field. */ |
1010 | 1351 | slot_data->ab_suffix = avb_strdup(ab_suffix); |
1011 | 1352 | if (slot_data->ab_suffix == NULL) { |
1012 | 1353 | |
... | ... | @@ -1013,23 +1354,37 @@ |
1013 | 1354 | goto fail; |
1014 | 1355 | } |
1015 | 1356 | |
1016 | - /* Add androidboot.vbmeta.device option. */ | |
1017 | - if (!cmdline_append_option(slot_data, | |
1018 | - "androidboot.vbmeta.device", | |
1019 | - "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { | |
1020 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1021 | - goto fail; | |
1357 | + /* If verification is disabled, we are done ... we specifically | |
1358 | + * don't want to add any androidboot.* options since verification | |
1359 | + * is disabled. | |
1360 | + */ | |
1361 | + if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) { | |
1362 | + /* Since verification is disabled we didn't process any | |
1363 | + * descriptors and thus there's no cmdline... so set root= such | |
1364 | + * that the system partition is mounted. | |
1365 | + */ | |
1366 | + avb_assert(slot_data->cmdline == NULL); | |
1367 | + slot_data->cmdline = | |
1368 | + avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)"); | |
1369 | + if (slot_data->cmdline == NULL) { | |
1370 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1371 | + goto fail; | |
1372 | + } | |
1373 | + } else { | |
1374 | + /* Add options - any failure in append_options() is either an | |
1375 | + * I/O or OOM error. | |
1376 | + */ | |
1377 | + AvbSlotVerifyResult sub_ret = append_options(ops, | |
1378 | + slot_data, | |
1379 | + &toplevel_vbmeta, | |
1380 | + algorithm_type, | |
1381 | + hashtree_error_mode); | |
1382 | + if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { | |
1383 | + ret = sub_ret; | |
1384 | + goto fail; | |
1385 | + } | |
1022 | 1386 | } |
1023 | 1387 | |
1024 | - /* Add androidboot.vbmeta.avb_version option. */ | |
1025 | - if (!cmdline_append_version(slot_data, | |
1026 | - "androidboot.vbmeta.avb_version", | |
1027 | - AVB_VERSION_MAJOR, | |
1028 | - AVB_VERSION_MINOR)) { | |
1029 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1030 | - goto fail; | |
1031 | - } | |
1032 | - | |
1033 | 1388 | /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */ |
1034 | 1389 | if (slot_data->cmdline != NULL) { |
1035 | 1390 | char* new_cmdline; |
... | ... | @@ -1043,84 +1398,6 @@ |
1043 | 1398 | slot_data->cmdline = new_cmdline; |
1044 | 1399 | } |
1045 | 1400 | |
1046 | - /* Set androidboot.avb.device_state to "locked" or "unlocked". */ | |
1047 | - bool is_device_unlocked; | |
1048 | - io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); | |
1049 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
1050 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1051 | - goto fail; | |
1052 | - } else if (io_ret != AVB_IO_RESULT_OK) { | |
1053 | - avb_error("Error getting device state.\n"); | |
1054 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
1055 | - goto fail; | |
1056 | - } | |
1057 | - if (!cmdline_append_option(slot_data, | |
1058 | - "androidboot.vbmeta.device_state", | |
1059 | - is_device_unlocked ? "unlocked" : "locked")) { | |
1060 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1061 | - goto fail; | |
1062 | - } | |
1063 | - | |
1064 | - /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash | |
1065 | - * function as is used to sign vbmeta. | |
1066 | - */ | |
1067 | - switch (algorithm_type) { | |
1068 | - /* Explicit fallthrough. */ | |
1069 | - case AVB_ALGORITHM_TYPE_NONE: | |
1070 | - case AVB_ALGORITHM_TYPE_SHA256_RSA2048: | |
1071 | - case AVB_ALGORITHM_TYPE_SHA256_RSA4096: | |
1072 | - case AVB_ALGORITHM_TYPE_SHA256_RSA8192: { | |
1073 | - AvbSHA256Ctx ctx; | |
1074 | - size_t n, total_size = 0; | |
1075 | - avb_sha256_init(&ctx); | |
1076 | - for (n = 0; n < slot_data->num_vbmeta_images; n++) { | |
1077 | - avb_sha256_update(&ctx, | |
1078 | - slot_data->vbmeta_images[n].vbmeta_data, | |
1079 | - slot_data->vbmeta_images[n].vbmeta_size); | |
1080 | - total_size += slot_data->vbmeta_images[n].vbmeta_size; | |
1081 | - } | |
1082 | - if (!cmdline_append_option( | |
1083 | - slot_data, "androidboot.vbmeta.hash_alg", "sha256") || | |
1084 | - !cmdline_append_uint64_base10( | |
1085 | - slot_data, "androidboot.vbmeta.size", total_size) || | |
1086 | - !cmdline_append_hex(slot_data, | |
1087 | - "androidboot.vbmeta.digest", | |
1088 | - avb_sha256_final(&ctx), | |
1089 | - AVB_SHA256_DIGEST_SIZE)) { | |
1090 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1091 | - goto fail; | |
1092 | - } | |
1093 | - } break; | |
1094 | - /* Explicit fallthrough. */ | |
1095 | - case AVB_ALGORITHM_TYPE_SHA512_RSA2048: | |
1096 | - case AVB_ALGORITHM_TYPE_SHA512_RSA4096: | |
1097 | - case AVB_ALGORITHM_TYPE_SHA512_RSA8192: { | |
1098 | - AvbSHA512Ctx ctx; | |
1099 | - size_t n, total_size = 0; | |
1100 | - avb_sha512_init(&ctx); | |
1101 | - for (n = 0; n < slot_data->num_vbmeta_images; n++) { | |
1102 | - avb_sha512_update(&ctx, | |
1103 | - slot_data->vbmeta_images[n].vbmeta_data, | |
1104 | - slot_data->vbmeta_images[n].vbmeta_size); | |
1105 | - total_size += slot_data->vbmeta_images[n].vbmeta_size; | |
1106 | - } | |
1107 | - if (!cmdline_append_option( | |
1108 | - slot_data, "androidboot.vbmeta.hash_alg", "sha512") || | |
1109 | - !cmdline_append_uint64_base10( | |
1110 | - slot_data, "androidboot.vbmeta.size", total_size) || | |
1111 | - !cmdline_append_hex(slot_data, | |
1112 | - "androidboot.vbmeta.digest", | |
1113 | - avb_sha512_final(&ctx), | |
1114 | - AVB_SHA512_DIGEST_SIZE)) { | |
1115 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1116 | - goto fail; | |
1117 | - } | |
1118 | - } break; | |
1119 | - case _AVB_ALGORITHM_NUM_TYPES: | |
1120 | - avb_assert_not_reached(); | |
1121 | - break; | |
1122 | - } | |
1123 | - | |
1124 | 1401 | if (out_data != NULL) { |
1125 | 1402 | *out_data = slot_data; |
1126 | 1403 | } else { |
... | ... | @@ -1141,7 +1418,7 @@ |
1141 | 1418 | return ret; |
1142 | 1419 | } |
1143 | 1420 | |
1144 | -void avb_slot_verify_data_free(AvbSlotVerifyData* data) { | |
1421 | +void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data) { | |
1145 | 1422 | if (data->ab_suffix != NULL) { |
1146 | 1423 | avb_free(data->ab_suffix); |
1147 | 1424 | } |
... | ... | @@ -1166,7 +1443,12 @@ |
1166 | 1443 | for (n = 0; n < data->num_loaded_partitions; n++) { |
1167 | 1444 | AvbPartitionData* loaded_partition = &data->loaded_partitions[n]; |
1168 | 1445 | if (loaded_partition->partition_name != NULL) { |
1169 | - avb_free(loaded_partition->partition_name); | |
1446 | + /* the address of bootimage isn't alloced by malloc, we don't | |
1447 | + * need to free it. */ | |
1448 | + if (strstr(loaded_partition->partition_name, "boot") != NULL) | |
1449 | + continue; | |
1450 | + else | |
1451 | + avb_free(loaded_partition->partition_name); | |
1170 | 1452 | } |
1171 | 1453 | if (loaded_partition->data != NULL) { |
1172 | 1454 | avb_free(loaded_partition->data); |
... | ... | @@ -1176,7 +1458,8 @@ |
1176 | 1458 | } |
1177 | 1459 | avb_free(data); |
1178 | 1460 | } |
1179 | -void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data) { | |
1461 | + | |
1462 | +void avb_slot_verify_data_free(AvbSlotVerifyData* data) { | |
1180 | 1463 | if (data->ab_suffix != NULL) { |
1181 | 1464 | avb_free(data->ab_suffix); |
1182 | 1465 | } |
... | ... | @@ -1201,12 +1484,7 @@ |
1201 | 1484 | for (n = 0; n < data->num_loaded_partitions; n++) { |
1202 | 1485 | AvbPartitionData* loaded_partition = &data->loaded_partitions[n]; |
1203 | 1486 | if (loaded_partition->partition_name != NULL) { |
1204 | - /* the address of bootimage isn't alloced by malloc, we don't | |
1205 | - * need to free it. */ | |
1206 | - if (strstr(loaded_partition->partition_name, "boot") != NULL) | |
1207 | - continue; | |
1208 | - else | |
1209 | - avb_free(loaded_partition->partition_name); | |
1487 | + avb_free(loaded_partition->partition_name); | |
1210 | 1488 | } |
1211 | 1489 | if (loaded_partition->data != NULL) { |
1212 | 1490 | avb_free(loaded_partition->data); |
... | ... | @@ -1244,6 +1522,9 @@ |
1244 | 1522 | break; |
1245 | 1523 | case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: |
1246 | 1524 | ret = "ERROR_UNSUPPORTED_VERSION"; |
1525 | + break; | |
1526 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: | |
1527 | + ret = "ERROR_INVALID_ARGUMENT"; | |
1247 | 1528 | break; |
1248 | 1529 | /* Do not add a 'default:' case here because of -Wswitch. */ |
1249 | 1530 | } |
lib/avb/libavb/avb_slot_verify.h
... | ... | @@ -50,9 +50,61 @@ |
50 | 50 | AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX, |
51 | 51 | AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, |
52 | 52 | AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA, |
53 | - AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION | |
53 | + AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION, | |
54 | + AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT | |
54 | 55 | } AvbSlotVerifyResult; |
55 | 56 | |
57 | +/* Various error handling modes for when verification fails using a | |
58 | + * hashtree at runtime inside the HLOS. | |
59 | + * | |
60 | + * AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE means that the OS | |
61 | + * will invalidate the current slot and restart. | |
62 | + * | |
63 | + * AVB_HASHTREE_ERROR_MODE_RESTART means that the OS will restart. | |
64 | + * | |
65 | + * AVB_HASHTREE_ERROR_MODE_EIO means that an EIO error will be | |
66 | + * returned to applications. | |
67 | + * | |
68 | + * AVB_HASHTREE_ERROR_MODE_LOGGING means that errors will be logged | |
69 | + * and corrupt data may be returned to applications. This mode should | |
70 | + * be used ONLY for diagnostics and debugging. It cannot be used | |
71 | + * unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also | |
72 | + * used. | |
73 | + */ | |
74 | +typedef enum { | |
75 | + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, | |
76 | + AVB_HASHTREE_ERROR_MODE_RESTART, | |
77 | + AVB_HASHTREE_ERROR_MODE_EIO, | |
78 | + AVB_HASHTREE_ERROR_MODE_LOGGING | |
79 | +} AvbHashtreeErrorMode; | |
80 | + | |
81 | +/* Flags that influence how avb_slot_verify() works. | |
82 | + * | |
83 | + * If AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is NOT set then | |
84 | + * avb_slot_verify() will bail out as soon as an error is encountered | |
85 | + * and |out_data| is set only if AVB_SLOT_VERIFY_RESULT_OK is | |
86 | + * returned. | |
87 | + * | |
88 | + * Otherwise if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set | |
89 | + * avb_slot_verify() will continue verification efforts and |out_data| | |
90 | + * is also set if AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, | |
91 | + * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or | |
92 | + * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is | |
93 | + * undefined which error is returned if more than one distinct error | |
94 | + * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is | |
95 | + * returned if, and only if, there are no errors. This mode is needed | |
96 | + * to boot valid but unverified slots when the device is unlocked. | |
97 | + * | |
98 | + * Also, if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set the | |
99 | + * contents loaded from |requested_partition| will be the contents of | |
100 | + * the entire partition instead of just the size specified in the hash | |
101 | + * descriptor. | |
102 | + */ | |
103 | +typedef enum { | |
104 | + AVB_SLOT_VERIFY_FLAGS_NONE = 0, | |
105 | + AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0) | |
106 | +} AvbSlotVerifyFlags; | |
107 | + | |
56 | 108 | /* Get a textual representation of |result|. */ |
57 | 109 | const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result); |
58 | 110 | |
... | ... | @@ -103,7 +155,10 @@ |
103 | 155 | * avb_slot_verify_data_free() function is called. |
104 | 156 | * |
105 | 157 | * The |ab_suffix| field is the copy of the of |ab_suffix| field |
106 | - * passed to avb_slot_verify(). It is the A/B suffix of the slot. | |
158 | + * passed to avb_slot_verify(). It is the A/B suffix of the slot. This | |
159 | + * value includes the leading underscore - typical values are "" (if | |
160 | + * no slots are in use), "_a" (for the first slot), and "_b" (for the | |
161 | + * second slot). | |
107 | 162 | * |
108 | 163 | * The VBMeta images that were checked are available in the |
109 | 164 | * |vbmeta_images| field. The field |num_vbmeta_images| contains the |
110 | 165 | |
111 | 166 | |
... | ... | @@ -132,11 +187,26 @@ |
132 | 187 | * performing proper substitution of the variables |
133 | 188 | * $(ANDROID_SYSTEM_PARTUUID), $(ANDROID_BOOT_PARTUUID), and |
134 | 189 | * $(ANDROID_VBMETA_PARTUUID) using the |
135 | - * get_unique_guid_for_partition() operation in |AvbOps|. | |
190 | + * get_unique_guid_for_partition() operation in |AvbOps|. Additionally | |
191 | + * $(ANDROID_VERITY_MODE) will be replaced with the proper dm-verity | |
192 | + * option depending on the value of |hashtree_error_mode|. | |
136 | 193 | * |
137 | 194 | * Additionally, the |cmdline| field will have the following kernel |
138 | - * command-line options set: | |
195 | + * command-line options set (unless verification is disabled, see | |
196 | + * below): | |
139 | 197 | * |
198 | + * androidboot.veritymode: This is set to 'disabled' if the | |
199 | + * AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED flag is set in top-level | |
200 | + * vbmeta struct. Otherwise it is set to 'enforcing' if the | |
201 | + * passed-in hashtree error mode is AVB_HASHTREE_ERROR_MODE_RESTART | |
202 | + * or AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, 'eio' if it's | |
203 | + * set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to | |
204 | + * AVB_HASHTREE_ERROR_MODE_LOGGING. | |
205 | + * | |
206 | + * androidboot.vbmeta.invalidate_on_error: This is set to 'yes' only | |
207 | + * if hashtree validation isn't disabled and the passed-in hashtree | |
208 | + * error mode is AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE. | |
209 | + * | |
140 | 210 | * androidboot.vbmeta.device_state: set to "locked" or "unlocked" |
141 | 211 | * depending on the result of the result of AvbOps's |
142 | 212 | * read_is_unlocked() function. |
143 | 213 | |
... | ... | @@ -158,9 +228,21 @@ |
158 | 228 | * necessarily the same version number of the on-disk metadata for |
159 | 229 | * the slot that was verified. |
160 | 230 | * |
161 | - * Note that androidboot.slot_suffix is not set in |cmdline| - you | |
162 | - * will have to pass this command-line option yourself. | |
231 | + * Note that androidboot.slot_suffix is not set in the |cmdline| field | |
232 | + * in |AvbSlotVerifyData| - you will have to set this yourself. | |
163 | 233 | * |
234 | + * If the |AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED| flag is set | |
235 | + * in the top-level vbmeta struct then only the top-level vbmeta | |
236 | + * struct is verified and descriptors will not processed. The return | |
237 | + * value will be set accordingly (if this flag is set via 'avbctl | |
238 | + * disable-verification' then the return value will be | |
239 | + * |AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION|) and | |
240 | + * |AvbSlotVerifyData| is returned. Additionally all partitions in the | |
241 | + * |requested_partitions| are loaded and the |cmdline| field is set to | |
242 | + * "root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)" and the GUID for the | |
243 | + * appropriate system partition is substituted in. Note that none of | |
244 | + * the androidboot.* options mentioned above will be set. | |
245 | + * | |
164 | 246 | * This struct may grow in the future without it being considered an |
165 | 247 | * ABI break. |
166 | 248 | */ |
167 | 249 | |
168 | 250 | |
169 | 251 | |
... | ... | @@ -174,23 +256,28 @@ |
174 | 256 | uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS]; |
175 | 257 | } AvbSlotVerifyData; |
176 | 258 | |
259 | +/* Fast version of avb_slot_verify_data_free, this method will not | |
260 | + * free bootimage */ | |
261 | +void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data); | |
177 | 262 | /* Frees a |AvbSlotVerifyData| including all data it points to. */ |
178 | 263 | void avb_slot_verify_data_free(AvbSlotVerifyData* data); |
179 | -void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data); | |
264 | + | |
180 | 265 | /* Performs a full verification of the slot identified by |ab_suffix| |
181 | - * and load the contents of the partitions whose name is in the | |
182 | - * NULL-terminated string array |requested_partitions| (each partition | |
183 | - * must use hash verification). If not using A/B, pass an empty string | |
184 | - * (e.g. "", not NULL) for |ab_suffix|. | |
266 | + * and load and verify the contents of the partitions whose name is in | |
267 | + * the NULL-terminated string array |requested_partitions| (each | |
268 | + * partition must use hash verification). If not using A/B, pass an | |
269 | + * empty string (e.g. "", not NULL) for |ab_suffix|. This parameter | |
270 | + * must include the leading underscore, for example "_a" should be | |
271 | + * used to refer to the first slot. | |
185 | 272 | * |
186 | 273 | * Typically the |requested_partitions| array only contains a single |
187 | 274 | * item for the boot partition, 'boot'. |
188 | 275 | * |
189 | - * Verification includes loading data from the 'vbmeta', all hash | |
190 | - * partitions, and possibly other partitions (with |ab_suffix| | |
191 | - * appended), inspecting rollback indexes, and checking if the public | |
192 | - * key used to sign the data is acceptable. The functions in |ops| | |
193 | - * will be used to do this. | |
276 | + * Verification includes loading and verifying data from the 'vbmeta', | |
277 | + * the requested hash partitions, and possibly other partitions (with | |
278 | + * |ab_suffix| appended), inspecting rollback indexes, and checking if | |
279 | + * the public key used to sign the data is acceptable. The functions | |
280 | + * in |ops| will be used to do this. | |
194 | 281 | * |
195 | 282 | * If |out_data| is not NULL, it will be set to a newly allocated |
196 | 283 | * |AvbSlotVerifyData| struct containing all the data needed to |
197 | 284 | |
... | ... | @@ -198,19 +285,18 @@ |
198 | 285 | * avb_slot_verify_data_free() when you are done with it. See below |
199 | 286 | * for when this is returned. |
200 | 287 | * |
201 | - * If |allow_verification_error| is false this function will bail out | |
202 | - * as soon as an error is encountered and |out_data| is set only if | |
203 | - * AVB_SLOT_VERIFY_RESULT_OK is returned. | |
288 | + * The |flags| parameter is used to influence the semantics of | |
289 | + * avb_slot_verify() - for example the | |
290 | + * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR flag can be used to | |
291 | + * ignore verification errors which is something needed in the | |
292 | + * UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details. | |
204 | 293 | * |
205 | - * Otherwise if |allow_verification_error| is true the function will | |
206 | - * continue verification efforts and |out_data| is also set if | |
207 | - * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, | |
208 | - * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or | |
209 | - * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is | |
210 | - * undefined which error is returned if more than one distinct error | |
211 | - * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is | |
212 | - * returned if, and only if, there are no errors. This mode is needed | |
213 | - * to boot valid but unverified slots when the device is unlocked. | |
294 | + * The |hashtree_error_mode| parameter should be set to the desired | |
295 | + * error handling mode when hashtree validation fails inside the | |
296 | + * HLOS. This value isn't used by libavb per se - it is forwarded to | |
297 | + * the HLOS through the androidboot.veritymode and | |
298 | + * androidboot.vbmeta.invalidate_on_error cmdline parameters. See the | |
299 | + * AvbHashtreeErrorMode enumeration for details. | |
214 | 300 | * |
215 | 301 | * Also note that |out_data| is never set if |
216 | 302 | * AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO, |
217 | 303 | |
... | ... | @@ -243,11 +329,17 @@ |
243 | 329 | * AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION is returned if |
244 | 330 | * some of the metadata requires a newer version of libavb than what |
245 | 331 | * is in use. |
332 | + * | |
333 | + * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT is returned if the | |
334 | + * caller passed invalid parameters, for example trying to use | |
335 | + * AVB_HASHTREE_ERROR_MODE_LOGGING without | |
336 | + * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR. | |
246 | 337 | */ |
247 | 338 | AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, |
248 | 339 | const char* const* requested_partitions, |
249 | 340 | const char* ab_suffix, |
250 | - bool allow_verification_error, | |
341 | + AvbSlotVerifyFlags flags, | |
342 | + AvbHashtreeErrorMode hashtree_error_mode, | |
251 | 343 | AvbSlotVerifyData** out_data); |
252 | 344 | |
253 | 345 | #ifdef __cplusplus |
lib/avb/libavb/avb_sysdeps.h
lib/avb/libavb/avb_vbmeta_image.h
... | ... | @@ -52,9 +52,13 @@ |
52 | 52 | * |
53 | 53 | * AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED: If this flag is set, |
54 | 54 | * hashtree image verification will be disabled. |
55 | + * | |
56 | + * AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED: If this flag is set, | |
57 | + * verification will be disabled and descriptors will not be parsed. | |
55 | 58 | */ |
56 | 59 | typedef enum { |
57 | - AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0) | |
60 | + AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0), | |
61 | + AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED = (1 << 1) | |
58 | 62 | } AvbVBMetaImageFlags; |
59 | 63 | |
60 | 64 | /* Binary format for header of the vbmeta image. |
... | ... | @@ -107,8 +111,8 @@ |
107 | 111 | * minimum version of libavb required to verify the header and depends |
108 | 112 | * on the features (e.g. algorithms, descriptors) used. Note that this |
109 | 113 | * may be 1.0 even if generated by an avbtool from 1.4 but where no |
110 | - * features introduced after 1.0 has been used. See the VERSIONING AND | |
111 | - * COMPATIBILITY section in the README file for more details. | |
114 | + * features introduced after 1.0 has been used. See the "Versioning | |
115 | + * and compatibility" section in the README.md file for more details. | |
112 | 116 | * |
113 | 117 | * All fields are stored in network byte order when serialized. To |
114 | 118 | * generate a copy with fields swapped to native byte order, use the |
lib/avb/libavb/avb_version.h
... | ... | @@ -52,10 +52,6 @@ |
52 | 52 | */ |
53 | 53 | const char* avb_version_string(void); |
54 | 54 | |
55 | -/* TODO: remove when there are no more users of AVB_{MAJOR,MINOR}_VERSION. */ | |
56 | -#define AVB_MAJOR_VERSION AVB_VERSION_MAJOR | |
57 | -#define AVB_MINOR_VERSION AVB_VERSION_MINOR | |
58 | - | |
59 | 55 | #ifdef __cplusplus |
60 | 56 | } |
61 | 57 | #endif |
lib/avb/libavb_ab/avb_ab_flow.c
... | ... | @@ -202,21 +202,19 @@ |
202 | 202 | return AVB_IO_RESULT_OK; |
203 | 203 | } |
204 | 204 | |
205 | -AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops, | |
205 | +AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, | |
206 | 206 | const char* const* requested_partitions, |
207 | - bool allow_verification_error, | |
207 | + AvbSlotVerifyFlags flags, | |
208 | + AvbHashtreeErrorMode hashtree_error_mode, | |
208 | 209 | AvbSlotVerifyData** out_data) { |
209 | 210 | AvbOps* ops = ab_ops->ops; |
210 | 211 | AvbSlotVerifyData* slot_data[2] = {NULL, NULL}; |
211 | 212 | AvbSlotVerifyData* data = NULL; |
212 | 213 | AvbABFlowResult ret; |
213 | 214 | AvbABData ab_data, ab_data_orig; |
214 | - size_t slot_index_to_boot, n = 0; | |
215 | + size_t slot_index_to_boot, n; | |
215 | 216 | AvbIOResult io_ret; |
216 | 217 | bool saw_and_allowed_verification_error = false; |
217 | - size_t target_slot; | |
218 | - AvbSlotVerifyResult verify_result; | |
219 | - bool set_slot_unbootable = false; | |
220 | 218 | |
221 | 219 | io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); |
222 | 220 | if (io_ret == AVB_IO_RESULT_ERROR_OOM) { |
223 | 221 | |
224 | 222 | |
... | ... | @@ -227,18 +225,18 @@ |
227 | 225 | goto out; |
228 | 226 | } |
229 | 227 | |
230 | - slot_index_to_boot = 2; // Means not 0 or 1 | |
231 | - target_slot = (ab_data.slots[1].priority > ab_data.slots[0].priority? 1 : 0); | |
232 | - | |
228 | + /* Validate all bootable slots. */ | |
233 | 229 | for (n = 0; n < 2; n++) { |
234 | - if (!slot_is_bootable(&ab_data.slots[target_slot])) { | |
235 | - target_slot = (target_slot == 1 ? 0 : 1); | |
236 | - continue; | |
237 | - } | |
230 | + if (slot_is_bootable(&ab_data.slots[n])) { | |
231 | + AvbSlotVerifyResult verify_result; | |
232 | + bool set_slot_unbootable = false; | |
238 | 233 | |
239 | - verify_result = avb_slot_verify(ops, requested_partitions, slot_suffixes[target_slot], | |
240 | - allow_verification_error, | |
241 | - &slot_data[target_slot]); | |
234 | + verify_result = avb_slot_verify(ops, | |
235 | + requested_partitions, | |
236 | + slot_suffixes[n], | |
237 | + flags, | |
238 | + hashtree_error_mode, | |
239 | + &slot_data[n]); | |
242 | 240 | switch (verify_result) { |
243 | 241 | case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: |
244 | 242 | ret = AVB_AB_FLOW_RESULT_ERROR_OOM; |
245 | 243 | |
... | ... | @@ -249,13 +247,13 @@ |
249 | 247 | goto out; |
250 | 248 | |
251 | 249 | case AVB_SLOT_VERIFY_RESULT_OK: |
252 | - slot_index_to_boot = target_slot; | |
253 | - n = 2; | |
254 | 250 | break; |
255 | 251 | |
256 | 252 | case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: |
257 | 253 | case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: |
258 | - /* Even with |allow_verification_error| these mean game over. */ | |
254 | + /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR | |
255 | + * these mean game over. | |
256 | + */ | |
259 | 257 | set_slot_unbootable = true; |
260 | 258 | break; |
261 | 259 | |
262 | 260 | |
263 | 261 | |
264 | 262 | |
265 | 263 | |
266 | 264 | |
267 | 265 | |
268 | 266 | |
269 | 267 | |
270 | 268 | |
... | ... | @@ -263,40 +261,53 @@ |
263 | 261 | case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: |
264 | 262 | case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: |
265 | 263 | case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: |
266 | - if (allow_verification_error) { | |
264 | + if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) { | |
267 | 265 | /* Do nothing since we allow this. */ |
268 | 266 | avb_debugv("Allowing slot ", |
269 | - slot_suffixes[target_slot], | |
267 | + slot_suffixes[n], | |
270 | 268 | " which verified " |
271 | 269 | "with result ", |
272 | 270 | avb_slot_verify_result_to_string(verify_result), |
273 | - " because |allow_verification_error| is true.\n", | |
271 | + " because " | |
272 | + "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR " | |
273 | + "is set.\n", | |
274 | 274 | NULL); |
275 | 275 | saw_and_allowed_verification_error = true; |
276 | - slot_index_to_boot = target_slot; | |
277 | - n = 2; | |
278 | 276 | } else { |
279 | 277 | set_slot_unbootable = true; |
280 | 278 | } |
281 | 279 | break; |
282 | - default: | |
283 | - break; | |
280 | + | |
281 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: | |
282 | + ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT; | |
283 | + goto out; | |
284 | + /* Do not add a 'default:' case here because of -Wswitch. */ | |
284 | 285 | } |
286 | + | |
285 | 287 | if (set_slot_unbootable) { |
286 | 288 | avb_errorv("Error verifying slot ", |
287 | - slot_suffixes[target_slot], | |
289 | + slot_suffixes[n], | |
288 | 290 | " with result ", |
289 | 291 | avb_slot_verify_result_to_string(verify_result), |
290 | 292 | " - setting unbootable.\n", |
291 | 293 | NULL); |
292 | - slot_set_unbootable(&ab_data.slots[target_slot]); | |
293 | - set_slot_unbootable = false; | |
294 | + slot_set_unbootable(&ab_data.slots[n]); | |
294 | 295 | } |
295 | - /* switch to another slot */ | |
296 | - target_slot = (target_slot == 1 ? 0 : 1); | |
296 | + } | |
297 | 297 | } |
298 | 298 | |
299 | - if (slot_index_to_boot == 2) { | |
299 | + if (slot_is_bootable(&ab_data.slots[0]) && | |
300 | + slot_is_bootable(&ab_data.slots[1])) { | |
301 | + if (ab_data.slots[1].priority > ab_data.slots[0].priority) { | |
302 | + slot_index_to_boot = 1; | |
303 | + } else { | |
304 | + slot_index_to_boot = 0; | |
305 | + } | |
306 | + } else if (slot_is_bootable(&ab_data.slots[0])) { | |
307 | + slot_index_to_boot = 0; | |
308 | + } else if (slot_is_bootable(&ab_data.slots[1])) { | |
309 | + slot_index_to_boot = 1; | |
310 | + } else { | |
300 | 311 | /* No bootable slots! */ |
301 | 312 | avb_error("No bootable slots found.\n"); |
302 | 313 | ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; |
... | ... | @@ -352,7 +363,7 @@ |
352 | 363 | data = slot_data[slot_index_to_boot]; |
353 | 364 | slot_data[slot_index_to_boot] = NULL; |
354 | 365 | if (saw_and_allowed_verification_error) { |
355 | - avb_assert(allow_verification_error); | |
366 | + avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); | |
356 | 367 | ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR; |
357 | 368 | } else { |
358 | 369 | ret = AVB_AB_FLOW_RESULT_OK; |
359 | 370 | |
360 | 371 | |
... | ... | @@ -388,18 +399,17 @@ |
388 | 399 | *out_data = data; |
389 | 400 | } else { |
390 | 401 | if (data != NULL) { |
391 | - /* the address of bootimage isn't alloced by malloc, | |
392 | - * we should not free it. */ | |
393 | - avb_slot_verify_data_free_fast(data); | |
402 | + avb_slot_verify_data_free(data); | |
394 | 403 | } |
395 | 404 | } |
396 | 405 | |
397 | 406 | return ret; |
398 | 407 | } |
399 | 408 | |
400 | -AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, | |
409 | +AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops, | |
401 | 410 | const char* const* requested_partitions, |
402 | - bool allow_verification_error, | |
411 | + AvbSlotVerifyFlags flags, | |
412 | + AvbHashtreeErrorMode hashtree_error_mode, | |
403 | 413 | AvbSlotVerifyData** out_data) { |
404 | 414 | AvbOps* ops = ab_ops->ops; |
405 | 415 | AvbSlotVerifyData* slot_data[2] = {NULL, NULL}; |
... | ... | @@ -409,6 +419,9 @@ |
409 | 419 | size_t slot_index_to_boot, n; |
410 | 420 | AvbIOResult io_ret; |
411 | 421 | bool saw_and_allowed_verification_error = false; |
422 | + size_t target_slot; | |
423 | + AvbSlotVerifyResult verify_result; | |
424 | + bool set_slot_unbootable = false; | |
412 | 425 | |
413 | 426 | io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); |
414 | 427 | if (io_ret == AVB_IO_RESULT_ERROR_OOM) { |
415 | 428 | |
416 | 429 | |
417 | 430 | |
418 | 431 | |
419 | 432 | |
420 | 433 | |
421 | 434 | |
422 | 435 | |
423 | 436 | |
424 | 437 | |
... | ... | @@ -419,79 +432,86 @@ |
419 | 432 | goto out; |
420 | 433 | } |
421 | 434 | |
422 | - /* Validate all bootable slots. */ | |
423 | - for (n = 0; n < 2; n++) { | |
424 | - if (slot_is_bootable(&ab_data.slots[n])) { | |
425 | - AvbSlotVerifyResult verify_result; | |
426 | - bool set_slot_unbootable = false; | |
435 | + slot_index_to_boot = 2; // Means not 0 or 1 | |
436 | + target_slot = (ab_data.slots[1].priority > ab_data.slots[0].priority? 1 : 0); | |
427 | 437 | |
428 | - verify_result = avb_slot_verify(ops, | |
438 | + for (n = 0; n < 2; n++) { | |
439 | + if (!slot_is_bootable(&ab_data.slots[target_slot])) { | |
440 | + target_slot = (target_slot == 1 ? 0 : 1); | |
441 | + continue; | |
442 | + } | |
443 | + verify_result = avb_slot_verify(ops, | |
429 | 444 | requested_partitions, |
430 | - slot_suffixes[n], | |
431 | - allow_verification_error, | |
432 | - &slot_data[n]); | |
433 | - switch (verify_result) { | |
434 | - case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: | |
435 | - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
436 | - goto out; | |
445 | + slot_suffixes[target_slot], | |
446 | + flags, | |
447 | + hashtree_error_mode, | |
448 | + &slot_data[target_slot]); | |
449 | + switch (verify_result) { | |
450 | + case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: | |
451 | + ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
452 | + goto out; | |
437 | 453 | |
438 | - case AVB_SLOT_VERIFY_RESULT_ERROR_IO: | |
439 | - ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
440 | - goto out; | |
454 | + case AVB_SLOT_VERIFY_RESULT_ERROR_IO: | |
455 | + ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
456 | + goto out; | |
441 | 457 | |
442 | - case AVB_SLOT_VERIFY_RESULT_OK: | |
443 | - break; | |
458 | + case AVB_SLOT_VERIFY_RESULT_OK: | |
459 | + slot_index_to_boot = target_slot; | |
460 | + n = 2; | |
461 | + break; | |
444 | 462 | |
445 | - case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: | |
446 | - case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: | |
447 | - /* Even with |allow_verification_error| these mean game over. */ | |
463 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: | |
464 | + case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: | |
465 | + /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR | |
466 | + * these mean game over. | |
467 | + */ | |
468 | + set_slot_unbootable = true; | |
469 | + break; | |
470 | + | |
471 | + /* explicit fallthrough. */ | |
472 | + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: | |
473 | + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: | |
474 | + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: | |
475 | + if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) { | |
476 | + /* Do nothing since we allow this. */ | |
477 | + avb_debugv("Allowing slot ", | |
478 | + slot_suffixes[target_slot], | |
479 | + " which verified " | |
480 | + "with result ", | |
481 | + avb_slot_verify_result_to_string(verify_result), | |
482 | + " because " | |
483 | + "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR " | |
484 | + "is set.\n", | |
485 | + NULL); | |
486 | + saw_and_allowed_verification_error = true; | |
487 | + slot_index_to_boot = target_slot; | |
488 | + n = 2; | |
489 | + } else { | |
448 | 490 | set_slot_unbootable = true; |
449 | - break; | |
491 | + } | |
492 | + break; | |
450 | 493 | |
451 | - /* explicit fallthrough. */ | |
452 | - case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: | |
453 | - case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: | |
454 | - case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: | |
455 | - if (allow_verification_error) { | |
456 | - /* Do nothing since we allow this. */ | |
457 | - avb_debugv("Allowing slot ", | |
458 | - slot_suffixes[n], | |
459 | - " which verified " | |
460 | - "with result ", | |
461 | - avb_slot_verify_result_to_string(verify_result), | |
462 | - " because |allow_verification_error| is true.\n", | |
463 | - NULL); | |
464 | - saw_and_allowed_verification_error = true; | |
465 | - } else { | |
466 | - set_slot_unbootable = true; | |
467 | - } | |
468 | - break; | |
469 | - } | |
494 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: | |
495 | + ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT; | |
496 | + goto out; | |
497 | + /* Do not add a 'default:' case here because of -Wswitch. */ | |
498 | + } | |
470 | 499 | |
471 | - if (set_slot_unbootable) { | |
472 | - avb_errorv("Error verifying slot ", | |
473 | - slot_suffixes[n], | |
474 | - " with result ", | |
475 | - avb_slot_verify_result_to_string(verify_result), | |
476 | - " - setting unbootable.\n", | |
477 | - NULL); | |
478 | - slot_set_unbootable(&ab_data.slots[n]); | |
479 | - } | |
500 | + if (set_slot_unbootable) { | |
501 | + avb_errorv("Error verifying slot ", | |
502 | + slot_suffixes[target_slot], | |
503 | + " with result ", | |
504 | + avb_slot_verify_result_to_string(verify_result), | |
505 | + " - setting unbootable.\n", | |
506 | + NULL); | |
507 | + slot_set_unbootable(&ab_data.slots[target_slot]); | |
508 | + set_slot_unbootable = false; | |
480 | 509 | } |
510 | + /* switch to another slot */ | |
511 | + target_slot = (target_slot == 1 ? 0 : 1); | |
481 | 512 | } |
482 | 513 | |
483 | - if (slot_is_bootable(&ab_data.slots[0]) && | |
484 | - slot_is_bootable(&ab_data.slots[1])) { | |
485 | - if (ab_data.slots[1].priority > ab_data.slots[0].priority) { | |
486 | - slot_index_to_boot = 1; | |
487 | - } else { | |
488 | - slot_index_to_boot = 0; | |
489 | - } | |
490 | - } else if (slot_is_bootable(&ab_data.slots[0])) { | |
491 | - slot_index_to_boot = 0; | |
492 | - } else if (slot_is_bootable(&ab_data.slots[1])) { | |
493 | - slot_index_to_boot = 1; | |
494 | - } else { | |
514 | + if (slot_index_to_boot == 2) { | |
495 | 515 | /* No bootable slots! */ |
496 | 516 | avb_error("No bootable slots found.\n"); |
497 | 517 | ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; |
... | ... | @@ -547,7 +567,7 @@ |
547 | 567 | data = slot_data[slot_index_to_boot]; |
548 | 568 | slot_data[slot_index_to_boot] = NULL; |
549 | 569 | if (saw_and_allowed_verification_error) { |
550 | - avb_assert(allow_verification_error); | |
570 | + avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); | |
551 | 571 | ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR; |
552 | 572 | } else { |
553 | 573 | ret = AVB_AB_FLOW_RESULT_OK; |
... | ... | @@ -583,7 +603,9 @@ |
583 | 603 | *out_data = data; |
584 | 604 | } else { |
585 | 605 | if (data != NULL) { |
586 | - avb_slot_verify_data_free(data); | |
606 | + /* the address of bootimage isn't alloced by malloc, | |
607 | + * we should not free it. */ | |
608 | + avb_slot_verify_data_free_fast(data); | |
587 | 609 | } |
588 | 610 | } |
589 | 611 | |
... | ... | @@ -698,6 +720,10 @@ |
698 | 720 | |
699 | 721 | case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS: |
700 | 722 | ret = "ERROR_NO_BOOTABLE_SLOTS"; |
723 | + break; | |
724 | + | |
725 | + case AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT: | |
726 | + ret = "ERROR_INVALID_ARGUMENT"; | |
701 | 727 | break; |
702 | 728 | /* Do not add a 'default:' case here because of -Wswitch. */ |
703 | 729 | } |
lib/avb/libavb_ab/avb_ab_flow.h
... | ... | @@ -140,7 +140,8 @@ |
140 | 140 | AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR, |
141 | 141 | AVB_AB_FLOW_RESULT_ERROR_OOM, |
142 | 142 | AVB_AB_FLOW_RESULT_ERROR_IO, |
143 | - AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS | |
143 | + AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS, | |
144 | + AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT | |
144 | 145 | } AvbABFlowResult; |
145 | 146 | |
146 | 147 | /* Get a textual representation of |result|. */ |
... | ... | @@ -156,9 +157,9 @@ |
156 | 157 | * |
157 | 158 | * 2. All bootable slots listed in the A/B metadata are verified using |
158 | 159 | * avb_slot_verify(). If a slot is invalid or if it fails verification |
159 | - * (and |allow_verification_error| is false, see below), it will be | |
160 | - * marked as unbootable in the A/B metadata and the metadata will be | |
161 | - * saved to disk before returning. | |
160 | + * (and AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is not set, see | |
161 | + * below), it will be marked as unbootable in the A/B metadata and the | |
162 | + * metadata will be saved to disk before returning. | |
162 | 163 | * |
163 | 164 | * 3. If there are no bootable slots, the value |
164 | 165 | * AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS is returned. |
165 | 166 | |
166 | 167 | |
... | ... | @@ -180,25 +181,26 @@ |
180 | 181 | * |requested_partitions| array only contains a single item for the |
181 | 182 | * boot partition, 'boot'. |
182 | 183 | * |
183 | - * If the device is unlocked (and _only_ if it's unlocked), true | |
184 | - * should be passed in the |allow_verification_error| parameter. This | |
185 | - * will allow considering slots as verified even when | |
186 | - * avb_slot_verify() returns | |
184 | + * If the device is unlocked (and _only_ if it's unlocked), the | |
185 | + * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR flag should be set | |
186 | + * in the |flags| parameter. This will allow considering slots as | |
187 | + * verified even when avb_slot_verify() returns | |
187 | 188 | * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, |
188 | 189 | * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or |
189 | 190 | * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX for the slot in |
190 | 191 | * question. |
191 | 192 | * |
192 | - * Note that androidboot.slot_suffix is not set in the |cmdline| field | |
193 | - * in |AvbSlotVerifyData| - you will have to pass this command-line | |
194 | - * option yourself. | |
193 | + * Note that neither androidboot.slot_suffix nor androidboot.slot are | |
194 | + * set in the |cmdline| field in |AvbSlotVerifyData| - you will have | |
195 | + * to pass these yourself. | |
195 | 196 | * |
196 | 197 | * If a slot was selected and it verified then AVB_AB_FLOW_RESULT_OK |
197 | 198 | * is returned. |
198 | 199 | * |
199 | 200 | * If a slot was selected but it didn't verify then |
200 | 201 | * AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR is returned. This can |
201 | - * only happen when |allow_verification_error| is true. | |
202 | + * only happen when the AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR | |
203 | + * flag is set. | |
202 | 204 | * |
203 | 205 | * If an I/O operation - such as loading/saving metadata or checking |
204 | 206 | * rollback indexes - fail, the value AVB_AB_FLOW_RESULT_ERROR_IO is |
205 | 207 | |
206 | 208 | |
... | ... | @@ -207,17 +209,24 @@ |
207 | 209 | * If memory allocation fails, AVB_AB_FLOW_RESULT_ERROR_OOM is |
208 | 210 | * returned. |
209 | 211 | * |
212 | + * If invalid arguments are passed, | |
213 | + * AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT is returned. For example | |
214 | + * this can happen if using AVB_HASHTREE_ERROR_MODE_LOGGING without | |
215 | + * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR. | |
216 | + * | |
210 | 217 | * Reasonable behavior for handling AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS |
211 | 218 | * is to initiate device repair (which is device-dependent). |
212 | 219 | */ |
213 | 220 | AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops, |
214 | 221 | const char* const* requested_partitions, |
215 | - bool allow_verification_error, | |
222 | + AvbSlotVerifyFlags flags, | |
223 | + AvbHashtreeErrorMode hashtree_error_mode, | |
216 | 224 | AvbSlotVerifyData** out_data); |
217 | 225 | |
218 | 226 | AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops, |
219 | 227 | const char* const* requested_partitions, |
220 | - bool allow_verification_error, | |
228 | + AvbSlotVerifyFlags flags, | |
229 | + AvbHashtreeErrorMode hashtree_error_mode, | |
221 | 230 | AvbSlotVerifyData** out_data); |
222 | 231 | |
223 | 232 | /* Marks the slot with the given slot number as active. Returns |