xref: /aosp_15_r20/external/avb/libavb/avb_descriptor.c (revision d289c2ba6de359471b23d594623b906876bc48a0)
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