Skip to content

Commit

Permalink
core: add interface to load user TAs
Browse files Browse the repository at this point in the history
Some use cases may require custom load and verification methods for
user-mode Trusted Applications. Introduce struct user_ta_store_ops with
open(), get_size(), read() and close() functions to abstract these
tasks from the ELF loader code. Do the communication with
tee-supplicant as well as the hashing and signature verification of the
TA binary in core/arch/arm/kernel/ree_fs_ta.c, which may be disabled
and replaced by a different implementation if need be.

CC: Zeng Tao <prime.zeng@hisilicon.com>
Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
Tested-by: Jerome Forissier <jerome.forissier@linaro.org> (HiKey, QEMU)
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
  • Loading branch information
jforissier committed May 10, 2017
1 parent 762b7d0 commit ee664c1
Show file tree
Hide file tree
Showing 8 changed files with 451 additions and 276 deletions.
9 changes: 9 additions & 0 deletions core/arch/arm/include/kernel/user_ta.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,25 @@ static inline struct user_ta_ctx *to_user_ta_ctx(struct tee_ta_ctx *ctx)
return container_of(ctx, struct user_ta_ctx, ctx);
}

struct user_ta_store_ops;

#ifdef CFG_WITH_USER_TA
TEE_Result tee_ta_init_user_ta_session(const TEE_UUID *uuid,
struct tee_ta_session *s);
TEE_Result tee_ta_register_ta_store(const struct user_ta_store_ops *ops);
#else
static inline TEE_Result tee_ta_init_user_ta_session(
const TEE_UUID *uuid __unused,
struct tee_ta_session *s __unused)
{
return TEE_ERROR_ITEM_NOT_FOUND;
}

static inline TEE_Result tee_ta_register_ta_store(
const struct user_ta_store_ops *ops __unused)
{
return TEE_ERROR_NOT_SUPPORTED;
}
#endif

#endif /*KERNEL_USER_TA_H*/
50 changes: 27 additions & 23 deletions core/arch/arm/kernel/elf_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include <tee_api_types.h>
#include <tee_api_defines.h>
#include <kernel/tee_misc.h>
#include <tee/tee_cryp_provider.h>
#include <kernel/user_ta.h>
#include <stdlib.h>
#include <string.h>
#include <util.h>
Expand All @@ -41,11 +41,9 @@
struct elf_load_state {
bool is_32bit;

uint8_t *nwdata;
size_t nwdata_len;

void *hash_ctx;
uint32_t hash_algo;
struct user_ta_store_handle *ta_handle;
const struct user_ta_store_ops *ta_store;
size_t data_len;

size_t next_offs;

Expand Down Expand Up @@ -139,16 +137,15 @@ static TEE_Result advance_to(struct elf_load_state *state, size_t offs)
if (offs == state->next_offs)
return TEE_SUCCESS;

if (offs > state->nwdata_len)
if (offs > state->data_len)
return TEE_ERROR_SECURITY;

res = crypto_ops.hash.update(state->hash_ctx, state->hash_algo,
state->nwdata + state->next_offs,
offs - state->next_offs);
res = state->ta_store->read(state->ta_handle, NULL,
offs - state->next_offs);
if (res != TEE_SUCCESS)
return res;
state->next_offs = offs;
return res;
return TEE_SUCCESS;
}

static TEE_Result copy_to(struct elf_load_state *state,
Expand All @@ -165,12 +162,12 @@ static TEE_Result copy_to(struct elf_load_state *state,

/* Check for integer overflow */
if ((len + dst_offs) < dst_offs || (len + dst_offs) > dst_size ||
(len + offs) < offs || (len + offs) > state->nwdata_len)
(len + offs) < offs || (len + offs) > state->data_len)
return TEE_ERROR_SECURITY;

memcpy((uint8_t *)dst + dst_offs, state->nwdata + offs, len);
res = crypto_ops.hash.update(state->hash_ctx, state->hash_algo,
(uint8_t *)dst + dst_offs, len);
res = state->ta_store->read(state->ta_handle,
(uint8_t *)dst + dst_offs,
len);
if (res != TEE_SUCCESS)
return res;
state->next_offs = offs + len;
Expand All @@ -194,20 +191,27 @@ static TEE_Result alloc_and_copy_to(void **p, struct elf_load_state *state,
return res;
}

TEE_Result elf_load_init(void *hash_ctx, uint32_t hash_algo, uint8_t *nwdata,
size_t nwdata_len, struct elf_load_state **ret_state)
TEE_Result elf_load_init(const struct user_ta_store_ops *ta_store,
struct user_ta_store_handle *ta_handle,
struct elf_load_state **ret_state)
{
struct elf_load_state *state;
TEE_Result res;

state = calloc(1, sizeof(*state));
if (!state)
return TEE_ERROR_OUT_OF_MEMORY;
state->hash_ctx = hash_ctx;
state->hash_algo = hash_algo;
state->nwdata = nwdata;
state->nwdata_len = nwdata_len;

state->ta_store = ta_store;
state->ta_handle = ta_handle;
res = ta_store->get_size(ta_handle, &state->data_len);
if (res != TEE_SUCCESS) {
free(state);
return res;
}

*ret_state = state;
return TEE_SUCCESS;
return res;
}

static TEE_Result e32_load_ehdr(struct elf_load_state *state, Elf32_Ehdr *ehdr)
Expand Down Expand Up @@ -639,7 +643,7 @@ TEE_Result elf_load_body(struct elf_load_state *state, vaddr_t vabase)
}

/* Hash until end of ELF */
res = advance_to(state, state->nwdata_len);
res = advance_to(state, state->data_len);
if (res != TEE_SUCCESS)
return res;

Expand Down
37 changes: 35 additions & 2 deletions core/arch/arm/kernel/elf_load.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,41 @@

struct elf_load_state;

TEE_Result elf_load_init(void *hash_ctx, uint32_t hash_algo, uint8_t *nwdata,
size_t nwdata_len, struct elf_load_state **state);
struct user_ta_store_handle;
struct user_ta_store_ops {
/*
* Open a TA. Does not guarantee that the TA is valid or even exists.
*/
TEE_Result (*open)(const TEE_UUID *uuid,
struct user_ta_store_handle **h);
/*
* Return the size of the unencrypted TA binary, that is: the TA
* header (struct ta_head) plus the ELF data.
*/
TEE_Result (*get_size)(const struct user_ta_store_handle *h,
size_t *size);
/*
* Read the TA sequentially, from the start of the TA header (struct
* ta_head) up to the end of the ELF.
* The TEE core is expected to read *exactly* get_size() bytes in total
* unless an error occurs. Therefore, an implementation may rely on the
* condition (current offset == total size) to detect the last call to
* this function.
* @data: pointer to secure memory where the TA bytes should be copied.
* If @data == NULL and @len != 0, the function should just skip @len
* bytes.
*/
TEE_Result (*read)(struct user_ta_store_handle *h, void *data,
size_t len);
/*
* Close a TA handle. Do nothing if @h == NULL.
*/
void (*close)(struct user_ta_store_handle *h);
};

TEE_Result elf_load_init(const struct user_ta_store_ops *ta_store,
struct user_ta_store_handle *ta_handle,
struct elf_load_state **state);
TEE_Result elf_load_head(struct elf_load_state *state, size_t head_size,
void **head, size_t *vasize, bool *is_32bit);
TEE_Result elf_load_body(struct elf_load_state *state, vaddr_t vabase);
Expand Down
Loading

0 comments on commit ee664c1

Please sign in to comment.