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