xref: /aosp_15_r20/external/avb/libavb/avb_property_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_property_descriptor.h"
26*d289c2baSAndroid Build Coastguard Worker #include "avb_util.h"
27*d289c2baSAndroid Build Coastguard Worker 
avb_property_descriptor_validate_and_byteswap(const AvbPropertyDescriptor * src,AvbPropertyDescriptor * dest)28*d289c2baSAndroid Build Coastguard Worker bool avb_property_descriptor_validate_and_byteswap(
29*d289c2baSAndroid Build Coastguard Worker     const AvbPropertyDescriptor* src, AvbPropertyDescriptor* dest) {
30*d289c2baSAndroid Build Coastguard Worker   uint64_t expected_size;
31*d289c2baSAndroid Build Coastguard Worker 
32*d289c2baSAndroid Build Coastguard Worker   avb_memcpy(dest, src, sizeof(AvbPropertyDescriptor));
33*d289c2baSAndroid Build Coastguard Worker 
34*d289c2baSAndroid Build Coastguard Worker   if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
35*d289c2baSAndroid Build Coastguard Worker                                             (AvbDescriptor*)dest))
36*d289c2baSAndroid Build Coastguard Worker     return false;
37*d289c2baSAndroid Build Coastguard Worker 
38*d289c2baSAndroid Build Coastguard Worker   if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
39*d289c2baSAndroid Build Coastguard Worker     avb_error("Invalid tag for property descriptor.\n");
40*d289c2baSAndroid Build Coastguard Worker     return false;
41*d289c2baSAndroid Build Coastguard Worker   }
42*d289c2baSAndroid Build Coastguard Worker 
43*d289c2baSAndroid Build Coastguard Worker   dest->key_num_bytes = avb_be64toh(dest->key_num_bytes);
44*d289c2baSAndroid Build Coastguard Worker   dest->value_num_bytes = avb_be64toh(dest->value_num_bytes);
45*d289c2baSAndroid Build Coastguard Worker 
46*d289c2baSAndroid Build Coastguard Worker   /* Check that key and value are fully contained. */
47*d289c2baSAndroid Build Coastguard Worker   expected_size = sizeof(AvbPropertyDescriptor) - sizeof(AvbDescriptor) + 2;
48*d289c2baSAndroid Build Coastguard Worker   if (!avb_safe_add_to(&expected_size, dest->key_num_bytes) ||
49*d289c2baSAndroid Build Coastguard Worker       !avb_safe_add_to(&expected_size, dest->value_num_bytes)) {
50*d289c2baSAndroid Build Coastguard Worker     avb_error("Overflow while adding up sizes.\n");
51*d289c2baSAndroid Build Coastguard Worker     return false;
52*d289c2baSAndroid Build Coastguard Worker   }
53*d289c2baSAndroid Build Coastguard Worker   if (expected_size > dest->parent_descriptor.num_bytes_following) {
54*d289c2baSAndroid Build Coastguard Worker     avb_error("Descriptor payload size overflow.\n");
55*d289c2baSAndroid Build Coastguard Worker     return false;
56*d289c2baSAndroid Build Coastguard Worker   }
57*d289c2baSAndroid Build Coastguard Worker 
58*d289c2baSAndroid Build Coastguard Worker   return true;
59*d289c2baSAndroid Build Coastguard Worker }
60*d289c2baSAndroid Build Coastguard Worker 
61*d289c2baSAndroid Build Coastguard Worker typedef struct {
62*d289c2baSAndroid Build Coastguard Worker   const char* key;
63*d289c2baSAndroid Build Coastguard Worker   size_t key_size;
64*d289c2baSAndroid Build Coastguard Worker   const char* ret_value;
65*d289c2baSAndroid Build Coastguard Worker   size_t ret_value_size;
66*d289c2baSAndroid Build Coastguard Worker } PropertyIteratorData;
67*d289c2baSAndroid Build Coastguard Worker 
property_lookup_desc_foreach(const AvbDescriptor * header,void * user_data)68*d289c2baSAndroid Build Coastguard Worker static bool property_lookup_desc_foreach(const AvbDescriptor* header,
69*d289c2baSAndroid Build Coastguard Worker                                          void* user_data) {
70*d289c2baSAndroid Build Coastguard Worker   PropertyIteratorData* data = (PropertyIteratorData*)user_data;
71*d289c2baSAndroid Build Coastguard Worker   AvbPropertyDescriptor prop_desc;
72*d289c2baSAndroid Build Coastguard Worker   const uint8_t* p;
73*d289c2baSAndroid Build Coastguard Worker   bool ret = true;
74*d289c2baSAndroid Build Coastguard Worker 
75*d289c2baSAndroid Build Coastguard Worker   if (header->tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
76*d289c2baSAndroid Build Coastguard Worker     goto out;
77*d289c2baSAndroid Build Coastguard Worker   }
78*d289c2baSAndroid Build Coastguard Worker 
79*d289c2baSAndroid Build Coastguard Worker   if (!avb_property_descriptor_validate_and_byteswap(
80*d289c2baSAndroid Build Coastguard Worker           (const AvbPropertyDescriptor*)header, &prop_desc)) {
81*d289c2baSAndroid Build Coastguard Worker     goto out;
82*d289c2baSAndroid Build Coastguard Worker   }
83*d289c2baSAndroid Build Coastguard Worker 
84*d289c2baSAndroid Build Coastguard Worker   p = (const uint8_t*)header;
85*d289c2baSAndroid Build Coastguard Worker   if (p[sizeof(AvbPropertyDescriptor) + prop_desc.key_num_bytes] != 0) {
86*d289c2baSAndroid Build Coastguard Worker     avb_error("No terminating NUL byte in key.\n");
87*d289c2baSAndroid Build Coastguard Worker     goto out;
88*d289c2baSAndroid Build Coastguard Worker   }
89*d289c2baSAndroid Build Coastguard Worker 
90*d289c2baSAndroid Build Coastguard Worker   if (data->key_size == prop_desc.key_num_bytes) {
91*d289c2baSAndroid Build Coastguard Worker     if (avb_memcmp(p + sizeof(AvbPropertyDescriptor),
92*d289c2baSAndroid Build Coastguard Worker                    data->key,
93*d289c2baSAndroid Build Coastguard Worker                    data->key_size) == 0) {
94*d289c2baSAndroid Build Coastguard Worker       data->ret_value = (const char*)(p + sizeof(AvbPropertyDescriptor) +
95*d289c2baSAndroid Build Coastguard Worker                                       prop_desc.key_num_bytes + 1);
96*d289c2baSAndroid Build Coastguard Worker       data->ret_value_size = prop_desc.value_num_bytes;
97*d289c2baSAndroid Build Coastguard Worker       /* Stop iterating. */
98*d289c2baSAndroid Build Coastguard Worker       ret = false;
99*d289c2baSAndroid Build Coastguard Worker       goto out;
100*d289c2baSAndroid Build Coastguard Worker     }
101*d289c2baSAndroid Build Coastguard Worker   }
102*d289c2baSAndroid Build Coastguard Worker 
103*d289c2baSAndroid Build Coastguard Worker out:
104*d289c2baSAndroid Build Coastguard Worker   return ret;
105*d289c2baSAndroid Build Coastguard Worker }
106*d289c2baSAndroid Build Coastguard Worker 
avb_property_lookup(const uint8_t * image_data,size_t image_size,const char * key,size_t key_size,size_t * out_value_size)107*d289c2baSAndroid Build Coastguard Worker const char* avb_property_lookup(const uint8_t* image_data,
108*d289c2baSAndroid Build Coastguard Worker                                 size_t image_size,
109*d289c2baSAndroid Build Coastguard Worker                                 const char* key,
110*d289c2baSAndroid Build Coastguard Worker                                 size_t key_size,
111*d289c2baSAndroid Build Coastguard Worker                                 size_t* out_value_size) {
112*d289c2baSAndroid Build Coastguard Worker   PropertyIteratorData data;
113*d289c2baSAndroid Build Coastguard Worker 
114*d289c2baSAndroid Build Coastguard Worker   if (key_size == 0) {
115*d289c2baSAndroid Build Coastguard Worker     key_size = avb_strlen(key);
116*d289c2baSAndroid Build Coastguard Worker   }
117*d289c2baSAndroid Build Coastguard Worker 
118*d289c2baSAndroid Build Coastguard Worker   data.key = key;
119*d289c2baSAndroid Build Coastguard Worker   data.key_size = key_size;
120*d289c2baSAndroid Build Coastguard Worker 
121*d289c2baSAndroid Build Coastguard Worker   if (avb_descriptor_foreach(
122*d289c2baSAndroid Build Coastguard Worker           image_data, image_size, property_lookup_desc_foreach, &data) == 0) {
123*d289c2baSAndroid Build Coastguard Worker     if (out_value_size != NULL) {
124*d289c2baSAndroid Build Coastguard Worker       *out_value_size = data.ret_value_size;
125*d289c2baSAndroid Build Coastguard Worker     }
126*d289c2baSAndroid Build Coastguard Worker     return data.ret_value;
127*d289c2baSAndroid Build Coastguard Worker   }
128*d289c2baSAndroid Build Coastguard Worker 
129*d289c2baSAndroid Build Coastguard Worker   if (out_value_size != NULL) {
130*d289c2baSAndroid Build Coastguard Worker     *out_value_size = 0;
131*d289c2baSAndroid Build Coastguard Worker   }
132*d289c2baSAndroid Build Coastguard Worker   return NULL;
133*d289c2baSAndroid Build Coastguard Worker }
134*d289c2baSAndroid Build Coastguard Worker 
avb_property_lookup_uint64(const uint8_t * image_data,size_t image_size,const char * key,size_t key_size,uint64_t * out_value)135*d289c2baSAndroid Build Coastguard Worker bool avb_property_lookup_uint64(const uint8_t* image_data,
136*d289c2baSAndroid Build Coastguard Worker                                 size_t image_size,
137*d289c2baSAndroid Build Coastguard Worker                                 const char* key,
138*d289c2baSAndroid Build Coastguard Worker                                 size_t key_size,
139*d289c2baSAndroid Build Coastguard Worker                                 uint64_t* out_value) {
140*d289c2baSAndroid Build Coastguard Worker   const char* value;
141*d289c2baSAndroid Build Coastguard Worker   bool ret = false;
142*d289c2baSAndroid Build Coastguard Worker   uint64_t parsed_val;
143*d289c2baSAndroid Build Coastguard Worker   int base;
144*d289c2baSAndroid Build Coastguard Worker   int n;
145*d289c2baSAndroid Build Coastguard Worker 
146*d289c2baSAndroid Build Coastguard Worker   value = avb_property_lookup(image_data, image_size, key, key_size, NULL);
147*d289c2baSAndroid Build Coastguard Worker   if (value == NULL) {
148*d289c2baSAndroid Build Coastguard Worker     goto out;
149*d289c2baSAndroid Build Coastguard Worker   }
150*d289c2baSAndroid Build Coastguard Worker 
151*d289c2baSAndroid Build Coastguard Worker   base = 10;
152*d289c2baSAndroid Build Coastguard Worker   if (avb_memcmp(value, "0x", 2) == 0) {
153*d289c2baSAndroid Build Coastguard Worker     base = 16;
154*d289c2baSAndroid Build Coastguard Worker     value += 2;
155*d289c2baSAndroid Build Coastguard Worker   }
156*d289c2baSAndroid Build Coastguard Worker 
157*d289c2baSAndroid Build Coastguard Worker   parsed_val = 0;
158*d289c2baSAndroid Build Coastguard Worker   for (n = 0; value[n] != '\0'; n++) {
159*d289c2baSAndroid Build Coastguard Worker     int c = value[n];
160*d289c2baSAndroid Build Coastguard Worker     int digit;
161*d289c2baSAndroid Build Coastguard Worker 
162*d289c2baSAndroid Build Coastguard Worker     parsed_val *= base;
163*d289c2baSAndroid Build Coastguard Worker 
164*d289c2baSAndroid Build Coastguard Worker     if (c >= '0' && c <= '9') {
165*d289c2baSAndroid Build Coastguard Worker       digit = c - '0';
166*d289c2baSAndroid Build Coastguard Worker     } else if (base == 16 && c >= 'a' && c <= 'f') {
167*d289c2baSAndroid Build Coastguard Worker       digit = c - 'a' + 10;
168*d289c2baSAndroid Build Coastguard Worker     } else if (base == 16 && c >= 'A' && c <= 'F') {
169*d289c2baSAndroid Build Coastguard Worker       digit = c - 'A' + 10;
170*d289c2baSAndroid Build Coastguard Worker     } else {
171*d289c2baSAndroid Build Coastguard Worker       avb_error("Invalid digit.\n");
172*d289c2baSAndroid Build Coastguard Worker       goto out;
173*d289c2baSAndroid Build Coastguard Worker     }
174*d289c2baSAndroid Build Coastguard Worker 
175*d289c2baSAndroid Build Coastguard Worker     parsed_val += digit;
176*d289c2baSAndroid Build Coastguard Worker   }
177*d289c2baSAndroid Build Coastguard Worker 
178*d289c2baSAndroid Build Coastguard Worker   ret = true;
179*d289c2baSAndroid Build Coastguard Worker   if (out_value != NULL) {
180*d289c2baSAndroid Build Coastguard Worker     *out_value = parsed_val;
181*d289c2baSAndroid Build Coastguard Worker   }
182*d289c2baSAndroid Build Coastguard Worker 
183*d289c2baSAndroid Build Coastguard Worker out:
184*d289c2baSAndroid Build Coastguard Worker   return ret;
185*d289c2baSAndroid Build Coastguard Worker }
186