diff --git a/core/arch/arm/include/kernel/user_ta.h b/core/arch/arm/include/kernel/user_ta.h index 196c0af2a40..3b980fe86a0 100644 --- a/core/arch/arm/include/kernel/user_ta.h +++ b/core/arch/arm/include/kernel/user_ta.h @@ -78,9 +78,12 @@ 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, @@ -88,6 +91,12 @@ static inline TEE_Result tee_ta_init_user_ta_session( { 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*/ diff --git a/core/arch/arm/kernel/elf_load.c b/core/arch/arm/kernel/elf_load.c index b1d6102b577..e66633eeb36 100644 --- a/core/arch/arm/kernel/elf_load.c +++ b/core/arch/arm/kernel/elf_load.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -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; @@ -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, @@ -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; @@ -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) @@ -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; diff --git a/core/arch/arm/kernel/elf_load.h b/core/arch/arm/kernel/elf_load.h index 4944e3a3395..95743f24e95 100644 --- a/core/arch/arm/kernel/elf_load.h +++ b/core/arch/arm/kernel/elf_load.h @@ -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); diff --git a/core/arch/arm/kernel/ree_fs_ta.c b/core/arch/arm/kernel/ree_fs_ta.c new file mode 100644 index 00000000000..9773dfecab1 --- /dev/null +++ b/core/arch/arm/kernel/ree_fs_ta.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf_load.h" + +struct user_ta_store_handle { + struct shdr *nw_ta; /* Non-secure (shared memory) */ + size_t nw_ta_size; + uint64_t cookie; + size_t offs; + struct shdr *shdr; /* Verified secure copy of @nw_ta's signed header */ + void *hash_ctx; + uint32_t hash_algo; +}; + +static TEE_Result alloc_and_copy_shdr(struct shdr **shdr, + const struct shdr *nw_ta, + size_t ta_size) +{ + size_t shdr_size; + + if (ta_size < sizeof(struct shdr)) + return TEE_ERROR_SECURITY; + shdr_size = SHDR_GET_SIZE(nw_ta); + if (ta_size < shdr_size) + return TEE_ERROR_SECURITY; + *shdr = malloc(shdr_size); + if (!*shdr) + return TEE_ERROR_SECURITY; + memcpy(*shdr, nw_ta, shdr_size); + if (shdr_size != SHDR_GET_SIZE(*shdr)) { + free(*shdr); + return TEE_ERROR_SECURITY; + } + return TEE_SUCCESS; +} + +static TEE_Result check_shdr(struct shdr *shdr) +{ + struct rsa_public_key key; + TEE_Result res; + uint32_t e = TEE_U32_TO_BIG_ENDIAN(ta_pub_key_exponent); + size_t hash_size; + + if (shdr->magic != SHDR_MAGIC || shdr->img_type != SHDR_TA) + return TEE_ERROR_SECURITY; + + if (TEE_ALG_GET_MAIN_ALG(shdr->algo) != TEE_MAIN_ALGO_RSA) + return TEE_ERROR_SECURITY; + + res = tee_hash_get_digest_size(TEE_DIGEST_HASH_TO_ALGO(shdr->algo), + &hash_size); + if (res != TEE_SUCCESS) + return res; + if (hash_size != shdr->hash_size) + return TEE_ERROR_SECURITY; + + if (!crypto_ops.acipher.alloc_rsa_public_key || + !crypto_ops.acipher.free_rsa_public_key || + !crypto_ops.acipher.rsassa_verify || + !crypto_ops.bignum.bin2bn) + return TEE_ERROR_NOT_SUPPORTED; + + res = crypto_ops.acipher.alloc_rsa_public_key(&key, shdr->sig_size); + if (res != TEE_SUCCESS) + return res; + + res = crypto_ops.bignum.bin2bn((uint8_t *)&e, sizeof(e), key.e); + if (res != TEE_SUCCESS) + goto out; + res = crypto_ops.bignum.bin2bn(ta_pub_key_modulus, + ta_pub_key_modulus_size, key.n); + if (res != TEE_SUCCESS) + goto out; + + res = crypto_ops.acipher.rsassa_verify(shdr->algo, &key, -1, + SHDR_GET_HASH(shdr), shdr->hash_size, + SHDR_GET_SIG(shdr), shdr->sig_size); +out: + crypto_ops.acipher.free_rsa_public_key(&key); + if (res != TEE_SUCCESS) + return TEE_ERROR_SECURITY; + return TEE_SUCCESS; +} +/* + * Load a TA via RPC with UUID defined by input param @uuid. The virtual + * address of the raw TA binary is received in out parameter @ta. + */ +static TEE_Result rpc_load(const TEE_UUID *uuid, struct shdr **ta, + uint64_t *cookie_ta, size_t *ta_size) +{ + TEE_Result res; + struct optee_msg_param params[2]; + paddr_t phta = 0; + uint64_t cta = 0; + + if (!uuid || !ta || !cookie_ta) + return TEE_ERROR_BAD_PARAMETERS; + + memset(params, 0, sizeof(params)); + params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + tee_uuid_to_octets((void *)¶ms[0].u.value, uuid); + params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; + params[1].u.tmem.buf_ptr = 0; + params[1].u.tmem.size = 0; + params[1].u.tmem.shm_ref = 0; + + res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_LOAD_TA, 2, params); + if (res != TEE_SUCCESS) + return res; + + thread_rpc_alloc_payload(params[1].u.tmem.size, &phta, &cta); + if (!phta) + return TEE_ERROR_OUT_OF_MEMORY; + + *ta = phys_to_virt(phta, MEM_AREA_NSEC_SHM); + /* We don't expect NULL as thread_rpc_alloc_payload() was successful */ + assert(*ta); + *cookie_ta = cta; + *ta_size = params[1].u.tmem.size; + + params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + tee_uuid_to_octets((void *)¶ms[0].u.value, uuid); + params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; + params[1].u.tmem.buf_ptr = phta; + params[1].u.tmem.shm_ref = cta; + /* Note that params[1].u.tmem.size is already assigned */ + + res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_LOAD_TA, 2, params); + if (res != TEE_SUCCESS) + thread_rpc_free_payload(cta); + return res; +} + +static TEE_Result ta_open(const TEE_UUID *uuid, + struct user_ta_store_handle **h) +{ + struct user_ta_store_handle *handle; + struct shdr *shdr = NULL; + void *hash_ctx = NULL; + size_t hash_ctx_size; + uint32_t hash_algo; + struct shdr *ta = NULL; + size_t ta_size = 0; + uint64_t cookie = 0; + TEE_Result res; + + if (!crypto_ops.hash.get_ctx_size || + !crypto_ops.hash.init || + !crypto_ops.hash.update) + return TEE_ERROR_NOT_SUPPORTED; + + handle = calloc(1, sizeof(*handle)); + if (!handle) + return TEE_ERROR_OUT_OF_MEMORY; + + /* Request TA from tee-supplicant */ + res = rpc_load(uuid, &ta, &cookie, &ta_size); + if (res != TEE_SUCCESS) + goto error; + + /* Make secure copy of signed header */ + res = alloc_and_copy_shdr(&shdr, ta, ta_size); + if (res != TEE_SUCCESS) + goto error_free_payload; + + /* Validate header signature */ + res = check_shdr(shdr); + if (res != TEE_SUCCESS) + goto error_free_payload; + + /* + * Initialize a hash context and run the algorithm over the signed + * header (less the final file hash and its signature of course) + */ + hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo); + res = crypto_ops.hash.get_ctx_size(hash_algo, &hash_ctx_size); + if (res != TEE_SUCCESS) + goto error_free_payload; + hash_ctx = malloc(hash_ctx_size); + if (!hash_ctx) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto error_free_payload; + } + res = crypto_ops.hash.init(hash_ctx, hash_algo); + if (res != TEE_SUCCESS) + goto error_free_payload; + res = crypto_ops.hash.update(hash_ctx, hash_algo, (uint8_t *)shdr, + sizeof(*shdr)); + if (res != TEE_SUCCESS) + goto error_free_payload; + + if (ta_size != SHDR_GET_SIZE(shdr) + shdr->img_size) { + res = TEE_ERROR_SECURITY; + goto error_free_payload; + } + + handle->nw_ta = ta; + handle->nw_ta_size = ta_size; + handle->cookie = cookie; + handle->offs = SHDR_GET_SIZE(shdr); + handle->hash_algo = hash_algo; + handle->hash_ctx = hash_ctx; + handle->shdr = shdr; + *h = handle; + return TEE_SUCCESS; + +error_free_payload: + thread_rpc_free_payload(cookie); +error: + free(hash_ctx); + free(shdr); + free(handle); + return res; +} + +static TEE_Result ta_get_size(const struct user_ta_store_handle *h, + size_t *size) +{ + *size = h->shdr->img_size; + return TEE_SUCCESS; +} + +static TEE_Result check_digest(struct user_ta_store_handle *h) +{ + void *digest = NULL; + TEE_Result res; + + if (!crypto_ops.hash.final) + return TEE_ERROR_NOT_SUPPORTED; + digest = malloc(h->shdr->hash_size); + if (!digest) + return TEE_ERROR_OUT_OF_MEMORY; + res = crypto_ops.hash.final(h->hash_ctx, h->hash_algo, digest, + h->shdr->hash_size); + if (res != TEE_SUCCESS) { + res = TEE_ERROR_SECURITY; + goto out; + } + if (memcmp(digest, SHDR_GET_HASH(h->shdr), h->shdr->hash_size)) + res = TEE_ERROR_SECURITY; +out: + free(digest); + return res; +} + +static TEE_Result ta_read(struct user_ta_store_handle *h, void *data, + size_t len) +{ + uint8_t *src = (uint8_t *)h->nw_ta + h->offs; + uint8_t *dst = src; + TEE_Result res; + + if (h->offs + len > h->nw_ta_size) + return TEE_ERROR_BAD_PARAMETERS; + if (data) { + dst = data; /* Hash secure buffer (shm might be modified) */ + memcpy(dst, src, len); + } + res = crypto_ops.hash.update(h->hash_ctx, h->hash_algo, dst, len); + if (res != TEE_SUCCESS) + return TEE_ERROR_SECURITY; + h->offs += len; + if (h->offs == h->nw_ta_size) { + /* + * Last read: time to check if our digest matches the expected + * one (from the signed header) + */ + res = check_digest(h); + } + return res; +} + +static void ta_close(struct user_ta_store_handle *h) +{ + if (!h) + return; + thread_rpc_free_payload(h->cookie); + free(h->hash_ctx); + free(h->shdr); + free(h); +} + +static const struct user_ta_store_ops ops = { + .open = ta_open, + .get_size = ta_get_size, + .read = ta_read, + .close = ta_close, +}; + +static TEE_Result register_supplicant_user_ta(void) +{ + return tee_ta_register_ta_store(&ops); +} + +service_init(register_supplicant_user_ta); diff --git a/core/arch/arm/kernel/sub.mk b/core/arch/arm/kernel/sub.mk index 4ee001db9a9..fc148a3a00b 100644 --- a/core/arch/arm/kernel/sub.mk +++ b/core/arch/arm/kernel/sub.mk @@ -1,4 +1,7 @@ -srcs-$(CFG_WITH_USER_TA) += user_ta.c +ifeq ($(CFG_WITH_USER_TA),y) +srcs-y += user_ta.c +srcs-$(CFG_REE_FS_TA) += ree_fs_ta.c +endif srcs-y += pseudo_ta.c srcs-y += elf_load.c srcs-y += tee_time.c diff --git a/core/arch/arm/kernel/user_ta.c b/core/arch/arm/kernel/user_ta.c index d9f1c892440..416bb924e33 100644 --- a/core/arch/arm/kernel/user_ta.c +++ b/core/arch/arm/kernel/user_ta.c @@ -59,75 +59,6 @@ #include "elf_load.h" #include "elf_common.h" -static TEE_Result load_header(const struct shdr *signed_ta, - struct shdr **sec_shdr) -{ - size_t s; - - if (!tee_vbuf_is_non_sec(signed_ta, sizeof(*signed_ta))) - return TEE_ERROR_SECURITY; - - s = SHDR_GET_SIZE(signed_ta); - if (!tee_vbuf_is_non_sec(signed_ta, s)) - return TEE_ERROR_SECURITY; - - /* Copy signed header into secure memory */ - *sec_shdr = malloc(s); - if (!*sec_shdr) - return TEE_ERROR_OUT_OF_MEMORY; - memcpy(*sec_shdr, signed_ta, s); - - return TEE_SUCCESS; -} - -static TEE_Result check_shdr(struct shdr *shdr) -{ - struct rsa_public_key key; - TEE_Result res; - uint32_t e = TEE_U32_TO_BIG_ENDIAN(ta_pub_key_exponent); - size_t hash_size; - - if (shdr->magic != SHDR_MAGIC || shdr->img_type != SHDR_TA) - return TEE_ERROR_SECURITY; - - if (TEE_ALG_GET_MAIN_ALG(shdr->algo) != TEE_MAIN_ALGO_RSA) - return TEE_ERROR_SECURITY; - - res = tee_hash_get_digest_size(TEE_DIGEST_HASH_TO_ALGO(shdr->algo), - &hash_size); - if (res != TEE_SUCCESS) - return res; - if (hash_size != shdr->hash_size) - return TEE_ERROR_SECURITY; - - if (!crypto_ops.acipher.alloc_rsa_public_key || - !crypto_ops.acipher.free_rsa_public_key || - !crypto_ops.acipher.rsassa_verify || - !crypto_ops.bignum.bin2bn) - return TEE_ERROR_NOT_SUPPORTED; - - res = crypto_ops.acipher.alloc_rsa_public_key(&key, shdr->sig_size); - if (res != TEE_SUCCESS) - return res; - - res = crypto_ops.bignum.bin2bn((uint8_t *)&e, sizeof(e), key.e); - if (res != TEE_SUCCESS) - goto out; - res = crypto_ops.bignum.bin2bn(ta_pub_key_modulus, - ta_pub_key_modulus_size, key.n); - if (res != TEE_SUCCESS) - goto out; - - res = crypto_ops.acipher.rsassa_verify(shdr->algo, &key, -1, - SHDR_GET_HASH(shdr), shdr->hash_size, - SHDR_GET_SIG(shdr), shdr->sig_size); -out: - crypto_ops.acipher.free_rsa_public_key(&key); - if (res != TEE_SUCCESS) - return TEE_ERROR_SECURITY; - return TEE_SUCCESS; -} - static uint32_t elf_flags_to_mattr(uint32_t flags, bool init_attrs) { uint32_t mattr = 0; @@ -249,48 +180,17 @@ static struct mobj *alloc_ta_mem(size_t size) #endif } -static TEE_Result load_elf(struct user_ta_ctx *utc, struct shdr *shdr, - const struct shdr *nmem_shdr) +static TEE_Result load_elf(struct user_ta_ctx *utc, + const struct user_ta_store_ops *ta_store, + struct user_ta_store_handle *ta_handle) { TEE_Result res; - size_t hash_ctx_size; - void *hash_ctx = NULL; - uint32_t hash_algo; - uint8_t *nwdata = (uint8_t *)nmem_shdr + SHDR_GET_SIZE(shdr); - size_t nwdata_len = shdr->img_size; - void *digest = NULL; struct elf_load_state *elf_state = NULL; struct ta_head *ta_head; void *p; size_t vasize; - if (!tee_vbuf_is_non_sec(nwdata, nwdata_len)) - return TEE_ERROR_SECURITY; - - if (!crypto_ops.hash.get_ctx_size || !crypto_ops.hash.init || - !crypto_ops.hash.update || !crypto_ops.hash.final) { - res = TEE_ERROR_NOT_IMPLEMENTED; - goto out; - } - hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo); - res = crypto_ops.hash.get_ctx_size(hash_algo, &hash_ctx_size); - if (res != TEE_SUCCESS) - goto out; - hash_ctx = malloc(hash_ctx_size); - if (!hash_ctx) { - res = TEE_ERROR_OUT_OF_MEMORY; - goto out; - } - res = crypto_ops.hash.init(hash_ctx, hash_algo); - if (res != TEE_SUCCESS) - goto out; - res = crypto_ops.hash.update(hash_ctx, hash_algo, - (uint8_t *)shdr, sizeof(struct shdr)); - if (res != TEE_SUCCESS) - goto out; - - res = elf_load_init(hash_ctx, hash_algo, nwdata, nwdata_len, - &elf_state); + res = elf_load_init(ta_store, ta_handle, &elf_state); if (res != TEE_SUCCESS) goto out; @@ -340,22 +240,6 @@ static TEE_Result load_elf(struct user_ta_ctx *utc, struct shdr *shdr, if (res != TEE_SUCCESS) goto out; - digest = malloc(shdr->hash_size); - if (!digest) { - res = TEE_ERROR_OUT_OF_MEMORY; - goto out; - } - - res = crypto_ops.hash.final(hash_ctx, hash_algo, digest, - shdr->hash_size); - if (res != TEE_SUCCESS) - goto out; - - if (memcmp(digest, SHDR_GET_HASH(shdr), shdr->hash_size) != 0) { - res = TEE_ERROR_SECURITY; - goto out; - } - /* * Replace the init attributes with attributes used when the TA is * running. @@ -366,8 +250,6 @@ static TEE_Result load_elf(struct user_ta_ctx *utc, struct shdr *shdr, out: elf_load_final(elf_state); - free(digest); - free(hash_ctx); return res; } @@ -376,41 +258,24 @@ static TEE_Result load_elf(struct user_ta_ctx *utc, struct shdr *shdr, * Verifies the TA signature. * Returns context ptr and TEE_Result. *---------------------------------------------------------------------------*/ -static TEE_Result ta_load(const TEE_UUID *uuid, const struct shdr *signed_ta, - struct tee_ta_ctx **ta_ctx) +static TEE_Result ta_load(const TEE_UUID *uuid, + const struct user_ta_store_ops *ta_store, + struct tee_ta_ctx **ta_ctx) { TEE_Result res; - /* man_flags: mandatory flags */ - uint32_t man_flags = TA_FLAG_USER_MODE | TA_FLAG_EXEC_DDR; - /* opt_flags: optional flags */ - uint32_t opt_flags = man_flags | TA_FLAG_SINGLE_INSTANCE | + uint32_t mandatory_flags = TA_FLAG_USER_MODE | TA_FLAG_EXEC_DDR; + uint32_t optional_flags = mandatory_flags | TA_FLAG_SINGLE_INSTANCE | TA_FLAG_MULTI_SESSION | TA_FLAG_SECURE_DATA_PATH | TA_FLAG_INSTANCE_KEEP_ALIVE | TA_FLAG_CACHE_MAINTENANCE; struct user_ta_ctx *utc = NULL; - struct shdr *sec_shdr = NULL; struct ta_head *ta_head; + struct user_ta_store_handle *ta_handle = NULL; - res = load_header(signed_ta, &sec_shdr); + res = ta_store->open(uuid, &ta_handle); if (res != TEE_SUCCESS) - goto error_return; - - res = check_shdr(sec_shdr); - if (res != TEE_SUCCESS) - goto error_return; - - /* - * ------------------------------------------------------------------ - * 2nd step: Register context - * Alloc and init the ta context structure, alloc physical/virtual - * memories to store/map the TA. - * ------------------------------------------------------------------ - */ - - /* - * Register context - */ + return res; - /* code below must be protected by mutex (multi-threaded) */ + /* Register context */ utc = calloc(1, sizeof(struct user_ta_ctx)); if (!utc) { res = TEE_ERROR_OUT_OF_MEMORY; @@ -420,11 +285,8 @@ static TEE_Result ta_load(const TEE_UUID *uuid, const struct shdr *signed_ta, TAILQ_INIT(&utc->cryp_states); TAILQ_INIT(&utc->objects); TAILQ_INIT(&utc->storage_enums); -#if defined(CFG_SE_API) - utc->se_service = NULL; -#endif - res = load_elf(utc, sec_shdr, signed_ta); + res = load_elf(utc, ta_store, ta_handle); if (res != TEE_SUCCESS) goto error_return; @@ -437,34 +299,29 @@ static TEE_Result ta_load(const TEE_UUID *uuid, const struct shdr *signed_ta, } /* check input flags bitmask consistency and save flags */ - if ((ta_head->flags & opt_flags) != ta_head->flags || - (ta_head->flags & man_flags) != man_flags) { - EMSG("TA flag issue: flags=%x opt=%X man=%X", - ta_head->flags, opt_flags, man_flags); + if ((ta_head->flags & optional_flags) != ta_head->flags || + (ta_head->flags & mandatory_flags) != mandatory_flags) { + EMSG("TA flag issue: flags=%x optional=%x mandatory=%x", + ta_head->flags, optional_flags, mandatory_flags); res = TEE_ERROR_BAD_FORMAT; goto error_return; } + DMSG("ELF load address 0x%x", utc->load_addr); utc->ctx.flags = ta_head->flags; utc->ctx.uuid = ta_head->uuid; utc->entry_func = ta_head->entry.ptr64; - utc->ctx.ref_count = 1; - condvar_init(&utc->ctx.busy_cv); TAILQ_INSERT_TAIL(&tee_ctxes, &utc->ctx, link); *ta_ctx = &utc->ctx; - DMSG("ELF load address 0x%x", utc->load_addr); - tee_mmu_set_ctx(NULL); - /* end thread protection (multi-threaded) */ - - free(sec_shdr); + ta_store->close(ta_handle); return TEE_SUCCESS; error_return: - free(sec_shdr); + ta_store->close(ta_handle); tee_mmu_set_ctx(NULL); if (utc) { pgt_flush_ctx(&utc->ctx); @@ -613,78 +470,6 @@ static TEE_Result user_ta_enter(TEE_ErrorOrigin *err, return res; } -/* - * Load a TA via RPC with UUID defined by input param uuid. The virtual - * address of the TA is recieved in out parameter ta - * - * Function is not thread safe - */ -static TEE_Result rpc_load(const TEE_UUID *uuid, struct shdr **ta, - uint64_t *cookie_ta) -{ - TEE_Result res; - struct optee_msg_param params[2]; - paddr_t phta = 0; - uint64_t cta = 0; - - - if (!uuid || !ta || !cookie_ta) - return TEE_ERROR_BAD_PARAMETERS; - - memset(params, 0, sizeof(params)); - params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; - tee_uuid_to_octets((void *)¶ms[0].u.value, uuid); - params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; - params[1].u.tmem.buf_ptr = 0; - params[1].u.tmem.size = 0; - params[1].u.tmem.shm_ref = 0; - - res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_LOAD_TA, 2, params); - if (res != TEE_SUCCESS) - return res; - - thread_rpc_alloc_payload(params[1].u.tmem.size, &phta, &cta); - if (!phta) - return TEE_ERROR_OUT_OF_MEMORY; - - *ta = phys_to_virt(phta, MEM_AREA_NSEC_SHM); - if (!*ta) { - res = TEE_ERROR_GENERIC; - goto out; - } - *cookie_ta = cta; - - params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; - tee_uuid_to_octets((void *)¶ms[0].u.value, uuid); - params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; - params[1].u.tmem.buf_ptr = phta; - params[1].u.tmem.shm_ref = cta; - /* Note that params[1].u.tmem.size is already assigned */ - - res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_LOAD_TA, 2, params); -out: - if (res != TEE_SUCCESS) - thread_rpc_free_payload(cta); - return res; -} - -static TEE_Result init_session_with_signed_ta(const TEE_UUID *uuid, - const struct shdr *signed_ta, - struct tee_ta_session *s) -{ - TEE_Result res; - - DMSG(" Load dynamic TA"); - /* load and verify */ - res = ta_load(uuid, signed_ta, &s->ctx); - if (res != TEE_SUCCESS) - return res; - - DMSG(" dyn TA : %pUl", (void *)&s->ctx->uuid); - - return res; -} - static TEE_Result user_ta_enter_open_session(struct tee_ta_session *s, struct tee_ta_param *param, TEE_ErrorOrigin *eo) { @@ -798,26 +583,24 @@ static const struct tee_ta_ops user_ta_ops __rodata_unpaged = { .get_instance_id = user_ta_get_instance_id, }; +static const struct user_ta_store_ops *user_ta_store; + +TEE_Result tee_ta_register_ta_store(const struct user_ta_store_ops *ops) +{ + user_ta_store = ops; + return TEE_SUCCESS; +} + TEE_Result tee_ta_init_user_ta_session(const TEE_UUID *uuid, struct tee_ta_session *s) { TEE_Result res; - struct shdr *ta = NULL; - uint64_t cookie_ta = 0; - - /* Request TA from tee-supplicant */ - res = rpc_load(uuid, &ta, &cookie_ta); - if (res != TEE_SUCCESS) - return res; - - res = init_session_with_signed_ta(uuid, ta, s); - /* - * Free normal world shared memory now that the TA either has been - * copied into secure memory or the TA failed to be initialized. - */ - thread_rpc_free_payload(cookie_ta); + if (!user_ta_store) + return TEE_ERROR_ITEM_NOT_FOUND; + DMSG("Load user TA %pUl", (void *)uuid); + res = ta_load(uuid, user_ta_store, &s->ctx); if (res == TEE_SUCCESS) s->ctx->ops = &user_ta_ops; return res; diff --git a/core/sub.mk b/core/sub.mk index 0732905d029..79bfd0720bd 100644 --- a/core/sub.mk +++ b/core/sub.mk @@ -2,9 +2,11 @@ subdirs-y += kernel subdirs-y += tee subdirs-y += drivers +ifeq ($(CFG_WITH_USER_TA)-$(CFG_REE_FS_TA),y-y) gensrcs-y += ta_pub_key produce-ta_pub_key = ta_pub_key.c depends-ta_pub_key = $(TA_SIGN_KEY) recipe-ta_pub_key = scripts/pem_to_pub_c.py --prefix ta_pub_key \ --key $(TA_SIGN_KEY) --out $(sub-dir-out)/ta_pub_key.c cleanfiles += $(sub-dir-out)/ta_pub_key.c +endif diff --git a/mk/config.mk b/mk/config.mk index 82f713388ed..d2afba663b4 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -164,6 +164,11 @@ endif # Enable support for dynamically loaded user TAs CFG_WITH_USER_TA ?= y +# Load user TAs from the REE filesystem via tee-supplicant +# There is currently no other alternative, but you may want to disable this in +# case you implement your own TA store +CFG_REE_FS_TA ?= y + # Use small pages to map user TAs CFG_SMALL_PAGE_USER_TA ?= y