blob: 4b2daefaecd593a423a7cfa1c6b5a8050185ae9c [file] [log] [blame]
/*
* Copyright (c) 2021 Google Inc. All rights reserved
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define TLOG_TAG "app_manifest"
#include <assert.h>
#include <inttypes.h>
#include <lib/app_manifest/app_manifest.h>
#include <lk/macros.h>
#include <string.h>
#include <trusty_log.h>
#include <uapi/err.h>
int app_manifest_iterator_reset(struct app_manifest_iterator* iterator,
const char* manifest_data,
size_t manifest_size) {
assert(iterator);
iterator->manifest_data = manifest_data;
iterator->manifest_size = manifest_size;
iterator->index = 0;
iterator->app_name = "<unknown>";
iterator->error = NO_ERROR;
return NO_ERROR;
}
/*
* Helper function that gets the pointer to the next object in the manifest
* after checking that the object does not extend past the end of the manifest
*/
static inline const void* app_manifest_get_ptr(
struct app_manifest_iterator* iterator,
size_t size) {
const void* curr = &iterator->manifest_data[iterator->index];
if (size > iterator->manifest_size - iterator->index) {
iterator->error = ERR_NOT_VALID;
return NULL;
}
iterator->index += size;
return curr;
}
/*
* Helper function that reads a sized object from the manifest after
* checking that the object does not extend past the end of the manifest
*/
static inline void app_manifest_read_ptr(struct app_manifest_iterator* iterator,
void* dest,
size_t size) {
const void* src = app_manifest_get_ptr(iterator, size);
if (src) {
memcpy(dest, src, size);
}
}
/* Helper function that reads one entry and advances the iterator */
static inline uint32_t app_manifest_read_entry(
struct app_manifest_iterator* iterator) {
uint32_t entry = 0;
app_manifest_read_ptr(iterator, &entry, sizeof(entry));
return entry;
}
static inline const char* app_manifest_read_string(
struct app_manifest_iterator* iterator,
uint32_t string_size,
const char* string_name) {
uint32_t string_entries;
size_t string_length;
const char* string;
/* string size with padding */
string_entries = round_up(string_size, sizeof(uint32_t));
if (string_entries == 0) {
TLOGE("invalid %s-size 0x%" PRIx32 "/0x%" PRIx32 "\n", string_name,
string_size, string_entries);
return NULL;
}
string = app_manifest_get_ptr(iterator, string_entries);
if (!string) {
TLOGE("manifest too small %zu, missing %s, "
"%s-size 0x%" PRIx32 "/0x%" PRIx32 "\n",
iterator->manifest_size, string_name, string_name, string_size,
string_entries);
return NULL;
}
/*
* Make sure that the string has exactly one \0 and it's the last character
*/
string_length = strnlen(string, string_size);
if (string_length != string_size - 1) {
TLOGE("%s-length invalid 0x%zx, %s-size 0x%" PRIx32 "/0x%" PRIx32 "\n",
string_name, string_length, string_name, string_size,
string_entries);
return NULL;
}
return string;
}
bool app_manifest_iterator_next(struct app_manifest_iterator* iterator,
struct app_manifest_config_entry* entry,
int* out_error) {
assert(entry);
if (iterator->index >= iterator->manifest_size) {
if (out_error) {
*out_error = NO_ERROR;
}
return false;
}
/*
* uuid and app_name are special cases: we return them
* using pseudo-keys because they're not present in the entries
*/
uint32_t manifest_key;
if (iterator->index == 0) {
manifest_key = APP_MANIFEST_CONFIG_KEY_UUID;
} else if (iterator->index == sizeof(uuid_t)) {
manifest_key = APP_MANIFEST_CONFIG_KEY_APP_NAME;
} else {
manifest_key = app_manifest_read_entry(iterator);
}
uint32_t string_size;
const char* string;
switch (manifest_key) {
case APP_MANIFEST_CONFIG_KEY_MIN_STACK_SIZE:
entry->value.min_stack_size = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing MIN_STACK_SIZE value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_MIN_SHADOW_STACK_SIZE:
entry->value.min_shadow_stack_size = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing MIN_SHADOW_STACK_SIZE value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_MIN_HEAP_SIZE:
entry->value.min_heap_size = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing MIN_HEAP_SIZE value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_MAP_MEM:
entry->value.mem_map.id = app_manifest_read_entry(iterator);
/*
* TODO: add big endian support? The manifest_compiler wrote the
* next two entries as 64 bit numbers with the byte order of the
* build machine. The code below assumes the manifest data and
* device are both little-endian.
*/
entry->value.mem_map.offset = app_manifest_read_entry(iterator);
entry->value.mem_map.offset |=
(uint64_t)app_manifest_read_entry(iterator) << 32;
entry->value.mem_map.size = app_manifest_read_entry(iterator);
entry->value.mem_map.size |= (uint64_t)app_manifest_read_entry(iterator)
<< 32;
entry->value.mem_map.arch_mmu_flags = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing MAP_MEM value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_MGMT_FLAGS:
entry->value.mgmt_flags = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing MGMT_FLAGS value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_START_PORT:
entry->value.start_port.flags = app_manifest_read_entry(iterator);
string_size = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing START_PORT values of app %s\n",
iterator->app_name);
goto error;
}
string = app_manifest_read_string(iterator, string_size,
"start-port-name");
if (!string) {
goto error;
}
entry->value.start_port.name_size = string_size;
entry->value.start_port.name = string;
break;
case APP_MANIFEST_CONFIG_KEY_PINNED_CPU:
entry->value.pinned_cpu = (int)app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing PINNED_CPU value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_PRIORITY:
entry->value.priority = (int)app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing PRIORITY value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_VERSION:
entry->value.version = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing VERSION value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_MIN_VERSION:
entry->value.min_version = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing MIN_VERSION value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_APPLOADER_FLAGS:
entry->value.apploader_flags = app_manifest_read_entry(iterator);
if (iterator->error != NO_ERROR) {
TLOGE("manifest missing APPLOADER_FLAGS value of app %s\n",
iterator->app_name);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_UUID:
app_manifest_read_ptr(iterator, &entry->value.uuid,
sizeof(entry->value.uuid));
if (iterator->error != NO_ERROR) {
TLOGE("manifest too small %zu, missing uuid\n",
iterator->manifest_size);
goto error;
}
break;
case APP_MANIFEST_CONFIG_KEY_APP_NAME:
string_size = app_manifest_read_entry(iterator);
string = app_manifest_read_string(iterator, string_size, "app-name");
if (!string) {
goto error;
}
entry->value.app_name = string;
iterator->app_name = string;
break;
default:
TLOGE("manifest contains unknown config key %" PRIu32 " for app %s\n",
manifest_key, iterator->app_name);
goto error;
}
assert(iterator->error == NO_ERROR);
entry->key = manifest_key;
if (out_error) {
*out_error = NO_ERROR;
}
return true;
error:
if (out_error) {
if (iterator->error != NO_ERROR) {
*out_error = iterator->error;
} else {
*out_error = ERR_NOT_VALID;
}
}
return false;
}