15843bb75SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 25843bb75SJerome Forissier /* 35843bb75SJerome Forissier * Copyright (c) 2018-2019, Linaro Limited 45843bb75SJerome Forissier */ 55843bb75SJerome Forissier 65843bb75SJerome Forissier #include <assert.h> 75843bb75SJerome Forissier #include <crypto/crypto.h> 85843bb75SJerome Forissier #include <kernel/handle.h> 95843bb75SJerome Forissier #include <kernel/huk_subkey.h> 105843bb75SJerome Forissier #include <kernel/misc.h> 115843bb75SJerome Forissier #include <kernel/msg_param.h> 125843bb75SJerome Forissier #include <kernel/pseudo_ta.h> 13a8e39e9cSJens Wiklander #include <kernel/tpm.h> 145843bb75SJerome Forissier #include <kernel/user_ta.h> 155843bb75SJerome Forissier #include <kernel/user_ta_store.h> 165843bb75SJerome Forissier #include <ldelf.h> 175843bb75SJerome Forissier #include <mm/file.h> 185843bb75SJerome Forissier #include <mm/fobj.h> 195843bb75SJerome Forissier #include <mm/tee_mmu.h> 205843bb75SJerome Forissier #include <pta_system.h> 21a8e39e9cSJens Wiklander #include <stdlib_ext.h> 22a8e39e9cSJens Wiklander #include <stdlib.h> 235843bb75SJerome Forissier #include <string.h> 245843bb75SJerome Forissier #include <tee_api_defines_extensions.h> 255843bb75SJerome Forissier #include <tee_api_defines.h> 265843bb75SJerome Forissier #include <util.h> 275843bb75SJerome Forissier 285843bb75SJerome Forissier struct bin_handle { 295843bb75SJerome Forissier const struct user_ta_store_ops *op; 305843bb75SJerome Forissier struct user_ta_store_handle *h; 315843bb75SJerome Forissier struct file *f; 325843bb75SJerome Forissier size_t offs_bytes; 335843bb75SJerome Forissier size_t size_bytes; 345843bb75SJerome Forissier }; 355843bb75SJerome Forissier 365843bb75SJerome Forissier struct system_ctx { 375843bb75SJerome Forissier struct handle_db db; 385843bb75SJerome Forissier const struct user_ta_store_ops *store_op; 395843bb75SJerome Forissier }; 405843bb75SJerome Forissier 415843bb75SJerome Forissier static unsigned int system_pnum; 425843bb75SJerome Forissier 435843bb75SJerome Forissier static TEE_Result system_rng_reseed(struct tee_ta_session *s __unused, 445843bb75SJerome Forissier uint32_t param_types, 455843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 465843bb75SJerome Forissier { 475843bb75SJerome Forissier size_t entropy_sz; 485843bb75SJerome Forissier uint8_t *entropy_input; 495843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 505843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 515843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 525843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 535843bb75SJerome Forissier 545843bb75SJerome Forissier if (exp_pt != param_types) 555843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 565843bb75SJerome Forissier entropy_input = params[0].memref.buffer; 575843bb75SJerome Forissier entropy_sz = params[0].memref.size; 585843bb75SJerome Forissier 59c2020b9dSJens Wiklander if (!entropy_sz || !entropy_input) 605843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 615843bb75SJerome Forissier 625843bb75SJerome Forissier crypto_rng_add_event(CRYPTO_RNG_SRC_NONSECURE, &system_pnum, 635843bb75SJerome Forissier entropy_input, entropy_sz); 645843bb75SJerome Forissier return TEE_SUCCESS; 655843bb75SJerome Forissier } 665843bb75SJerome Forissier 675843bb75SJerome Forissier static TEE_Result system_derive_ta_unique_key(struct tee_ta_session *s, 685843bb75SJerome Forissier uint32_t param_types, 695843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 705843bb75SJerome Forissier { 715843bb75SJerome Forissier size_t data_len = sizeof(TEE_UUID); 725843bb75SJerome Forissier TEE_Result res = TEE_ERROR_GENERIC; 735843bb75SJerome Forissier uint8_t *data = NULL; 745843bb75SJerome Forissier uint32_t access_flags = 0; 755843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 765843bb75SJerome Forissier TEE_PARAM_TYPE_MEMREF_OUTPUT, 775843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 785843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 795843bb75SJerome Forissier struct user_ta_ctx *utc = NULL; 805843bb75SJerome Forissier 815843bb75SJerome Forissier if (exp_pt != param_types) 825843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 835843bb75SJerome Forissier 845843bb75SJerome Forissier if (params[0].memref.size > TA_DERIVED_EXTRA_DATA_MAX_SIZE || 855843bb75SJerome Forissier params[1].memref.size < TA_DERIVED_KEY_MIN_SIZE || 865843bb75SJerome Forissier params[1].memref.size > TA_DERIVED_KEY_MAX_SIZE) 875843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 885843bb75SJerome Forissier 895843bb75SJerome Forissier utc = to_user_ta_ctx(s->ctx); 905843bb75SJerome Forissier 915843bb75SJerome Forissier /* 925843bb75SJerome Forissier * The derived key shall not end up in non-secure memory by 935843bb75SJerome Forissier * mistake. 945843bb75SJerome Forissier * 955843bb75SJerome Forissier * Note that we're allowing shared memory as long as it's 965843bb75SJerome Forissier * secure. This is needed because a TA always uses shared memory 975843bb75SJerome Forissier * when communicating with another TA. 985843bb75SJerome Forissier */ 995843bb75SJerome Forissier access_flags = TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER | 1005843bb75SJerome Forissier TEE_MEMORY_ACCESS_SECURE; 1011936dfc7SJens Wiklander res = tee_mmu_check_access_rights(&utc->uctx, access_flags, 1025843bb75SJerome Forissier (uaddr_t)params[1].memref.buffer, 1035843bb75SJerome Forissier params[1].memref.size); 1045843bb75SJerome Forissier if (res != TEE_SUCCESS) 1055843bb75SJerome Forissier return TEE_ERROR_SECURITY; 1065843bb75SJerome Forissier 1075843bb75SJerome Forissier /* Take extra data into account. */ 1085843bb75SJerome Forissier if (ADD_OVERFLOW(data_len, params[0].memref.size, &data_len)) 1095843bb75SJerome Forissier return TEE_ERROR_SECURITY; 1105843bb75SJerome Forissier 1115843bb75SJerome Forissier data = calloc(data_len, 1); 1125843bb75SJerome Forissier if (!data) 1135843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 1145843bb75SJerome Forissier 1155843bb75SJerome Forissier memcpy(data, &s->ctx->uuid, sizeof(TEE_UUID)); 1165843bb75SJerome Forissier 1175843bb75SJerome Forissier /* Append the user provided data */ 1185843bb75SJerome Forissier memcpy(data + sizeof(TEE_UUID), params[0].memref.buffer, 1195843bb75SJerome Forissier params[0].memref.size); 1205843bb75SJerome Forissier 1215843bb75SJerome Forissier res = huk_subkey_derive(HUK_SUBKEY_UNIQUE_TA, data, data_len, 1225843bb75SJerome Forissier params[1].memref.buffer, 1235843bb75SJerome Forissier params[1].memref.size); 124a8e39e9cSJens Wiklander free_wipe(data); 1255843bb75SJerome Forissier 1265843bb75SJerome Forissier return res; 1275843bb75SJerome Forissier } 1285843bb75SJerome Forissier 1295843bb75SJerome Forissier static TEE_Result system_map_zi(struct tee_ta_session *s, uint32_t param_types, 1305843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 1315843bb75SJerome Forissier { 1325843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 1335843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INOUT, 1345843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT, 1355843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 1365843bb75SJerome Forissier struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx); 1375843bb75SJerome Forissier uint32_t prot = TEE_MATTR_URW | TEE_MATTR_PRW; 1385843bb75SJerome Forissier TEE_Result res = TEE_ERROR_GENERIC; 1395843bb75SJerome Forissier struct mobj *mobj = NULL; 1405843bb75SJerome Forissier uint32_t pad_begin = 0; 141b9651492SJens Wiklander uint32_t vm_flags = 0; 1425843bb75SJerome Forissier struct fobj *f = NULL; 1435843bb75SJerome Forissier uint32_t pad_end = 0; 1445843bb75SJerome Forissier size_t num_bytes = 0; 1455843bb75SJerome Forissier vaddr_t va = 0; 1465843bb75SJerome Forissier 1475843bb75SJerome Forissier if (exp_pt != param_types) 1485843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 1495843bb75SJerome Forissier if (params[0].value.b & ~PTA_SYSTEM_MAP_FLAG_SHAREABLE) 1505843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 1515843bb75SJerome Forissier 1525843bb75SJerome Forissier if (params[0].value.b & PTA_SYSTEM_MAP_FLAG_SHAREABLE) 1535843bb75SJerome Forissier vm_flags |= VM_FLAG_SHAREABLE; 1545843bb75SJerome Forissier 1555843bb75SJerome Forissier num_bytes = params[0].value.a; 1565843bb75SJerome Forissier va = reg_pair_to_64(params[1].value.a, params[1].value.b); 1575843bb75SJerome Forissier pad_begin = params[2].value.a; 1585843bb75SJerome Forissier pad_end = params[2].value.b; 1595843bb75SJerome Forissier 160787295dfSJens Wiklander f = fobj_ta_mem_alloc(ROUNDUP_DIV(num_bytes, SMALL_PAGE_SIZE)); 1615843bb75SJerome Forissier if (!f) 1625843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 1635843bb75SJerome Forissier mobj = mobj_with_fobj_alloc(f, NULL); 1645843bb75SJerome Forissier fobj_put(f); 1655843bb75SJerome Forissier if (!mobj) 1665843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 1671936dfc7SJens Wiklander res = vm_map_pad(&utc->uctx, &va, num_bytes, prot, vm_flags, 1685843bb75SJerome Forissier mobj, 0, pad_begin, pad_end); 169b9651492SJens Wiklander mobj_put(mobj); 170b9651492SJens Wiklander if (!res) 1715843bb75SJerome Forissier reg_pair_from_64(va, ¶ms[1].value.a, ¶ms[1].value.b); 1725843bb75SJerome Forissier 1735843bb75SJerome Forissier return res; 1745843bb75SJerome Forissier } 1755843bb75SJerome Forissier 1765843bb75SJerome Forissier static TEE_Result system_unmap(struct tee_ta_session *s, uint32_t param_types, 1775843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 1785843bb75SJerome Forissier { 1795843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 1805843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT, 1815843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 1825843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 18379f22013SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx); 18479f22013SJens Wiklander TEE_Result res = TEE_SUCCESS; 18579f22013SJens Wiklander uint32_t vm_flags = 0; 186*095b07ceSJens Wiklander vaddr_t end_va = 0; 18779f22013SJens Wiklander vaddr_t va = 0; 18879f22013SJens Wiklander size_t sz = 0; 1895843bb75SJerome Forissier 1905843bb75SJerome Forissier if (exp_pt != param_types) 1915843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 1925843bb75SJerome Forissier 1935843bb75SJerome Forissier if (params[0].value.b) 1945843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 1955843bb75SJerome Forissier 19679f22013SJens Wiklander va = reg_pair_to_64(params[1].value.a, params[1].value.b); 19779f22013SJens Wiklander sz = ROUNDUP(params[0].value.a, SMALL_PAGE_SIZE); 19879f22013SJens Wiklander 199*095b07ceSJens Wiklander /* 200*095b07ceSJens Wiklander * The vm_get_flags() and vm_unmap() are supposed to detect or 201*095b07ceSJens Wiklander * handle overflow directly or indirectly. However, this function 202*095b07ceSJens Wiklander * an API function so an extra guard here is in order. If nothing 203*095b07ceSJens Wiklander * else to make it easier to review the code. 204*095b07ceSJens Wiklander */ 205*095b07ceSJens Wiklander if (ADD_OVERFLOW(va, sz, &end_va)) 206*095b07ceSJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 207*095b07ceSJens Wiklander 20879f22013SJens Wiklander res = vm_get_flags(&utc->uctx, va, sz, &vm_flags); 20979f22013SJens Wiklander if (res) 21079f22013SJens Wiklander return res; 21179f22013SJens Wiklander if (vm_flags & VM_FLAG_PERMANENT) 21279f22013SJens Wiklander return TEE_ERROR_ACCESS_DENIED; 21379f22013SJens Wiklander 21479f22013SJens Wiklander return vm_unmap(&to_user_ta_ctx(s->ctx)->uctx, va, sz); 2155843bb75SJerome Forissier } 2165843bb75SJerome Forissier 2175843bb75SJerome Forissier static void ta_bin_close(void *ptr) 2185843bb75SJerome Forissier { 2195843bb75SJerome Forissier struct bin_handle *binh = ptr; 2205843bb75SJerome Forissier 2215843bb75SJerome Forissier if (binh) { 2225843bb75SJerome Forissier if (binh->op && binh->h) 2235843bb75SJerome Forissier binh->op->close(binh->h); 2245843bb75SJerome Forissier file_put(binh->f); 2255843bb75SJerome Forissier } 2265843bb75SJerome Forissier free(binh); 2275843bb75SJerome Forissier } 2285843bb75SJerome Forissier 2295843bb75SJerome Forissier static TEE_Result system_open_ta_binary(struct system_ctx *ctx, 2305843bb75SJerome Forissier uint32_t param_types, 2315843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 2325843bb75SJerome Forissier { 2335843bb75SJerome Forissier TEE_Result res = TEE_SUCCESS; 2345843bb75SJerome Forissier struct bin_handle *binh = NULL; 2355843bb75SJerome Forissier int h = 0; 2365843bb75SJerome Forissier TEE_UUID *uuid = NULL; 2375843bb75SJerome Forissier uint8_t tag[FILE_TAG_SIZE] = { 0 }; 2385843bb75SJerome Forissier unsigned int tag_len = sizeof(tag); 2395843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 2405843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_OUTPUT, 2415843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 2425843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 2435843bb75SJerome Forissier 2445843bb75SJerome Forissier if (exp_pt != param_types) 2455843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 2465843bb75SJerome Forissier if (params[0].memref.size != sizeof(*uuid)) 2475843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 2485843bb75SJerome Forissier 2495843bb75SJerome Forissier uuid = params[0].memref.buffer; 2505843bb75SJerome Forissier 2515843bb75SJerome Forissier binh = calloc(1, sizeof(*binh)); 2525843bb75SJerome Forissier if (!binh) 2535843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 2545843bb75SJerome Forissier 2555843bb75SJerome Forissier SCATTERED_ARRAY_FOREACH(binh->op, ta_stores, struct user_ta_store_ops) { 2565843bb75SJerome Forissier DMSG("Lookup user TA ELF %pUl (%s)", 2575843bb75SJerome Forissier (void *)uuid, binh->op->description); 2585843bb75SJerome Forissier 2595843bb75SJerome Forissier res = binh->op->open(uuid, &binh->h); 2605843bb75SJerome Forissier DMSG("res=0x%x", res); 2615843bb75SJerome Forissier if (res != TEE_ERROR_ITEM_NOT_FOUND && 2625843bb75SJerome Forissier res != TEE_ERROR_STORAGE_NOT_AVAILABLE) 2635843bb75SJerome Forissier break; 2645843bb75SJerome Forissier } 2655843bb75SJerome Forissier if (res) 2665843bb75SJerome Forissier goto err; 2675843bb75SJerome Forissier 2685843bb75SJerome Forissier res = binh->op->get_size(binh->h, &binh->size_bytes); 2695843bb75SJerome Forissier if (res) 2705843bb75SJerome Forissier goto err; 2715843bb75SJerome Forissier res = binh->op->get_tag(binh->h, tag, &tag_len); 2725843bb75SJerome Forissier if (res) 2735843bb75SJerome Forissier goto err; 2745843bb75SJerome Forissier binh->f = file_get_by_tag(tag, tag_len); 2755843bb75SJerome Forissier if (!binh->f) 2765843bb75SJerome Forissier goto err_oom; 2775843bb75SJerome Forissier 2785843bb75SJerome Forissier h = handle_get(&ctx->db, binh); 2795843bb75SJerome Forissier if (h < 0) 2805843bb75SJerome Forissier goto err_oom; 281908ce2d4SJens Wiklander params[0].value.a = h; 2825843bb75SJerome Forissier 2835843bb75SJerome Forissier return TEE_SUCCESS; 2845843bb75SJerome Forissier err_oom: 2855843bb75SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 2865843bb75SJerome Forissier err: 2875843bb75SJerome Forissier ta_bin_close(binh); 2885843bb75SJerome Forissier return res; 2895843bb75SJerome Forissier } 2905843bb75SJerome Forissier 2915843bb75SJerome Forissier static TEE_Result system_close_ta_binary(struct system_ctx *ctx, 2925843bb75SJerome Forissier uint32_t param_types, 2935843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 2945843bb75SJerome Forissier { 2955843bb75SJerome Forissier TEE_Result res = TEE_SUCCESS; 2965843bb75SJerome Forissier struct bin_handle *binh = NULL; 2975843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 2985843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 2995843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 3005843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 3015843bb75SJerome Forissier 3025843bb75SJerome Forissier if (exp_pt != param_types) 3035843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 3045843bb75SJerome Forissier 3055843bb75SJerome Forissier if (params[0].value.b) 3065843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 3075843bb75SJerome Forissier 3085843bb75SJerome Forissier binh = handle_put(&ctx->db, params[0].value.a); 3095843bb75SJerome Forissier if (!binh) 3105843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 3115843bb75SJerome Forissier 3125843bb75SJerome Forissier if (binh->offs_bytes < binh->size_bytes) 3135843bb75SJerome Forissier res = binh->op->read(binh->h, NULL, 3145843bb75SJerome Forissier binh->size_bytes - binh->offs_bytes); 3155843bb75SJerome Forissier 3165843bb75SJerome Forissier ta_bin_close(binh); 3175843bb75SJerome Forissier return res; 3185843bb75SJerome Forissier } 3195843bb75SJerome Forissier 3205843bb75SJerome Forissier static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va, 3215843bb75SJerome Forissier size_t offs_bytes, size_t num_bytes) 3225843bb75SJerome Forissier { 3235843bb75SJerome Forissier TEE_Result res = TEE_SUCCESS; 3244047f318SJens Wiklander size_t next_offs = 0; 3255843bb75SJerome Forissier 3265843bb75SJerome Forissier if (offs_bytes < binh->offs_bytes) 3275843bb75SJerome Forissier return TEE_ERROR_BAD_STATE; 3284047f318SJens Wiklander 3294047f318SJens Wiklander if (ADD_OVERFLOW(offs_bytes, num_bytes, &next_offs)) 3304047f318SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 3314047f318SJens Wiklander 3325843bb75SJerome Forissier if (offs_bytes > binh->offs_bytes) { 3335843bb75SJerome Forissier res = binh->op->read(binh->h, NULL, 3345843bb75SJerome Forissier offs_bytes - binh->offs_bytes); 3355843bb75SJerome Forissier if (res) 3365843bb75SJerome Forissier return res; 3375843bb75SJerome Forissier binh->offs_bytes = offs_bytes; 3385843bb75SJerome Forissier } 3395843bb75SJerome Forissier 3404047f318SJens Wiklander if (next_offs > binh->size_bytes) { 3415843bb75SJerome Forissier size_t rb = binh->size_bytes - binh->offs_bytes; 3425843bb75SJerome Forissier 3435843bb75SJerome Forissier res = binh->op->read(binh->h, (void *)va, rb); 3445843bb75SJerome Forissier if (res) 3455843bb75SJerome Forissier return res; 3464047f318SJens Wiklander memset((uint8_t *)va + rb, 0, num_bytes - rb); 3475843bb75SJerome Forissier binh->offs_bytes = binh->size_bytes; 3485843bb75SJerome Forissier } else { 3494047f318SJens Wiklander res = binh->op->read(binh->h, (void *)va, num_bytes); 3505843bb75SJerome Forissier if (res) 3515843bb75SJerome Forissier return res; 3524047f318SJens Wiklander binh->offs_bytes = next_offs; 3535843bb75SJerome Forissier } 3545843bb75SJerome Forissier 3555843bb75SJerome Forissier return TEE_SUCCESS; 3565843bb75SJerome Forissier } 3575843bb75SJerome Forissier 3585843bb75SJerome Forissier static TEE_Result system_map_ta_binary(struct system_ctx *ctx, 3595843bb75SJerome Forissier struct tee_ta_session *s, 3605843bb75SJerome Forissier uint32_t param_types, 3615843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 3625843bb75SJerome Forissier { 3635843bb75SJerome Forissier const uint32_t accept_flags = PTA_SYSTEM_MAP_FLAG_SHAREABLE | 3645843bb75SJerome Forissier PTA_SYSTEM_MAP_FLAG_WRITEABLE | 3655843bb75SJerome Forissier PTA_SYSTEM_MAP_FLAG_EXECUTABLE; 3665843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 3675843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT, 3685843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INOUT, 3695843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT); 3705843bb75SJerome Forissier struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx); 3715843bb75SJerome Forissier struct bin_handle *binh = NULL; 3721e4e976bSJens Wiklander uint32_t num_rounded_bytes = 0; 3735843bb75SJerome Forissier TEE_Result res = TEE_SUCCESS; 3745843bb75SJerome Forissier struct file_slice *fs = NULL; 3755843bb75SJerome Forissier bool file_is_locked = false; 3765843bb75SJerome Forissier struct mobj *mobj = NULL; 3775843bb75SJerome Forissier uint32_t offs_bytes = 0; 3785843bb75SJerome Forissier uint32_t offs_pages = 0; 3795843bb75SJerome Forissier uint32_t num_bytes = 0; 3805843bb75SJerome Forissier uint32_t pad_begin = 0; 3815843bb75SJerome Forissier uint32_t pad_end = 0; 3825843bb75SJerome Forissier size_t num_pages = 0; 3835843bb75SJerome Forissier uint32_t flags = 0; 3845843bb75SJerome Forissier uint32_t prot = 0; 3855843bb75SJerome Forissier vaddr_t va = 0; 3865843bb75SJerome Forissier 3875843bb75SJerome Forissier if (exp_pt != param_types) 3885843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 3895843bb75SJerome Forissier 3905843bb75SJerome Forissier binh = handle_lookup(&ctx->db, params[0].value.a); 3915843bb75SJerome Forissier if (!binh) 3925843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 3935843bb75SJerome Forissier flags = params[0].value.b; 3945843bb75SJerome Forissier offs_bytes = params[1].value.a; 3955843bb75SJerome Forissier num_bytes = params[1].value.b; 3965843bb75SJerome Forissier va = reg_pair_to_64(params[2].value.a, params[2].value.b); 3975843bb75SJerome Forissier pad_begin = params[3].value.a; 3985843bb75SJerome Forissier pad_end = params[3].value.b; 3995843bb75SJerome Forissier 4005843bb75SJerome Forissier if ((flags & accept_flags) != flags) 4015843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 4025843bb75SJerome Forissier 4035843bb75SJerome Forissier if ((flags & PTA_SYSTEM_MAP_FLAG_SHAREABLE) && 4045843bb75SJerome Forissier (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) 4055843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 4065843bb75SJerome Forissier 4075843bb75SJerome Forissier if ((flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE) && 4085843bb75SJerome Forissier (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) 4095843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 4105843bb75SJerome Forissier 4115843bb75SJerome Forissier if (offs_bytes & SMALL_PAGE_MASK) 4125843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 4135843bb75SJerome Forissier 4145843bb75SJerome Forissier prot = TEE_MATTR_UR | TEE_MATTR_PR; 4155843bb75SJerome Forissier if (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE) 4165843bb75SJerome Forissier prot |= TEE_MATTR_UW | TEE_MATTR_PW; 4175843bb75SJerome Forissier if (flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE) 4185843bb75SJerome Forissier prot |= TEE_MATTR_UX; 4195843bb75SJerome Forissier 4205843bb75SJerome Forissier offs_pages = offs_bytes >> SMALL_PAGE_SHIFT; 4211e4e976bSJens Wiklander if (ROUNDUP_OVERFLOW(num_bytes, SMALL_PAGE_SIZE, &num_rounded_bytes)) 4221e4e976bSJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 4231e4e976bSJens Wiklander num_pages = num_rounded_bytes / SMALL_PAGE_SIZE; 4245843bb75SJerome Forissier 4255843bb75SJerome Forissier if (!file_trylock(binh->f)) { 4265843bb75SJerome Forissier /* 4275843bb75SJerome Forissier * Before we can block on the file lock we must make all 4285843bb75SJerome Forissier * our page tables available for reclaiming in order to 4295843bb75SJerome Forissier * avoid a dead-lock with the other thread (which already 4305843bb75SJerome Forissier * is holding the file lock) mapping lots of memory below. 4315843bb75SJerome Forissier */ 4325843bb75SJerome Forissier tee_mmu_set_ctx(NULL); 4335843bb75SJerome Forissier file_lock(binh->f); 4345843bb75SJerome Forissier tee_mmu_set_ctx(s->ctx); 4355843bb75SJerome Forissier } 4365843bb75SJerome Forissier file_is_locked = true; 4375843bb75SJerome Forissier fs = file_find_slice(binh->f, offs_pages); 4385843bb75SJerome Forissier if (fs) { 4395843bb75SJerome Forissier /* If there's registered slice it has to match */ 4405843bb75SJerome Forissier if (fs->page_offset != offs_pages || 4415843bb75SJerome Forissier num_pages > fs->fobj->num_pages) { 4425843bb75SJerome Forissier res = TEE_ERROR_BAD_PARAMETERS; 4435843bb75SJerome Forissier goto err; 4445843bb75SJerome Forissier } 4455843bb75SJerome Forissier 4465843bb75SJerome Forissier /* If there's a slice we must be mapping shareable */ 4475843bb75SJerome Forissier if (!(flags & PTA_SYSTEM_MAP_FLAG_SHAREABLE)) { 4485843bb75SJerome Forissier res = TEE_ERROR_BAD_PARAMETERS; 4495843bb75SJerome Forissier goto err; 4505843bb75SJerome Forissier } 4515843bb75SJerome Forissier 4525843bb75SJerome Forissier mobj = mobj_with_fobj_alloc(fs->fobj, binh->f); 4535843bb75SJerome Forissier if (!mobj) { 4545843bb75SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 4555843bb75SJerome Forissier goto err; 4565843bb75SJerome Forissier } 4571e4e976bSJens Wiklander res = vm_map_pad(&utc->uctx, &va, num_rounded_bytes, 458b9651492SJens Wiklander prot, VM_FLAG_READONLY, 4595843bb75SJerome Forissier mobj, 0, pad_begin, pad_end); 460b9651492SJens Wiklander mobj_put(mobj); 4615843bb75SJerome Forissier if (res) 4625843bb75SJerome Forissier goto err; 4635843bb75SJerome Forissier } else { 4645843bb75SJerome Forissier struct fobj *f = fobj_ta_mem_alloc(num_pages); 4655843bb75SJerome Forissier struct file *file = NULL; 466b9651492SJens Wiklander uint32_t vm_flags = 0; 4675843bb75SJerome Forissier 4685843bb75SJerome Forissier if (!f) { 4695843bb75SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 4705843bb75SJerome Forissier goto err; 4715843bb75SJerome Forissier } 4725843bb75SJerome Forissier if (!(flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) { 4735843bb75SJerome Forissier file = binh->f; 4745843bb75SJerome Forissier vm_flags |= VM_FLAG_READONLY; 4755843bb75SJerome Forissier } 4765843bb75SJerome Forissier 4775843bb75SJerome Forissier mobj = mobj_with_fobj_alloc(f, file); 4785843bb75SJerome Forissier fobj_put(f); 4795843bb75SJerome Forissier if (!mobj) { 4805843bb75SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 4815843bb75SJerome Forissier goto err; 4825843bb75SJerome Forissier } 4831e4e976bSJens Wiklander res = vm_map_pad(&utc->uctx, &va, num_rounded_bytes, 4845843bb75SJerome Forissier TEE_MATTR_PRW, vm_flags, mobj, 0, 4855843bb75SJerome Forissier pad_begin, pad_end); 486b9651492SJens Wiklander mobj_put(mobj); 4875843bb75SJerome Forissier if (res) 4885843bb75SJerome Forissier goto err; 4895843bb75SJerome Forissier res = binh_copy_to(binh, va, offs_bytes, num_bytes); 4905843bb75SJerome Forissier if (res) 4915843bb75SJerome Forissier goto err_unmap_va; 4921e4e976bSJens Wiklander res = vm_set_prot(&utc->uctx, va, num_rounded_bytes, 4931936dfc7SJens Wiklander prot); 4945843bb75SJerome Forissier if (res) 4955843bb75SJerome Forissier goto err_unmap_va; 4965843bb75SJerome Forissier 4975843bb75SJerome Forissier /* 4985843bb75SJerome Forissier * The context currently is active set it again to update 4995843bb75SJerome Forissier * the mapping. 5005843bb75SJerome Forissier */ 5015843bb75SJerome Forissier tee_mmu_set_ctx(s->ctx); 5025843bb75SJerome Forissier 5035843bb75SJerome Forissier if (!(flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) { 5045843bb75SJerome Forissier res = file_add_slice(binh->f, f, offs_pages); 5055843bb75SJerome Forissier if (res) 5065843bb75SJerome Forissier goto err_unmap_va; 5075843bb75SJerome Forissier } 5085843bb75SJerome Forissier } 5095843bb75SJerome Forissier 5105843bb75SJerome Forissier file_unlock(binh->f); 5115843bb75SJerome Forissier 5125843bb75SJerome Forissier reg_pair_from_64(va, ¶ms[2].value.a, ¶ms[2].value.b); 5135843bb75SJerome Forissier return TEE_SUCCESS; 5145843bb75SJerome Forissier 5155843bb75SJerome Forissier err_unmap_va: 5161e4e976bSJens Wiklander if (vm_unmap(&utc->uctx, va, num_rounded_bytes)) 5175843bb75SJerome Forissier panic(); 5185843bb75SJerome Forissier 5195843bb75SJerome Forissier /* 5205843bb75SJerome Forissier * The context currently is active set it again to update 5215843bb75SJerome Forissier * the mapping. 5225843bb75SJerome Forissier */ 5235843bb75SJerome Forissier tee_mmu_set_ctx(s->ctx); 5245843bb75SJerome Forissier 5255843bb75SJerome Forissier err: 5265843bb75SJerome Forissier if (file_is_locked) 5275843bb75SJerome Forissier file_unlock(binh->f); 5285843bb75SJerome Forissier 5295843bb75SJerome Forissier return res; 5305843bb75SJerome Forissier } 5315843bb75SJerome Forissier 5325843bb75SJerome Forissier static TEE_Result system_copy_from_ta_binary(struct system_ctx *ctx, 5335843bb75SJerome Forissier uint32_t param_types, 5345843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 5355843bb75SJerome Forissier { 5365843bb75SJerome Forissier struct bin_handle *binh = NULL; 5375843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 5385843bb75SJerome Forissier TEE_PARAM_TYPE_MEMREF_OUTPUT, 5395843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 5405843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 5415843bb75SJerome Forissier 5425843bb75SJerome Forissier if (exp_pt != param_types) 5435843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 5445843bb75SJerome Forissier 5455843bb75SJerome Forissier binh = handle_lookup(&ctx->db, params[0].value.a); 5465843bb75SJerome Forissier if (!binh) 5475843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 5485843bb75SJerome Forissier 5495843bb75SJerome Forissier return binh_copy_to(binh, (vaddr_t)params[1].memref.buffer, 5505843bb75SJerome Forissier params[0].value.b, params[1].memref.size); 5515843bb75SJerome Forissier } 5525843bb75SJerome Forissier 5535843bb75SJerome Forissier static TEE_Result system_set_prot(struct tee_ta_session *s, 5545843bb75SJerome Forissier uint32_t param_types, 5555843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 5565843bb75SJerome Forissier { 5575843bb75SJerome Forissier const uint32_t accept_flags = PTA_SYSTEM_MAP_FLAG_WRITEABLE | 5585843bb75SJerome Forissier PTA_SYSTEM_MAP_FLAG_EXECUTABLE; 5595843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 5605843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT, 5615843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 5625843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 5635843bb75SJerome Forissier struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx); 5645843bb75SJerome Forissier uint32_t prot = TEE_MATTR_UR | TEE_MATTR_PR; 5655843bb75SJerome Forissier TEE_Result res = TEE_SUCCESS; 5665843bb75SJerome Forissier uint32_t vm_flags = 0; 5675843bb75SJerome Forissier uint32_t flags = 0; 56818871ad0SJens Wiklander vaddr_t end_va = 0; 5695843bb75SJerome Forissier vaddr_t va = 0; 5705843bb75SJerome Forissier size_t sz = 0; 5715843bb75SJerome Forissier 5725843bb75SJerome Forissier if (exp_pt != param_types) 5735843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 5745843bb75SJerome Forissier 5755843bb75SJerome Forissier flags = params[0].value.b; 5765843bb75SJerome Forissier 5775843bb75SJerome Forissier if ((flags & accept_flags) != flags) 5785843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 5795843bb75SJerome Forissier if (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE) 5805843bb75SJerome Forissier prot |= TEE_MATTR_UW | TEE_MATTR_PW; 5815843bb75SJerome Forissier if (flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE) 5825843bb75SJerome Forissier prot |= TEE_MATTR_UX; 5835843bb75SJerome Forissier 584f19dd214SJens Wiklander va = reg_pair_to_64(params[1].value.a, params[1].value.b); 5855843bb75SJerome Forissier sz = ROUNDUP(params[0].value.a, SMALL_PAGE_SIZE); 5865843bb75SJerome Forissier 58718871ad0SJens Wiklander /* 58818871ad0SJens Wiklander * The vm_get_flags() and vm_set_prot() are supposed to detect or 58918871ad0SJens Wiklander * handle overflow directly or indirectly. However, this function 59018871ad0SJens Wiklander * an API function so an extra guard here is in order. If nothing 59118871ad0SJens Wiklander * else to make it easier to review the code. 59218871ad0SJens Wiklander */ 59318871ad0SJens Wiklander if (ADD_OVERFLOW(va, sz, &end_va)) 59418871ad0SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 59518871ad0SJens Wiklander 5961936dfc7SJens Wiklander res = vm_get_flags(&utc->uctx, va, sz, &vm_flags); 5975843bb75SJerome Forissier if (res) 5985843bb75SJerome Forissier return res; 59979f22013SJens Wiklander if (vm_flags & VM_FLAG_PERMANENT) 60079f22013SJens Wiklander return TEE_ERROR_ACCESS_DENIED; 6015843bb75SJerome Forissier 6025843bb75SJerome Forissier /* 6035843bb75SJerome Forissier * If the segment is a mapping of a part of a file (vm_flags & 6045843bb75SJerome Forissier * VM_FLAG_READONLY) it cannot be made writeable as all mapped 6055843bb75SJerome Forissier * files are mapped read-only. 6065843bb75SJerome Forissier */ 6075843bb75SJerome Forissier if ((vm_flags & VM_FLAG_READONLY) && 6085843bb75SJerome Forissier (prot & (TEE_MATTR_UW | TEE_MATTR_PW))) 6095843bb75SJerome Forissier return TEE_ERROR_ACCESS_DENIED; 6105843bb75SJerome Forissier 6111936dfc7SJens Wiklander return vm_set_prot(&utc->uctx, va, sz, prot); 6125843bb75SJerome Forissier } 6135843bb75SJerome Forissier 6145843bb75SJerome Forissier static TEE_Result system_remap(struct tee_ta_session *s, uint32_t param_types, 6155843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 6165843bb75SJerome Forissier { 6175843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 6185843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT, 6195843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INOUT, 6205843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT); 6215843bb75SJerome Forissier struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx); 6225843bb75SJerome Forissier TEE_Result res = TEE_SUCCESS; 6235843bb75SJerome Forissier uint32_t num_bytes = 0; 6245843bb75SJerome Forissier uint32_t pad_begin = 0; 62579f22013SJens Wiklander uint32_t vm_flags = 0; 6265843bb75SJerome Forissier uint32_t pad_end = 0; 6275843bb75SJerome Forissier vaddr_t old_va = 0; 6285843bb75SJerome Forissier vaddr_t new_va = 0; 6295843bb75SJerome Forissier 6305843bb75SJerome Forissier if (exp_pt != param_types) 6315843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 6325843bb75SJerome Forissier 6335843bb75SJerome Forissier num_bytes = params[0].value.a; 6345843bb75SJerome Forissier old_va = reg_pair_to_64(params[1].value.a, params[1].value.b); 6355843bb75SJerome Forissier new_va = reg_pair_to_64(params[2].value.a, params[2].value.b); 6365843bb75SJerome Forissier pad_begin = params[3].value.a; 6375843bb75SJerome Forissier pad_end = params[3].value.b; 6385843bb75SJerome Forissier 63979f22013SJens Wiklander res = vm_get_flags(&utc->uctx, old_va, num_bytes, &vm_flags); 64079f22013SJens Wiklander if (res) 64179f22013SJens Wiklander return res; 64279f22013SJens Wiklander if (vm_flags & VM_FLAG_PERMANENT) 64379f22013SJens Wiklander return TEE_ERROR_ACCESS_DENIED; 64479f22013SJens Wiklander 6451936dfc7SJens Wiklander res = vm_remap(&utc->uctx, &new_va, old_va, num_bytes, pad_begin, 6461936dfc7SJens Wiklander pad_end); 6475843bb75SJerome Forissier if (!res) 6485843bb75SJerome Forissier reg_pair_from_64(new_va, ¶ms[2].value.a, 6495843bb75SJerome Forissier ¶ms[2].value.b); 6505843bb75SJerome Forissier 6515843bb75SJerome Forissier return res; 6525843bb75SJerome Forissier } 6535843bb75SJerome Forissier 6545843bb75SJerome Forissier /* ldelf has the same architecture/register width as the kernel */ 6555843bb75SJerome Forissier #ifdef ARM32 6565843bb75SJerome Forissier static const bool is_arm32 = true; 6575843bb75SJerome Forissier #else 6585843bb75SJerome Forissier static const bool is_arm32; 6595843bb75SJerome Forissier #endif 6605843bb75SJerome Forissier 6615843bb75SJerome Forissier static TEE_Result call_ldelf_dlopen(struct user_ta_ctx *utc, TEE_UUID *uuid, 6625843bb75SJerome Forissier uint32_t flags) 6635843bb75SJerome Forissier { 6645843bb75SJerome Forissier uaddr_t usr_stack = utc->ldelf_stack_ptr; 6655843bb75SJerome Forissier TEE_Result res = TEE_ERROR_GENERIC; 6665843bb75SJerome Forissier struct dl_entry_arg *arg = NULL; 6675843bb75SJerome Forissier uint32_t panic_code = 0; 6685843bb75SJerome Forissier uint32_t panicked = 0; 6695843bb75SJerome Forissier 6705843bb75SJerome Forissier assert(uuid); 6715843bb75SJerome Forissier 6725843bb75SJerome Forissier usr_stack -= ROUNDUP(sizeof(*arg), STACK_ALIGNMENT); 6735843bb75SJerome Forissier arg = (struct dl_entry_arg *)usr_stack; 6745843bb75SJerome Forissier 6751936dfc7SJens Wiklander res = tee_mmu_check_access_rights(&utc->uctx, 6761936dfc7SJens Wiklander TEE_MEMORY_ACCESS_READ | 6775843bb75SJerome Forissier TEE_MEMORY_ACCESS_WRITE | 6785843bb75SJerome Forissier TEE_MEMORY_ACCESS_ANY_OWNER, 6795843bb75SJerome Forissier (uaddr_t)arg, sizeof(*arg)); 6805843bb75SJerome Forissier if (res) { 6815843bb75SJerome Forissier EMSG("ldelf stack is inaccessible!"); 6825843bb75SJerome Forissier return res; 6835843bb75SJerome Forissier } 6845843bb75SJerome Forissier 6855843bb75SJerome Forissier memset(arg, 0, sizeof(*arg)); 6865843bb75SJerome Forissier arg->cmd = LDELF_DL_ENTRY_DLOPEN; 6875843bb75SJerome Forissier arg->dlopen.uuid = *uuid; 6885843bb75SJerome Forissier arg->dlopen.flags = flags; 6895843bb75SJerome Forissier 6905843bb75SJerome Forissier res = thread_enter_user_mode((vaddr_t)arg, 0, 0, 0, 6915843bb75SJerome Forissier usr_stack, utc->dl_entry_func, 6925843bb75SJerome Forissier is_arm32, &panicked, &panic_code); 6935843bb75SJerome Forissier if (panicked) { 6945843bb75SJerome Forissier EMSG("ldelf dl_entry function panicked"); 6955843bb75SJerome Forissier abort_print_current_ta(); 6965843bb75SJerome Forissier res = TEE_ERROR_TARGET_DEAD; 6975843bb75SJerome Forissier } 6985843bb75SJerome Forissier if (!res) 6995843bb75SJerome Forissier res = arg->ret; 7005843bb75SJerome Forissier 7015843bb75SJerome Forissier return res; 7025843bb75SJerome Forissier } 7035843bb75SJerome Forissier 7045843bb75SJerome Forissier static TEE_Result call_ldelf_dlsym(struct user_ta_ctx *utc, TEE_UUID *uuid, 7055843bb75SJerome Forissier const char *sym, size_t maxlen, vaddr_t *val) 7065843bb75SJerome Forissier { 7075843bb75SJerome Forissier uaddr_t usr_stack = utc->ldelf_stack_ptr; 7085843bb75SJerome Forissier TEE_Result res = TEE_ERROR_GENERIC; 7095843bb75SJerome Forissier struct dl_entry_arg *arg = NULL; 7105843bb75SJerome Forissier uint32_t panic_code = 0; 7115843bb75SJerome Forissier uint32_t panicked = 0; 7125843bb75SJerome Forissier size_t len = strnlen(sym, maxlen); 7135843bb75SJerome Forissier 7145843bb75SJerome Forissier if (len == maxlen) 7155843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 7165843bb75SJerome Forissier 7175843bb75SJerome Forissier usr_stack -= ROUNDUP(sizeof(*arg) + len + 1, STACK_ALIGNMENT); 7185843bb75SJerome Forissier arg = (struct dl_entry_arg *)usr_stack; 7195843bb75SJerome Forissier 7201936dfc7SJens Wiklander res = tee_mmu_check_access_rights(&utc->uctx, 7211936dfc7SJens Wiklander TEE_MEMORY_ACCESS_READ | 7225843bb75SJerome Forissier TEE_MEMORY_ACCESS_WRITE | 7235843bb75SJerome Forissier TEE_MEMORY_ACCESS_ANY_OWNER, 7241936dfc7SJens Wiklander (uaddr_t)arg, sizeof(*arg) + len + 1); 7255843bb75SJerome Forissier if (res) { 7265843bb75SJerome Forissier EMSG("ldelf stack is inaccessible!"); 7275843bb75SJerome Forissier return res; 7285843bb75SJerome Forissier } 7295843bb75SJerome Forissier 7305843bb75SJerome Forissier memset(arg, 0, sizeof(*arg)); 7315843bb75SJerome Forissier arg->cmd = LDELF_DL_ENTRY_DLSYM; 7325843bb75SJerome Forissier arg->dlsym.uuid = *uuid; 7335843bb75SJerome Forissier memcpy(arg->dlsym.symbol, sym, len); 7348027bd32SEtienne Carriere arg->dlsym.symbol[len] = '\0'; 7355843bb75SJerome Forissier 7365843bb75SJerome Forissier res = thread_enter_user_mode((vaddr_t)arg, 0, 0, 0, 7375843bb75SJerome Forissier usr_stack, utc->dl_entry_func, 7385843bb75SJerome Forissier is_arm32, &panicked, &panic_code); 7395843bb75SJerome Forissier if (panicked) { 7405843bb75SJerome Forissier EMSG("ldelf dl_entry function panicked"); 7415843bb75SJerome Forissier abort_print_current_ta(); 7425843bb75SJerome Forissier res = TEE_ERROR_TARGET_DEAD; 7435843bb75SJerome Forissier } 7445843bb75SJerome Forissier if (!res) { 7455843bb75SJerome Forissier res = arg->ret; 7465843bb75SJerome Forissier if (!res) 7475843bb75SJerome Forissier *val = arg->dlsym.val; 7485843bb75SJerome Forissier } 7495843bb75SJerome Forissier 7505843bb75SJerome Forissier return res; 7515843bb75SJerome Forissier } 7525843bb75SJerome Forissier 7535843bb75SJerome Forissier static TEE_Result system_dlopen(struct tee_ta_session *cs, uint32_t param_types, 7545843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 7555843bb75SJerome Forissier { 7565843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 7575843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT, 7585843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 7595843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 7605843bb75SJerome Forissier TEE_Result res = TEE_ERROR_GENERIC; 7615843bb75SJerome Forissier struct tee_ta_session *s = NULL; 7625843bb75SJerome Forissier struct user_ta_ctx *utc = NULL; 7635843bb75SJerome Forissier TEE_UUID *uuid = NULL; 7645843bb75SJerome Forissier uint32_t flags = 0; 7655843bb75SJerome Forissier 7665843bb75SJerome Forissier if (exp_pt != param_types) 7675843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 7685843bb75SJerome Forissier 7695843bb75SJerome Forissier uuid = params[0].memref.buffer; 7705843bb75SJerome Forissier if (!uuid || params[0].memref.size != sizeof(*uuid)) 7715843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 7725843bb75SJerome Forissier 7735843bb75SJerome Forissier flags = params[1].value.a; 7745843bb75SJerome Forissier 7755843bb75SJerome Forissier utc = to_user_ta_ctx(cs->ctx); 7765843bb75SJerome Forissier 7775843bb75SJerome Forissier s = tee_ta_pop_current_session(); 7785843bb75SJerome Forissier res = call_ldelf_dlopen(utc, uuid, flags); 7795843bb75SJerome Forissier tee_ta_push_current_session(s); 7805843bb75SJerome Forissier 7815843bb75SJerome Forissier return res; 7825843bb75SJerome Forissier } 7835843bb75SJerome Forissier 7845843bb75SJerome Forissier static TEE_Result system_dlsym(struct tee_ta_session *cs, uint32_t param_types, 7855843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 7865843bb75SJerome Forissier { 7875843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 7885843bb75SJerome Forissier TEE_PARAM_TYPE_MEMREF_INPUT, 7895843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_OUTPUT, 7905843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 7915843bb75SJerome Forissier TEE_Result res = TEE_ERROR_GENERIC; 7925843bb75SJerome Forissier struct tee_ta_session *s = NULL; 7935843bb75SJerome Forissier struct user_ta_ctx *utc = NULL; 7945843bb75SJerome Forissier const char *sym = NULL; 7955843bb75SJerome Forissier TEE_UUID *uuid = NULL; 7965843bb75SJerome Forissier size_t maxlen = 0; 7975843bb75SJerome Forissier vaddr_t va = 0; 7985843bb75SJerome Forissier 7995843bb75SJerome Forissier if (exp_pt != param_types) 8005843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 8015843bb75SJerome Forissier 8025843bb75SJerome Forissier uuid = params[0].memref.buffer; 8035843bb75SJerome Forissier if (uuid && params[0].memref.size != sizeof(*uuid)) 8045843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 8055843bb75SJerome Forissier 8065843bb75SJerome Forissier sym = params[1].memref.buffer; 8075843bb75SJerome Forissier if (!sym) 8085843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 8095843bb75SJerome Forissier maxlen = params[1].memref.size; 8105843bb75SJerome Forissier 8115843bb75SJerome Forissier utc = to_user_ta_ctx(cs->ctx); 8125843bb75SJerome Forissier 8135843bb75SJerome Forissier s = tee_ta_pop_current_session(); 8145843bb75SJerome Forissier res = call_ldelf_dlsym(utc, uuid, sym, maxlen, &va); 8155843bb75SJerome Forissier tee_ta_push_current_session(s); 8165843bb75SJerome Forissier 8175843bb75SJerome Forissier if (!res) 8185843bb75SJerome Forissier reg_pair_from_64(va, ¶ms[2].value.a, ¶ms[2].value.b); 8195843bb75SJerome Forissier 8205843bb75SJerome Forissier return res; 8215843bb75SJerome Forissier } 8225843bb75SJerome Forissier 823dd333f03SJavier Almansa Sobrino static TEE_Result system_get_tpm_event_log(uint32_t param_types, 824dd333f03SJavier Almansa Sobrino TEE_Param params[TEE_NUM_PARAMS]) 825dd333f03SJavier Almansa Sobrino { 826dd333f03SJavier Almansa Sobrino uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT, 827dd333f03SJavier Almansa Sobrino TEE_PARAM_TYPE_NONE, 828dd333f03SJavier Almansa Sobrino TEE_PARAM_TYPE_NONE, 829dd333f03SJavier Almansa Sobrino TEE_PARAM_TYPE_NONE); 830dd333f03SJavier Almansa Sobrino size_t size = 0; 831dd333f03SJavier Almansa Sobrino TEE_Result res = TEE_SUCCESS; 832dd333f03SJavier Almansa Sobrino 833dd333f03SJavier Almansa Sobrino if (exp_pt != param_types) 834dd333f03SJavier Almansa Sobrino return TEE_ERROR_BAD_PARAMETERS; 835dd333f03SJavier Almansa Sobrino 836dd333f03SJavier Almansa Sobrino size = params[0].memref.size; 837dd333f03SJavier Almansa Sobrino res = tpm_get_event_log(params[0].memref.buffer, &size); 838dd333f03SJavier Almansa Sobrino params[0].memref.size = size; 839dd333f03SJavier Almansa Sobrino 840dd333f03SJavier Almansa Sobrino return res; 841dd333f03SJavier Almansa Sobrino } 842dd333f03SJavier Almansa Sobrino 8435843bb75SJerome Forissier static TEE_Result open_session(uint32_t param_types __unused, 8445843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS] __unused, 8455843bb75SJerome Forissier void **sess_ctx) 8465843bb75SJerome Forissier { 8475843bb75SJerome Forissier struct tee_ta_session *s = NULL; 8485843bb75SJerome Forissier struct system_ctx *ctx = NULL; 8495843bb75SJerome Forissier 8505843bb75SJerome Forissier /* Check that we're called from a user TA */ 8515843bb75SJerome Forissier s = tee_ta_get_calling_session(); 8525843bb75SJerome Forissier if (!s) 8535843bb75SJerome Forissier return TEE_ERROR_ACCESS_DENIED; 8545843bb75SJerome Forissier if (!is_user_ta_ctx(s->ctx)) 8555843bb75SJerome Forissier return TEE_ERROR_ACCESS_DENIED; 8565843bb75SJerome Forissier 8575843bb75SJerome Forissier ctx = calloc(1, sizeof(*ctx)); 8585843bb75SJerome Forissier if (!ctx) 8595843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 8605843bb75SJerome Forissier 8615843bb75SJerome Forissier *sess_ctx = ctx; 8625843bb75SJerome Forissier 8635843bb75SJerome Forissier return TEE_SUCCESS; 8645843bb75SJerome Forissier } 8655843bb75SJerome Forissier 8665843bb75SJerome Forissier static void close_session(void *sess_ctx) 8675843bb75SJerome Forissier { 8685843bb75SJerome Forissier struct system_ctx *ctx = sess_ctx; 8695843bb75SJerome Forissier 8705843bb75SJerome Forissier handle_db_destroy(&ctx->db, ta_bin_close); 8715843bb75SJerome Forissier free(ctx); 8725843bb75SJerome Forissier } 8735843bb75SJerome Forissier 8745843bb75SJerome Forissier static TEE_Result invoke_command(void *sess_ctx, uint32_t cmd_id, 8755843bb75SJerome Forissier uint32_t param_types, 8765843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 8775843bb75SJerome Forissier { 8785843bb75SJerome Forissier struct tee_ta_session *s = tee_ta_get_calling_session(); 8795843bb75SJerome Forissier 8805843bb75SJerome Forissier switch (cmd_id) { 8815843bb75SJerome Forissier case PTA_SYSTEM_ADD_RNG_ENTROPY: 8825843bb75SJerome Forissier return system_rng_reseed(s, param_types, params); 8835843bb75SJerome Forissier case PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY: 8845843bb75SJerome Forissier return system_derive_ta_unique_key(s, param_types, params); 8855843bb75SJerome Forissier case PTA_SYSTEM_MAP_ZI: 8865843bb75SJerome Forissier return system_map_zi(s, param_types, params); 8875843bb75SJerome Forissier case PTA_SYSTEM_UNMAP: 8885843bb75SJerome Forissier return system_unmap(s, param_types, params); 8895843bb75SJerome Forissier case PTA_SYSTEM_OPEN_TA_BINARY: 8905843bb75SJerome Forissier return system_open_ta_binary(sess_ctx, param_types, params); 8915843bb75SJerome Forissier case PTA_SYSTEM_CLOSE_TA_BINARY: 8925843bb75SJerome Forissier return system_close_ta_binary(sess_ctx, param_types, params); 8935843bb75SJerome Forissier case PTA_SYSTEM_MAP_TA_BINARY: 8945843bb75SJerome Forissier return system_map_ta_binary(sess_ctx, s, param_types, params); 8955843bb75SJerome Forissier case PTA_SYSTEM_COPY_FROM_TA_BINARY: 8965843bb75SJerome Forissier return system_copy_from_ta_binary(sess_ctx, param_types, 8975843bb75SJerome Forissier params); 8985843bb75SJerome Forissier case PTA_SYSTEM_SET_PROT: 8995843bb75SJerome Forissier return system_set_prot(s, param_types, params); 9005843bb75SJerome Forissier case PTA_SYSTEM_REMAP: 9015843bb75SJerome Forissier return system_remap(s, param_types, params); 9025843bb75SJerome Forissier case PTA_SYSTEM_DLOPEN: 9035843bb75SJerome Forissier return system_dlopen(s, param_types, params); 9045843bb75SJerome Forissier case PTA_SYSTEM_DLSYM: 9055843bb75SJerome Forissier return system_dlsym(s, param_types, params); 906dd333f03SJavier Almansa Sobrino case PTA_SYSTEM_GET_TPM_EVENT_LOG: 907dd333f03SJavier Almansa Sobrino return system_get_tpm_event_log(param_types, params); 9085843bb75SJerome Forissier default: 9095843bb75SJerome Forissier break; 9105843bb75SJerome Forissier } 9115843bb75SJerome Forissier 9125843bb75SJerome Forissier return TEE_ERROR_NOT_IMPLEMENTED; 9135843bb75SJerome Forissier } 9145843bb75SJerome Forissier 9155843bb75SJerome Forissier pseudo_ta_register(.uuid = PTA_SYSTEM_UUID, .name = "system.pta", 9165843bb75SJerome Forissier .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT, 9175843bb75SJerome Forissier .open_session_entry_point = open_session, 9185843bb75SJerome Forissier .close_session_entry_point = close_session, 9195843bb75SJerome Forissier .invoke_command_entry_point = invoke_command); 920