From d0c636148b3a9392de97309546304bf9abb1d933 Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Tue, 25 Jul 2017 18:17:11 +0200 Subject: [PATCH] Add support for early Trusted Applications Early TAs are user-mode Trusted Applications that are embedded at link time in the TEE binary. A special read-only data section is used to store them (.rodata.early_ta). A Python script takes care of converting the TAs into a C source file with the proper linker section attribute. The feature is disabled by default. To enable it, the paths to the TA binaries have to be given in $(EARLY_TA_PATHS). They should be ELF files. Typical build steps: $ make ... CFG_EARLY_TA=y ta_dev_kit # (1) $ # ... build the TAs ... # (2) $ make ... EARLY_TA_PATHS=path/to/.stripped.elf # (3) Notes: - Setting CFG_EARLY_TA=y during the first step (1) is not necessary, but it will avoid rebuilding libraries during the third step (3) - CFG_EARLY_TA is automatically enabled when EARLY_TA_PATHS is non-empty in step (3) - Several TAs may be given in $(EARLY_TA_PATHS) (3) Early TAs are given a higher load priority than REE FS TAs, since they should be available even before tee-supplicant is ready. Suggested-by: Zeng Tao Signed-off-by: Jerome Forissier Reviewed-by: Jens Wiklander Reviewed-by: Etienne Carriere --- core/arch/arm/include/kernel/early_ta.h | 41 ++++++++ core/arch/arm/include/kernel/linker.h | 6 +- core/arch/arm/kernel/early_ta.c | 124 ++++++++++++++++++++++++ core/arch/arm/kernel/kern.ld.S | 13 +++ core/arch/arm/kernel/link_dummy.ld | 2 + core/arch/arm/kernel/sub.mk | 1 + core/arch/arm/kernel/user_ta.c | 13 ++- core/arch/arm/plat-sunxi/kern.ld.S | 6 ++ core/sub.mk | 13 +++ lib/libutils/ext/include/compiler.h | 1 + mk/config.mk | 22 +++++ scripts/ta_bin_to_c.py | 95 ++++++++++++++++++ 12 files changed, 331 insertions(+), 6 deletions(-) create mode 100644 core/arch/arm/include/kernel/early_ta.h create mode 100644 core/arch/arm/kernel/early_ta.c create mode 100755 scripts/ta_bin_to_c.py diff --git a/core/arch/arm/include/kernel/early_ta.h b/core/arch/arm/include/kernel/early_ta.h new file mode 100644 index 00000000000..b745bacbf64 --- /dev/null +++ b/core/arch/arm/include/kernel/early_ta.h @@ -0,0 +1,41 @@ +/* + * 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. + */ +#ifndef KERNEL_EARLY_TA_H +#define KERNEL_EARLY_TA_H + +#include +#include +#include + +struct early_ta { + TEE_UUID uuid; + uint32_t size; + const uint8_t ta[]; /* @size bytes */ +}; + +#endif /* KERNEL_EARLY_TA_H */ + diff --git a/core/arch/arm/include/kernel/linker.h b/core/arch/arm/include/kernel/linker.h index 105a012f405..6864e229d62 100644 --- a/core/arch/arm/include/kernel/linker.h +++ b/core/arch/arm/include/kernel/linker.h @@ -28,8 +28,9 @@ #define __KERNEL_LINKER_H #include -#include #include +#include +#include #include #include @@ -116,6 +117,9 @@ extern const vaddr_t __ctor_end; extern const struct dt_driver __rodata_dtdrv_start; extern const struct dt_driver __rodata_dtdrv_end; +extern const struct early_ta __rodata_early_ta_start; +extern const struct early_ta __rodata_early_ta_end; + /* Generated by core/arch/arm/kernel/link.mk */ extern const char core_v_str[]; diff --git a/core/arch/arm/kernel/early_ta.c b/core/arch/arm/kernel/early_ta.c new file mode 100644 index 00000000000..68e2e4a8489 --- /dev/null +++ b/core/arch/arm/kernel/early_ta.c @@ -0,0 +1,124 @@ +/* + * 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 "elf_load.h" + +struct user_ta_store_handle { + const struct early_ta *early_ta; + size_t offs; +}; + +#define for_each_early_ta(_ta) \ + for (_ta = &__rodata_early_ta_start; _ta < &__rodata_early_ta_end; \ + _ta = (const struct early_ta *) \ + ROUNDUP((vaddr_t)_ta + sizeof(*_ta) + _ta->size, \ + __alignof__(struct early_ta))) + +static const struct early_ta *find_early_ta(const TEE_UUID *uuid) +{ + const struct early_ta *ta; + + for_each_early_ta(ta) + if (!memcmp(&ta->uuid, uuid, sizeof(*uuid))) + return ta; + + return NULL; +} + +static TEE_Result early_ta_open(const TEE_UUID *uuid, + struct user_ta_store_handle **h) +{ + const struct early_ta *ta; + struct user_ta_store_handle *handle; + + ta = find_early_ta(uuid); + if (!ta) + return TEE_ERROR_ITEM_NOT_FOUND; + + handle = calloc(1, sizeof(*handle)); + if (!handle) + return TEE_ERROR_OUT_OF_MEMORY; + + handle->early_ta = ta; + *h = handle; + + return TEE_SUCCESS; +} + +static TEE_Result early_ta_get_size(const struct user_ta_store_handle *h, + size_t *size) +{ + *size = h->early_ta->size; + return TEE_SUCCESS; +} + +static TEE_Result early_ta_read(struct user_ta_store_handle *h, void *data, + size_t len) +{ + uint8_t *src = (uint8_t *)h->early_ta->ta + h->offs; + + if (h->offs + len > h->early_ta->size) + return TEE_ERROR_BAD_PARAMETERS; + if (data) + memcpy(data, src, len); + h->offs += len; + + return TEE_SUCCESS; +} + +static void early_ta_close(struct user_ta_store_handle *h) +{ + free(h); +} + +static struct user_ta_store_ops ops = { + .description = "early TA", + .open = early_ta_open, + .get_size = early_ta_get_size, + .read = early_ta_read, + .close = early_ta_close, + .priority = 5, +}; + +static TEE_Result early_ta_init(void) +{ + const struct early_ta *ta; + + for_each_early_ta(ta) + DMSG("Early TA %pUl size %u", (void *)&ta->uuid, ta->size); + + return tee_ta_register_ta_store(&ops); +} + +service_init(early_ta_init); diff --git a/core/arch/arm/kernel/kern.ld.S b/core/arch/arm/kernel/kern.ld.S index 991d779b092..b2cc3065a9a 100644 --- a/core/arch/arm/kernel/kern.ld.S +++ b/core/arch/arm/kernel/kern.ld.S @@ -118,6 +118,13 @@ SECTIONS KEEP(*(.rodata.dtdrv)) __rodata_dtdrv_end = .; #endif +#ifdef CFG_EARLY_TA + . = ALIGN(8); + __rodata_early_ta_start = .; + KEEP(*(.rodata.early_ta)) + __rodata_early_ta_end = .; +#endif + *(.rodata .rodata.*) /* @@ -328,6 +335,12 @@ SECTIONS __rodata_dtdrv_start = .; KEEP(*(.rodata.dtdrv)) __rodata_dtdrv_end = .; +#endif +#ifdef CFG_EARLY_TA + . = ALIGN(8); + __rodata_early_ta_start = .; + KEEP(*(.rodata.early_ta)) + __rodata_early_ta_end = .; #endif *(.rodata*) /* diff --git a/core/arch/arm/kernel/link_dummy.ld b/core/arch/arm/kernel/link_dummy.ld index f48f9a04de4..4aca773e287 100644 --- a/core/arch/arm/kernel/link_dummy.ld +++ b/core/arch/arm/kernel/link_dummy.ld @@ -66,6 +66,8 @@ __pageable_part_start = .; __pageable_start = .; __rodata_dtdrv_end = .; __rodata_dtdrv_start = .; +__rodata_early_ta_start = .; +__rodata_early_ta_end = .; __rodata_end = .; __rodata_start = .; __start_phys_nsec_ddr_section = .; diff --git a/core/arch/arm/kernel/sub.mk b/core/arch/arm/kernel/sub.mk index 79b109e2416..178aa5082f9 100644 --- a/core/arch/arm/kernel/sub.mk +++ b/core/arch/arm/kernel/sub.mk @@ -1,6 +1,7 @@ ifeq ($(CFG_WITH_USER_TA),y) srcs-y += user_ta.c srcs-$(CFG_REE_FS_TA) += ree_fs_ta.c +srcs-$(CFG_EARLY_TA) += early_ta.c endif srcs-y += pseudo_ta.c srcs-y += elf_load.c diff --git a/core/arch/arm/kernel/user_ta.c b/core/arch/arm/kernel/user_ta.c index 57ab6e63f60..2e4cbbca608 100644 --- a/core/arch/arm/kernel/user_ta.c +++ b/core/arch/arm/kernel/user_ta.c @@ -625,16 +625,19 @@ TEE_Result tee_ta_init_user_ta_session(const TEE_UUID *uuid, struct tee_ta_session *s) { const struct user_ta_store_ops *store; - TEE_Result res = TEE_ERROR_ITEM_NOT_FOUND; + TEE_Result res; SLIST_FOREACH(store, &uta_store_list, link) { DMSG("Lookup user TA %pUl (%s)", (void *)uuid, store->description); res = ta_load(uuid, store, &s->ctx); - if (res == TEE_SUCCESS) { + if (res == TEE_ERROR_ITEM_NOT_FOUND) + continue; + if (res == TEE_SUCCESS) s->ctx->ops = &user_ta_ops; - return res; - } + else + DMSG("res=0x%x", res); + return res; } - return res; + return TEE_ERROR_ITEM_NOT_FOUND; } diff --git a/core/arch/arm/plat-sunxi/kern.ld.S b/core/arch/arm/plat-sunxi/kern.ld.S index f6218046bae..0f7a67e0439 100644 --- a/core/arch/arm/plat-sunxi/kern.ld.S +++ b/core/arch/arm/plat-sunxi/kern.ld.S @@ -129,6 +129,12 @@ SECTIONS .rodata : ALIGN(4) { __rodata_start = .; +#ifdef CFG_EARLY_TA + . = ALIGN(8); + __rodata_early_ta_start = .; + KEEP(*(.rodata.early_ta)) + __rodata_early_ta_end = .; +#endif *(.rodata .rodata.* .gnu.linkonce.r.*) /* diff --git a/core/sub.mk b/core/sub.mk index 9dbe8b7fda0..762c81b539f 100644 --- a/core/sub.mk +++ b/core/sub.mk @@ -10,3 +10,16 @@ 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 + +ifeq ($(CFG_WITH_USER_TA)-$(CFG_EARLY_TA),y-y) +define process_early_ta +early-ta-$1-uuid := $(firstword $(subst ., ,$(notdir $1))) +gensrcs-y += early-ta-$1 +produce-early-ta-$1 = early_ta_$$(early-ta-$1-uuid).c +depends-early-ta-$1 = $1 scripts/ta_bin_to_c.py +recipe-early-ta-$1 = scripts/ta_bin_to_c.py --ta $1 \ + --out $(sub-dir-out)/early_ta_$$(early-ta-$1-uuid).c +cleanfiles += $(sub-dir-out)/early_ta_$$(early-ta-$1-uuid).c +endef +$(foreach f, $(EARLY_TA_PATHS), $(eval $(call process_early_ta,$(f)))) +endif diff --git a/lib/libutils/ext/include/compiler.h b/lib/libutils/ext/include/compiler.h index 85528061e59..1bab0f38d3d 100644 --- a/lib/libutils/ext/include/compiler.h +++ b/lib/libutils/ext/include/compiler.h @@ -52,6 +52,7 @@ #define __bss __section(".bss") #define __rodata __section(".rodata") #define __rodata_unpaged __section(".rodata.__unpaged") +#define __early_ta __section(".rodata.early_ta") #define __noprof __attribute__((no_instrument_function)) #define __compiler_bswap64(x) __builtin_bswap64((x)) diff --git a/mk/config.mk b/mk/config.mk index d3e378143a7..56d35706cfa 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -176,6 +176,28 @@ CFG_WITH_USER_TA ?= y # case you implement your own TA store CFG_REE_FS_TA ?= y +# Support for loading user TAs from a special section in the TEE binary. +# Such TAs are available even before tee-supplicant is available (hence their +# name), but note that many services exported to TAs may need tee-supplicant, +# so early use is limited to a subset of the TEE Internal Core API (crypto...) +# To use this feature, set EARLY_TA_PATHS to the paths to one or more TA ELF +# file(s). For example: +# $ make ... \ +# EARLY_TA_PATHS="path/to/8aaaf200-2450-11e4-abe2-0002a5d5c51b.stripped.elf \ +# path/to/cb3e5ba0-adf1-11e0-998b-0002a5d5c51b.stripped.elf" +# Typical build steps: +# $ make ta_dev_kit CFG_EARLY_TA=y # Create the dev kit (user mode libraries, +# # headers, makefiles), ready to build TAs. +# # CFG_EARLY_TA=y is optional, it prevents +# # later library recompilations. +# +# $ make EARLY_TA_PATHS= # Build OP-TEE and embbed the TA(s) +ifneq ($(EARLY_TA_PATHS),) +$(call force,CFG_EARLY_TA,y) +else +CFG_EARLY_TA ?= n +endif + # Enable paging, requires SRAM, can't be enabled by default CFG_WITH_PAGER ?= n diff --git a/scripts/ta_bin_to_c.py b/scripts/ta_bin_to_c.py new file mode 100755 index 00000000000..13a38c7cd1b --- /dev/null +++ b/scripts/ta_bin_to_c.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# +# 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. +# + +import argparse +import array +import os +import re +import uuid + +def get_args(): + + parser = argparse.ArgumentParser(description='Converts a Trusted ' + 'Application ELF file into a C source file, ready for ' + 'inclusion in the TEE binary as an "early TA".') + + parser.add_argument('--out', required=True, + help='Name of the output C file') + + parser.add_argument('--ta', required=True, + help='Path to the TA binary. File name has to be: .* ' + 'such as: 8aaaf200-2450-11e4-abe2-0002a5d5c51b.stripped.elf') + + return parser.parse_args() + +def main(): + + args = get_args(); + + ta_uuid = uuid.UUID(re.sub('\..*', '', os.path.basename(args.ta))) + + f = open(args.out, 'w') + f.write('/* Generated from ' + args.ta + ' by ' + + os.path.basename(__file__) + ' */\n\n') + f.write('#include \n'); + f.write('#include \n\n'); + f.write('__extension__ const struct early_ta __early_ta_' + + ta_uuid.hex + + '\n__early_ta __aligned(__alignof__(struct early_ta)) = {\n') + f.write('\t.uuid = {\n') + f.write('\t\t.timeLow = 0x{:08x},\n'.format(ta_uuid.time_low)) + f.write('\t\t.timeMid = 0x{:04x},\n'.format(ta_uuid.time_mid)) + f.write('\t\t.timeHiAndVersion = ' + + '0x{:04x},\n'.format(ta_uuid.time_hi_version)) + f.write('\t\t.clockSeqAndNode = {\n') + csn = '{0:02x}{1:02x}{2:012x}'.format(ta_uuid.clock_seq_hi_variant, + ta_uuid.clock_seq_low, ta_uuid.node) + f.write('\t\t\t') + f.write(', '.join('0x' + csn[i:i+2] for i in range(0, len(csn), 2))) + f.write('\n\t\t},\n\t},\n') + f.write('\t.size = {:d},'.format(os.path.getsize(args.ta))) + f.write('\t.ta = {\n') + i = 0 + with open(args.ta, 'rb') as ta: + byte = ta.read(1) + while byte: + if i % 8 == 0: + f.write('\t\t'); + f.write('0x' + '{:02x}'.format(ord(byte)) + ',') + i = i + 1 + byte = ta.read(1) + if i % 8 == 0 or not byte: + f.write('\n') + else: + f.write(' ') + f.write('\t},\n') + f.write('};\n'); + f.close() + +if __name__ == "__main__": + main()