xref: /optee_os/core/pta/system.c (revision 095b07ce4d69723dbbc29da65544aa75fd08b8d6)
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, &params[1].value.a, &params[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, &params[2].value.a, &params[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, &params[2].value.a,
6495843bb75SJerome Forissier 				 &params[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, &params[2].value.a, &params[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