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