1 /*
2 * Copyright (c) 2021 Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * 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 NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #define TLOG_TAG "app_manifest"
25
26 #include <assert.h>
27 #include <inttypes.h>
28 #include <lib/app_manifest/app_manifest.h>
29 #include <lk/macros.h>
30 #include <string.h>
31 #include <trusty_log.h>
32 #include <uapi/err.h>
33
app_manifest_iterator_reset(struct app_manifest_iterator * iterator,const char * manifest_data,size_t manifest_size)34 int app_manifest_iterator_reset(struct app_manifest_iterator* iterator,
35 const char* manifest_data,
36 size_t manifest_size) {
37 assert(iterator);
38
39 iterator->manifest_data = manifest_data;
40 iterator->manifest_size = manifest_size;
41 iterator->index = 0;
42 iterator->app_name = "<unknown>";
43 iterator->error = NO_ERROR;
44
45 return NO_ERROR;
46 }
47
48 /*
49 * Helper function that gets the pointer to the next object in the manifest
50 * after checking that the object does not extend past the end of the manifest
51 */
app_manifest_get_ptr(struct app_manifest_iterator * iterator,size_t size)52 static inline const void* app_manifest_get_ptr(
53 struct app_manifest_iterator* iterator,
54 size_t size) {
55 const void* curr = &iterator->manifest_data[iterator->index];
56 if (size > iterator->manifest_size - iterator->index) {
57 iterator->error = ERR_NOT_VALID;
58 return NULL;
59 }
60 iterator->index += size;
61 return curr;
62 }
63
64 /*
65 * Helper function that reads a sized object from the manifest after
66 * checking that the object does not extend past the end of the manifest
67 */
app_manifest_read_ptr(struct app_manifest_iterator * iterator,void * dest,size_t size)68 static inline void app_manifest_read_ptr(struct app_manifest_iterator* iterator,
69 void* dest,
70 size_t size) {
71 const void* src = app_manifest_get_ptr(iterator, size);
72 if (src) {
73 memcpy(dest, src, size);
74 }
75 }
76
77 /* Helper function that reads one entry and advances the iterator */
app_manifest_read_entry(struct app_manifest_iterator * iterator)78 static inline uint32_t app_manifest_read_entry(
79 struct app_manifest_iterator* iterator) {
80 uint32_t entry = 0;
81 app_manifest_read_ptr(iterator, &entry, sizeof(entry));
82 return entry;
83 }
84
app_manifest_read_string(struct app_manifest_iterator * iterator,uint32_t string_size,const char * string_name)85 static inline const char* app_manifest_read_string(
86 struct app_manifest_iterator* iterator,
87 uint32_t string_size,
88 const char* string_name) {
89 uint32_t string_entries;
90 size_t string_length;
91 const char* string;
92
93 /* string size with padding */
94 string_entries = round_up(string_size, sizeof(uint32_t));
95 if (string_entries == 0) {
96 TLOGE("invalid %s-size 0x%" PRIx32 "/0x%" PRIx32 "\n", string_name,
97 string_size, string_entries);
98 return NULL;
99 }
100
101 string = app_manifest_get_ptr(iterator, string_entries);
102 if (!string) {
103 TLOGE("manifest too small %zu, missing %s, "
104 "%s-size 0x%" PRIx32 "/0x%" PRIx32 "\n",
105 iterator->manifest_size, string_name, string_name, string_size,
106 string_entries);
107 return NULL;
108 }
109
110 /*
111 * Make sure that the string has exactly one \0 and it's the last character
112 */
113 string_length = strnlen(string, string_size);
114 if (string_length != string_size - 1) {
115 TLOGE("%s-length invalid 0x%zx, %s-size 0x%" PRIx32 "/0x%" PRIx32 "\n",
116 string_name, string_length, string_name, string_size,
117 string_entries);
118 return NULL;
119 }
120
121 return string;
122 }
123
app_manifest_iterator_next(struct app_manifest_iterator * iterator,struct app_manifest_config_entry * entry,int * out_error)124 bool app_manifest_iterator_next(struct app_manifest_iterator* iterator,
125 struct app_manifest_config_entry* entry,
126 int* out_error) {
127 assert(entry);
128
129 if (iterator->index >= iterator->manifest_size) {
130 if (out_error) {
131 *out_error = NO_ERROR;
132 }
133 return false;
134 }
135
136 /*
137 * uuid and app_name are special cases: we return them
138 * using pseudo-keys because they're not present in the entries
139 */
140 uint32_t manifest_key;
141 if (iterator->index == 0) {
142 manifest_key = APP_MANIFEST_CONFIG_KEY_UUID;
143 } else if (iterator->index == sizeof(uuid_t)) {
144 manifest_key = APP_MANIFEST_CONFIG_KEY_APP_NAME;
145 } else {
146 manifest_key = app_manifest_read_entry(iterator);
147 }
148
149 uint32_t string_size;
150 const char* string;
151 switch (manifest_key) {
152 case APP_MANIFEST_CONFIG_KEY_MIN_STACK_SIZE:
153 entry->value.min_stack_size = app_manifest_read_entry(iterator);
154 if (iterator->error != NO_ERROR) {
155 TLOGE("manifest missing MIN_STACK_SIZE value of app %s\n",
156 iterator->app_name);
157 goto error;
158 }
159 break;
160 case APP_MANIFEST_CONFIG_KEY_MIN_SHADOW_STACK_SIZE:
161 entry->value.min_shadow_stack_size = app_manifest_read_entry(iterator);
162 if (iterator->error != NO_ERROR) {
163 TLOGE("manifest missing MIN_SHADOW_STACK_SIZE value of app %s\n",
164 iterator->app_name);
165 goto error;
166 }
167 break;
168
169 case APP_MANIFEST_CONFIG_KEY_MIN_HEAP_SIZE:
170 entry->value.min_heap_size = app_manifest_read_entry(iterator);
171 if (iterator->error != NO_ERROR) {
172 TLOGE("manifest missing MIN_HEAP_SIZE value of app %s\n",
173 iterator->app_name);
174 goto error;
175 }
176 break;
177
178 case APP_MANIFEST_CONFIG_KEY_MAP_MEM:
179 entry->value.mem_map.id = app_manifest_read_entry(iterator);
180 /*
181 * TODO: add big endian support? The manifest_compiler wrote the
182 * next two entries as 64 bit numbers with the byte order of the
183 * build machine. The code below assumes the manifest data and
184 * device are both little-endian.
185 */
186 entry->value.mem_map.offset = app_manifest_read_entry(iterator);
187 entry->value.mem_map.offset |=
188 (uint64_t)app_manifest_read_entry(iterator) << 32;
189 entry->value.mem_map.size = app_manifest_read_entry(iterator);
190 entry->value.mem_map.size |= (uint64_t)app_manifest_read_entry(iterator)
191 << 32;
192 entry->value.mem_map.arch_mmu_flags = app_manifest_read_entry(iterator);
193 if (iterator->error != NO_ERROR) {
194 TLOGE("manifest missing MAP_MEM value of app %s\n",
195 iterator->app_name);
196 goto error;
197 }
198 break;
199
200 case APP_MANIFEST_CONFIG_KEY_MGMT_FLAGS:
201 entry->value.mgmt_flags = app_manifest_read_entry(iterator);
202 if (iterator->error != NO_ERROR) {
203 TLOGE("manifest missing MGMT_FLAGS value of app %s\n",
204 iterator->app_name);
205 goto error;
206 }
207 break;
208
209 case APP_MANIFEST_CONFIG_KEY_START_PORT:
210 entry->value.start_port.flags = app_manifest_read_entry(iterator);
211
212 string_size = app_manifest_read_entry(iterator);
213 if (iterator->error != NO_ERROR) {
214 TLOGE("manifest missing START_PORT values of app %s\n",
215 iterator->app_name);
216 goto error;
217 }
218
219 string = app_manifest_read_string(iterator, string_size,
220 "start-port-name");
221 if (!string) {
222 goto error;
223 }
224
225 entry->value.start_port.name_size = string_size;
226 entry->value.start_port.name = string;
227 break;
228
229 case APP_MANIFEST_CONFIG_KEY_PINNED_CPU:
230 entry->value.pinned_cpu = (int)app_manifest_read_entry(iterator);
231 if (iterator->error != NO_ERROR) {
232 TLOGE("manifest missing PINNED_CPU value of app %s\n",
233 iterator->app_name);
234 goto error;
235 }
236 break;
237
238 case APP_MANIFEST_CONFIG_KEY_PRIORITY:
239 entry->value.priority = (int)app_manifest_read_entry(iterator);
240 if (iterator->error != NO_ERROR) {
241 TLOGE("manifest missing PRIORITY value of app %s\n",
242 iterator->app_name);
243 goto error;
244 }
245 break;
246
247 case APP_MANIFEST_CONFIG_KEY_VERSION:
248 entry->value.version = app_manifest_read_entry(iterator);
249 if (iterator->error != NO_ERROR) {
250 TLOGE("manifest missing VERSION value of app %s\n",
251 iterator->app_name);
252 goto error;
253 }
254 break;
255
256 case APP_MANIFEST_CONFIG_KEY_MIN_VERSION:
257 entry->value.min_version = app_manifest_read_entry(iterator);
258 if (iterator->error != NO_ERROR) {
259 TLOGE("manifest missing MIN_VERSION value of app %s\n",
260 iterator->app_name);
261 goto error;
262 }
263 break;
264
265 case APP_MANIFEST_CONFIG_KEY_APPLOADER_FLAGS:
266 entry->value.apploader_flags = app_manifest_read_entry(iterator);
267 if (iterator->error != NO_ERROR) {
268 TLOGE("manifest missing APPLOADER_FLAGS value of app %s\n",
269 iterator->app_name);
270 goto error;
271 }
272 break;
273
274 case APP_MANIFEST_CONFIG_KEY_UUID:
275 app_manifest_read_ptr(iterator, &entry->value.uuid,
276 sizeof(entry->value.uuid));
277 if (iterator->error != NO_ERROR) {
278 TLOGE("manifest too small %zu, missing uuid\n",
279 iterator->manifest_size);
280 goto error;
281 }
282 break;
283
284 case APP_MANIFEST_CONFIG_KEY_APP_NAME:
285 string_size = app_manifest_read_entry(iterator);
286 string = app_manifest_read_string(iterator, string_size, "app-name");
287 if (!string) {
288 goto error;
289 }
290
291 entry->value.app_name = string;
292 iterator->app_name = string;
293 break;
294
295 default:
296 TLOGE("manifest contains unknown config key %" PRIu32 " for app %s\n",
297 manifest_key, iterator->app_name);
298 goto error;
299 }
300
301 assert(iterator->error == NO_ERROR);
302 entry->key = manifest_key;
303 if (out_error) {
304 *out_error = NO_ERROR;
305 }
306 return true;
307
308 error:
309 if (out_error) {
310 if (iterator->error != NO_ERROR) {
311 *out_error = iterator->error;
312 } else {
313 *out_error = ERR_NOT_VALID;
314 }
315 }
316 return false;
317 }
318