1*d289c2baSAndroid Build Coastguard Worker /*
2*d289c2baSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*d289c2baSAndroid Build Coastguard Worker *
4*d289c2baSAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person
5*d289c2baSAndroid Build Coastguard Worker * obtaining a copy of this software and associated documentation
6*d289c2baSAndroid Build Coastguard Worker * files (the "Software"), to deal in the Software without
7*d289c2baSAndroid Build Coastguard Worker * restriction, including without limitation the rights to use, copy,
8*d289c2baSAndroid Build Coastguard Worker * modify, merge, publish, distribute, sublicense, and/or sell copies
9*d289c2baSAndroid Build Coastguard Worker * of the Software, and to permit persons to whom the Software is
10*d289c2baSAndroid Build Coastguard Worker * furnished to do so, subject to the following conditions:
11*d289c2baSAndroid Build Coastguard Worker *
12*d289c2baSAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be
13*d289c2baSAndroid Build Coastguard Worker * included in all copies or substantial portions of the Software.
14*d289c2baSAndroid Build Coastguard Worker *
15*d289c2baSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*d289c2baSAndroid Build Coastguard Worker * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*d289c2baSAndroid Build Coastguard Worker * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18*d289c2baSAndroid Build Coastguard Worker * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19*d289c2baSAndroid Build Coastguard Worker * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20*d289c2baSAndroid Build Coastguard Worker * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21*d289c2baSAndroid Build Coastguard Worker * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*d289c2baSAndroid Build Coastguard Worker * SOFTWARE.
23*d289c2baSAndroid Build Coastguard Worker */
24*d289c2baSAndroid Build Coastguard Worker
25*d289c2baSAndroid Build Coastguard Worker #include "avb_descriptor.h"
26*d289c2baSAndroid Build Coastguard Worker #include "avb_util.h"
27*d289c2baSAndroid Build Coastguard Worker #include "avb_vbmeta_image.h"
28*d289c2baSAndroid Build Coastguard Worker
avb_descriptor_validate_and_byteswap(const AvbDescriptor * src,AvbDescriptor * dest)29*d289c2baSAndroid Build Coastguard Worker bool avb_descriptor_validate_and_byteswap(const AvbDescriptor* src,
30*d289c2baSAndroid Build Coastguard Worker AvbDescriptor* dest) {
31*d289c2baSAndroid Build Coastguard Worker dest->tag = avb_be64toh(src->tag);
32*d289c2baSAndroid Build Coastguard Worker dest->num_bytes_following = avb_be64toh(src->num_bytes_following);
33*d289c2baSAndroid Build Coastguard Worker
34*d289c2baSAndroid Build Coastguard Worker if ((dest->num_bytes_following & 0x07) != 0) {
35*d289c2baSAndroid Build Coastguard Worker avb_error("Descriptor size is not divisible by 8.\n");
36*d289c2baSAndroid Build Coastguard Worker return false;
37*d289c2baSAndroid Build Coastguard Worker }
38*d289c2baSAndroid Build Coastguard Worker return true;
39*d289c2baSAndroid Build Coastguard Worker }
40*d289c2baSAndroid Build Coastguard Worker
avb_descriptor_foreach(const uint8_t * image_data,size_t image_size,AvbDescriptorForeachFunc foreach_func,void * user_data)41*d289c2baSAndroid Build Coastguard Worker bool avb_descriptor_foreach(const uint8_t* image_data,
42*d289c2baSAndroid Build Coastguard Worker size_t image_size,
43*d289c2baSAndroid Build Coastguard Worker AvbDescriptorForeachFunc foreach_func,
44*d289c2baSAndroid Build Coastguard Worker void* user_data) {
45*d289c2baSAndroid Build Coastguard Worker const AvbVBMetaImageHeader* header = NULL;
46*d289c2baSAndroid Build Coastguard Worker bool ret = false;
47*d289c2baSAndroid Build Coastguard Worker const uint8_t* image_end;
48*d289c2baSAndroid Build Coastguard Worker const uint8_t* desc_start;
49*d289c2baSAndroid Build Coastguard Worker const uint8_t* desc_end;
50*d289c2baSAndroid Build Coastguard Worker const uint8_t* p;
51*d289c2baSAndroid Build Coastguard Worker uint64_t desc_offset = 0;
52*d289c2baSAndroid Build Coastguard Worker uint64_t desc_size = 0;
53*d289c2baSAndroid Build Coastguard Worker
54*d289c2baSAndroid Build Coastguard Worker if (image_data == NULL) {
55*d289c2baSAndroid Build Coastguard Worker avb_error("image_data is NULL\n.");
56*d289c2baSAndroid Build Coastguard Worker goto out;
57*d289c2baSAndroid Build Coastguard Worker }
58*d289c2baSAndroid Build Coastguard Worker
59*d289c2baSAndroid Build Coastguard Worker if (foreach_func == NULL) {
60*d289c2baSAndroid Build Coastguard Worker avb_error("foreach_func is NULL\n.");
61*d289c2baSAndroid Build Coastguard Worker goto out;
62*d289c2baSAndroid Build Coastguard Worker }
63*d289c2baSAndroid Build Coastguard Worker
64*d289c2baSAndroid Build Coastguard Worker /* The data is supposed to have been cryptographically verified at this point,
65*d289c2baSAndroid Build Coastguard Worker * This check is just adding defense in depth.
66*d289c2baSAndroid Build Coastguard Worker */
67*d289c2baSAndroid Build Coastguard Worker if (image_size < sizeof(AvbVBMetaImageHeader)) {
68*d289c2baSAndroid Build Coastguard Worker avb_error("Length is smaller than header.\n");
69*d289c2baSAndroid Build Coastguard Worker goto out;
70*d289c2baSAndroid Build Coastguard Worker }
71*d289c2baSAndroid Build Coastguard Worker
72*d289c2baSAndroid Build Coastguard Worker /* Ensure magic is correct. */
73*d289c2baSAndroid Build Coastguard Worker if (avb_memcmp(image_data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
74*d289c2baSAndroid Build Coastguard Worker avb_error("Magic is incorrect.\n");
75*d289c2baSAndroid Build Coastguard Worker goto out;
76*d289c2baSAndroid Build Coastguard Worker }
77*d289c2baSAndroid Build Coastguard Worker
78*d289c2baSAndroid Build Coastguard Worker /* Careful, not byteswapped - also ensure it's aligned properly. */
79*d289c2baSAndroid Build Coastguard Worker avb_assert_aligned(image_data);
80*d289c2baSAndroid Build Coastguard Worker header = (const AvbVBMetaImageHeader*)image_data;
81*d289c2baSAndroid Build Coastguard Worker image_end = image_data + image_size;
82*d289c2baSAndroid Build Coastguard Worker
83*d289c2baSAndroid Build Coastguard Worker /* Since the data is supposed to have been cryptographically verified at this
84*d289c2baSAndroid Build Coastguard Worker * point, being overflow-safe is just for defense.
85*d289c2baSAndroid Build Coastguard Worker * The following lines are overflow-safe version of:
86*d289c2baSAndroid Build Coastguard Worker * desc_offset = sizeof(AvbVBMetaImageHeader) +
87*d289c2baSAndroid Build Coastguard Worker * avb_be64toh(header->authentication_data_block_size)) +
88*d289c2baSAndroid Build Coastguard Worker * avb_be64toh(header->descriptors_offset)
89*d289c2baSAndroid Build Coastguard Worker */
90*d289c2baSAndroid Build Coastguard Worker if (!avb_safe_add(&desc_offset,
91*d289c2baSAndroid Build Coastguard Worker sizeof(AvbVBMetaImageHeader),
92*d289c2baSAndroid Build Coastguard Worker avb_be64toh(header->authentication_data_block_size))) {
93*d289c2baSAndroid Build Coastguard Worker avb_error("Invalid authentication data block size.\n");
94*d289c2baSAndroid Build Coastguard Worker goto out;
95*d289c2baSAndroid Build Coastguard Worker }
96*d289c2baSAndroid Build Coastguard Worker if (!avb_safe_add_to(&desc_offset, avb_be64toh(header->descriptors_offset))) {
97*d289c2baSAndroid Build Coastguard Worker avb_error("Invalid descriptors offset.\n");
98*d289c2baSAndroid Build Coastguard Worker goto out;
99*d289c2baSAndroid Build Coastguard Worker }
100*d289c2baSAndroid Build Coastguard Worker
101*d289c2baSAndroid Build Coastguard Worker if (desc_offset > (uint64_t)(image_end - image_data)) {
102*d289c2baSAndroid Build Coastguard Worker avb_error("Descriptors not inside passed-in data.\n");
103*d289c2baSAndroid Build Coastguard Worker goto out;
104*d289c2baSAndroid Build Coastguard Worker }
105*d289c2baSAndroid Build Coastguard Worker
106*d289c2baSAndroid Build Coastguard Worker desc_start = image_data + desc_offset;
107*d289c2baSAndroid Build Coastguard Worker
108*d289c2baSAndroid Build Coastguard Worker desc_size = avb_be64toh(header->descriptors_size);
109*d289c2baSAndroid Build Coastguard Worker if (desc_size > (uint64_t)(image_end - desc_start)) {
110*d289c2baSAndroid Build Coastguard Worker avb_error("Descriptors not inside passed-in data.\n");
111*d289c2baSAndroid Build Coastguard Worker goto out;
112*d289c2baSAndroid Build Coastguard Worker }
113*d289c2baSAndroid Build Coastguard Worker
114*d289c2baSAndroid Build Coastguard Worker desc_end = desc_start + desc_size;
115*d289c2baSAndroid Build Coastguard Worker
116*d289c2baSAndroid Build Coastguard Worker for (p = desc_start; p < desc_end;) {
117*d289c2baSAndroid Build Coastguard Worker uint64_t nb_following;
118*d289c2baSAndroid Build Coastguard Worker uint64_t nb_total = 0;
119*d289c2baSAndroid Build Coastguard Worker const AvbDescriptor* dh;
120*d289c2baSAndroid Build Coastguard Worker
121*d289c2baSAndroid Build Coastguard Worker if (sizeof(AvbDescriptor) > (size_t)(desc_end - p)) {
122*d289c2baSAndroid Build Coastguard Worker avb_error("Invalid descriptor length.\n");
123*d289c2baSAndroid Build Coastguard Worker goto out;
124*d289c2baSAndroid Build Coastguard Worker }
125*d289c2baSAndroid Build Coastguard Worker
126*d289c2baSAndroid Build Coastguard Worker dh = (const AvbDescriptor*)p;
127*d289c2baSAndroid Build Coastguard Worker avb_assert_aligned(dh);
128*d289c2baSAndroid Build Coastguard Worker nb_following = avb_be64toh(dh->num_bytes_following);
129*d289c2baSAndroid Build Coastguard Worker
130*d289c2baSAndroid Build Coastguard Worker if (!avb_safe_add(&nb_total, sizeof(AvbDescriptor), nb_following)) {
131*d289c2baSAndroid Build Coastguard Worker avb_error("Invalid descriptor length.\n");
132*d289c2baSAndroid Build Coastguard Worker goto out;
133*d289c2baSAndroid Build Coastguard Worker }
134*d289c2baSAndroid Build Coastguard Worker
135*d289c2baSAndroid Build Coastguard Worker if ((nb_total & 7) != 0) {
136*d289c2baSAndroid Build Coastguard Worker avb_error("Invalid descriptor length.\n");
137*d289c2baSAndroid Build Coastguard Worker goto out;
138*d289c2baSAndroid Build Coastguard Worker }
139*d289c2baSAndroid Build Coastguard Worker
140*d289c2baSAndroid Build Coastguard Worker if (nb_total > (uint64_t)(desc_end - p)) {
141*d289c2baSAndroid Build Coastguard Worker avb_error("Invalid data in descriptors array.\n");
142*d289c2baSAndroid Build Coastguard Worker goto out;
143*d289c2baSAndroid Build Coastguard Worker }
144*d289c2baSAndroid Build Coastguard Worker
145*d289c2baSAndroid Build Coastguard Worker if (foreach_func(dh, user_data) == 0) {
146*d289c2baSAndroid Build Coastguard Worker goto out;
147*d289c2baSAndroid Build Coastguard Worker }
148*d289c2baSAndroid Build Coastguard Worker
149*d289c2baSAndroid Build Coastguard Worker p += nb_total;
150*d289c2baSAndroid Build Coastguard Worker }
151*d289c2baSAndroid Build Coastguard Worker
152*d289c2baSAndroid Build Coastguard Worker ret = true;
153*d289c2baSAndroid Build Coastguard Worker
154*d289c2baSAndroid Build Coastguard Worker out:
155*d289c2baSAndroid Build Coastguard Worker return ret;
156*d289c2baSAndroid Build Coastguard Worker }
157*d289c2baSAndroid Build Coastguard Worker
count_descriptors(const AvbDescriptor * descriptor,void * user_data)158*d289c2baSAndroid Build Coastguard Worker static bool count_descriptors(const AvbDescriptor* descriptor,
159*d289c2baSAndroid Build Coastguard Worker void* user_data) {
160*d289c2baSAndroid Build Coastguard Worker size_t* num_descriptors = user_data;
161*d289c2baSAndroid Build Coastguard Worker *num_descriptors += 1;
162*d289c2baSAndroid Build Coastguard Worker return true;
163*d289c2baSAndroid Build Coastguard Worker }
164*d289c2baSAndroid Build Coastguard Worker
165*d289c2baSAndroid Build Coastguard Worker typedef struct {
166*d289c2baSAndroid Build Coastguard Worker size_t descriptor_number;
167*d289c2baSAndroid Build Coastguard Worker const AvbDescriptor** descriptors;
168*d289c2baSAndroid Build Coastguard Worker } SetDescriptorData;
169*d289c2baSAndroid Build Coastguard Worker
set_descriptors(const AvbDescriptor * descriptor,void * user_data)170*d289c2baSAndroid Build Coastguard Worker static bool set_descriptors(const AvbDescriptor* descriptor, void* user_data) {
171*d289c2baSAndroid Build Coastguard Worker SetDescriptorData* data = user_data;
172*d289c2baSAndroid Build Coastguard Worker data->descriptors[data->descriptor_number++] = descriptor;
173*d289c2baSAndroid Build Coastguard Worker return true;
174*d289c2baSAndroid Build Coastguard Worker }
175*d289c2baSAndroid Build Coastguard Worker
avb_descriptor_get_all(const uint8_t * image_data,size_t image_size,size_t * out_num_descriptors)176*d289c2baSAndroid Build Coastguard Worker const AvbDescriptor** avb_descriptor_get_all(const uint8_t* image_data,
177*d289c2baSAndroid Build Coastguard Worker size_t image_size,
178*d289c2baSAndroid Build Coastguard Worker size_t* out_num_descriptors) {
179*d289c2baSAndroid Build Coastguard Worker size_t num_descriptors = 0;
180*d289c2baSAndroid Build Coastguard Worker SetDescriptorData data;
181*d289c2baSAndroid Build Coastguard Worker
182*d289c2baSAndroid Build Coastguard Worker avb_descriptor_foreach(
183*d289c2baSAndroid Build Coastguard Worker image_data, image_size, count_descriptors, &num_descriptors);
184*d289c2baSAndroid Build Coastguard Worker
185*d289c2baSAndroid Build Coastguard Worker data.descriptor_number = 0;
186*d289c2baSAndroid Build Coastguard Worker data.descriptors =
187*d289c2baSAndroid Build Coastguard Worker avb_calloc(sizeof(const AvbDescriptor*) * (num_descriptors + 1));
188*d289c2baSAndroid Build Coastguard Worker if (data.descriptors == NULL) {
189*d289c2baSAndroid Build Coastguard Worker return NULL;
190*d289c2baSAndroid Build Coastguard Worker }
191*d289c2baSAndroid Build Coastguard Worker avb_descriptor_foreach(image_data, image_size, set_descriptors, &data);
192*d289c2baSAndroid Build Coastguard Worker avb_assert(data.descriptor_number == num_descriptors);
193*d289c2baSAndroid Build Coastguard Worker
194*d289c2baSAndroid Build Coastguard Worker if (out_num_descriptors != NULL) {
195*d289c2baSAndroid Build Coastguard Worker *out_num_descriptors = num_descriptors;
196*d289c2baSAndroid Build Coastguard Worker }
197*d289c2baSAndroid Build Coastguard Worker
198*d289c2baSAndroid Build Coastguard Worker return data.descriptors;
199*d289c2baSAndroid Build Coastguard Worker }
200