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