xref: /optee_os/core/tee/socket.c (revision 090e9463da46e73801daaba9939aeee5c2ee4656)
16e9e277fSJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
26e9e277fSJerome Forissier /*
36e9e277fSJerome Forissier  * Copyright (c) 2016-2017, Linaro Limited
46e9e277fSJerome Forissier  */
56e9e277fSJerome Forissier 
66e9e277fSJerome Forissier #include <assert.h>
76e9e277fSJerome Forissier #include <mm/mobj.h>
86e9e277fSJerome Forissier #include <kernel/pseudo_ta.h>
9*090e9463SJens Wiklander #include <kernel/user_access.h>
106e9e277fSJerome Forissier #include <optee_rpc_cmd.h>
116e9e277fSJerome Forissier #include <pta_socket.h>
126e9e277fSJerome Forissier #include <string.h>
136e9e277fSJerome Forissier #include <tee/tee_fs_rpc.h>
146e9e277fSJerome Forissier 
get_instance_id(struct ts_session * sess)1500b3b9a2SJens Wiklander static uint32_t get_instance_id(struct ts_session *sess)
166e9e277fSJerome Forissier {
176e9e277fSJerome Forissier 	return sess->ctx->ops->get_instance_id(sess->ctx);
186e9e277fSJerome Forissier }
196e9e277fSJerome Forissier 
socket_open(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])206e9e277fSJerome Forissier static TEE_Result socket_open(uint32_t instance_id, uint32_t param_types,
216e9e277fSJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS])
226e9e277fSJerome Forissier {
237c94d5d6SJens Wiklander 	struct thread_param tpm[4] = { };
247c94d5d6SJens Wiklander 	struct mobj *mobj = NULL;
257c94d5d6SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
267c94d5d6SJens Wiklander 	void *va = NULL;
276e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
286e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_INPUT,
296e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
306e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_VALUE_OUTPUT);
316e9e277fSJerome Forissier 
326e9e277fSJerome Forissier 	if (exp_pt != param_types) {
336e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
346e9e277fSJerome Forissier 		     param_types, exp_pt);
356e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
366e9e277fSJerome Forissier 	}
376e9e277fSJerome Forissier 
381a7d8eaeSJens Wiklander 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
391a7d8eaeSJens Wiklander 					THREAD_SHM_TYPE_APPLICATION,
409bee8f2aSJens Wiklander 					params[1].memref.size, &mobj);
416e9e277fSJerome Forissier 	if (!va)
426e9e277fSJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
436e9e277fSJerome Forissier 
44*090e9463SJens Wiklander 	res = copy_from_user(va, params[1].memref.buffer,
45*090e9463SJens Wiklander 			     params[1].memref.size);
46*090e9463SJens Wiklander 	if (res)
47*090e9463SJens Wiklander 		return res;
486e9e277fSJerome Forissier 
497c94d5d6SJens Wiklander 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_OPEN, instance_id, 0);
507c94d5d6SJens Wiklander 	tpm[1] = THREAD_PARAM_VALUE(IN,
516e9e277fSJerome Forissier 				    params[0].value.b, /* server port number */
526e9e277fSJerome Forissier 				    params[2].value.a, /* protocol */
537c94d5d6SJens Wiklander 				    params[0].value.a  /* ip version */);
547c94d5d6SJens Wiklander 	tpm[2] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size);
557c94d5d6SJens Wiklander 	tpm[3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0);
566e9e277fSJerome Forissier 
576e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 4, tpm);
586e9e277fSJerome Forissier 	if (res == TEE_SUCCESS)
596e9e277fSJerome Forissier 		params[3].value.a = tpm[3].u.value.a;
606e9e277fSJerome Forissier 
616e9e277fSJerome Forissier 	return res;
626e9e277fSJerome Forissier }
636e9e277fSJerome Forissier 
socket_close(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])646e9e277fSJerome Forissier static TEE_Result socket_close(uint32_t instance_id, uint32_t param_types,
656e9e277fSJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS])
666e9e277fSJerome Forissier {
677c94d5d6SJens Wiklander 	struct thread_param tpm = { };
686e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
696e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE,
706e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE,
716e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE);
726e9e277fSJerome Forissier 
736e9e277fSJerome Forissier 	if (exp_pt != param_types) {
746e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
756e9e277fSJerome Forissier 		     param_types, exp_pt);
766e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
776e9e277fSJerome Forissier 	}
786e9e277fSJerome Forissier 
797c94d5d6SJens Wiklander 	tpm = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_CLOSE, instance_id,
806e9e277fSJerome Forissier 				 params[0].value.a);
816e9e277fSJerome Forissier 
826e9e277fSJerome Forissier 	return thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
836e9e277fSJerome Forissier }
846e9e277fSJerome Forissier 
socket_send(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])856e9e277fSJerome Forissier static TEE_Result socket_send(uint32_t instance_id, uint32_t param_types,
866e9e277fSJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS])
876e9e277fSJerome Forissier {
887c94d5d6SJens Wiklander 	struct thread_param tpm[3] = { };
897c94d5d6SJens Wiklander 	struct mobj *mobj = NULL;
907c94d5d6SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
917c94d5d6SJens Wiklander 	void *va = NULL;
926e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
936e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_INPUT,
946e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_VALUE_OUTPUT,
956e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE);
966e9e277fSJerome Forissier 
976e9e277fSJerome Forissier 	if (exp_pt != param_types) {
986e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
996e9e277fSJerome Forissier 		     param_types, exp_pt);
1006e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
1016e9e277fSJerome Forissier 	}
1026e9e277fSJerome Forissier 
1031a7d8eaeSJens Wiklander 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1041a7d8eaeSJens Wiklander 					THREAD_SHM_TYPE_APPLICATION,
1059bee8f2aSJens Wiklander 					params[1].memref.size, &mobj);
1066e9e277fSJerome Forissier 	if (!va)
1076e9e277fSJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
1086e9e277fSJerome Forissier 
109*090e9463SJens Wiklander 	res = copy_from_user(va, params[1].memref.buffer,
110*090e9463SJens Wiklander 			     params[1].memref.size);
111*090e9463SJens Wiklander 	if (res)
112*090e9463SJens Wiklander 		return res;
1136e9e277fSJerome Forissier 
1147c94d5d6SJens Wiklander 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_SEND, instance_id,
1157c94d5d6SJens Wiklander 				    params[0].value.a /* handle */);
1167c94d5d6SJens Wiklander 	tpm[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size);
1177c94d5d6SJens Wiklander 	tpm[2] = THREAD_PARAM_VALUE(INOUT, params[0].value.b, /* timeout */
1187c94d5d6SJens Wiklander 				     0, 0);
1196e9e277fSJerome Forissier 
1206e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
1216e9e277fSJerome Forissier 	params[2].value.a = tpm[2].u.value.b; /* transmitted bytes */
1226e9e277fSJerome Forissier 
1236e9e277fSJerome Forissier 	return res;
1246e9e277fSJerome Forissier }
1256e9e277fSJerome Forissier 
socket_recv(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])1266e9e277fSJerome Forissier static TEE_Result socket_recv(uint32_t instance_id, uint32_t param_types,
1276e9e277fSJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS])
1286e9e277fSJerome Forissier {
1297c94d5d6SJens Wiklander 	struct thread_param tpm[3] = { };
130e9907fd7SJens Wiklander 	struct mobj *mobj = NULL;
131e9907fd7SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
132e9907fd7SJens Wiklander 	void *va = NULL;
1336e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
1346e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
1356e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE,
1366e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE);
1376e9e277fSJerome Forissier 
1386e9e277fSJerome Forissier 	if (exp_pt != param_types) {
1396e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
1406e9e277fSJerome Forissier 		     param_types, exp_pt);
1416e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
1426e9e277fSJerome Forissier 	}
1436e9e277fSJerome Forissier 
144e9907fd7SJens Wiklander 	if (params[1].memref.size) {
1451a7d8eaeSJens Wiklander 		va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1461a7d8eaeSJens Wiklander 						THREAD_SHM_TYPE_APPLICATION,
1479bee8f2aSJens Wiklander 						params[1].memref.size, &mobj);
1486e9e277fSJerome Forissier 		if (!va)
1496e9e277fSJerome Forissier 			return TEE_ERROR_OUT_OF_MEMORY;
150e9907fd7SJens Wiklander 	}
1516e9e277fSJerome Forissier 
1527c94d5d6SJens Wiklander 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_RECV, instance_id,
1537c94d5d6SJens Wiklander 				    params[0].value.a /* handle */);
1547c94d5d6SJens Wiklander 	tpm[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, params[1].memref.size);
1557c94d5d6SJens Wiklander 	tpm[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* timeout */, 0, 0);
1566e9e277fSJerome Forissier 
1576e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
1586e9e277fSJerome Forissier 
159*090e9463SJens Wiklander 	if (params[1].memref.size) {
160*090e9463SJens Wiklander 		TEE_Result res2 = TEE_SUCCESS;
161*090e9463SJens Wiklander 
162*090e9463SJens Wiklander 		res2 = copy_to_user(params[1].memref.buffer, va,
163*090e9463SJens Wiklander 				    MIN(params[1].memref.size,
164*090e9463SJens Wiklander 					tpm[1].u.memref.size));
165*090e9463SJens Wiklander 		if (res2)
166*090e9463SJens Wiklander 			return res2;
167*090e9463SJens Wiklander 	}
168e9907fd7SJens Wiklander 	params[1].memref.size = tpm[1].u.memref.size;
1696e9e277fSJerome Forissier 
1706e9e277fSJerome Forissier 	return res;
1716e9e277fSJerome Forissier }
1726e9e277fSJerome Forissier 
socket_ioctl(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])1736e9e277fSJerome Forissier static TEE_Result socket_ioctl(uint32_t instance_id, uint32_t param_types,
1746e9e277fSJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS])
1756e9e277fSJerome Forissier {
1767c94d5d6SJens Wiklander 	struct thread_param tpm[3] = { };
1777c94d5d6SJens Wiklander 	struct mobj *mobj = NULL;
1787c94d5d6SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
1797c94d5d6SJens Wiklander 	void *va = NULL;
1806e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
1816e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_INOUT,
1826e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE,
1836e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE);
1846e9e277fSJerome Forissier 
1856e9e277fSJerome Forissier 	if (exp_pt != param_types) {
1866e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
1876e9e277fSJerome Forissier 		     param_types, exp_pt);
1886e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
1896e9e277fSJerome Forissier 	}
1906e9e277fSJerome Forissier 
1911a7d8eaeSJens Wiklander 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1921a7d8eaeSJens Wiklander 					THREAD_SHM_TYPE_APPLICATION,
1939bee8f2aSJens Wiklander 					params[1].memref.size, &mobj);
1946e9e277fSJerome Forissier 	if (!va)
1956e9e277fSJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
1966e9e277fSJerome Forissier 
197*090e9463SJens Wiklander 	res = copy_from_user(va, params[1].memref.buffer,
198*090e9463SJens Wiklander 			     params[1].memref.size);
199*090e9463SJens Wiklander 	if (res)
200*090e9463SJens Wiklander 		return res;
2016e9e277fSJerome Forissier 
2027c94d5d6SJens Wiklander 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_IOCTL, instance_id,
2037c94d5d6SJens Wiklander 				    params[0].value.a /* handle */);
2047c94d5d6SJens Wiklander 	tpm[1] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, params[1].memref.size);
2057c94d5d6SJens Wiklander 	tpm[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* ioctl command */,
2067c94d5d6SJens Wiklander 				    0, 0);
2076e9e277fSJerome Forissier 
2086e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
209*090e9463SJens Wiklander 	if (tpm[1].u.memref.size <= params[1].memref.size) {
210*090e9463SJens Wiklander 		TEE_Result res2 = TEE_SUCCESS;
211*090e9463SJens Wiklander 
212*090e9463SJens Wiklander 		res2 = copy_to_user(params[1].memref.buffer, va,
213*090e9463SJens Wiklander 				    tpm[1].u.memref.size);
214*090e9463SJens Wiklander 		if (res2)
215*090e9463SJens Wiklander 			return res2;
216*090e9463SJens Wiklander 	}
2176e9e277fSJerome Forissier 
2186e9e277fSJerome Forissier 	params[1].memref.size = tpm[1].u.memref.size;
2196e9e277fSJerome Forissier 
2206e9e277fSJerome Forissier 	return res;
2216e9e277fSJerome Forissier }
2226e9e277fSJerome Forissier 
2236e9e277fSJerome Forissier typedef TEE_Result (*ta_func)(uint32_t instance_id, uint32_t param_types,
2246e9e277fSJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS]);
2256e9e277fSJerome Forissier 
2266e9e277fSJerome Forissier static const ta_func ta_funcs[] = {
2276e9e277fSJerome Forissier 	[PTA_SOCKET_OPEN] = socket_open,
2286e9e277fSJerome Forissier 	[PTA_SOCKET_CLOSE] = socket_close,
2296e9e277fSJerome Forissier 	[PTA_SOCKET_SEND] = socket_send,
2306e9e277fSJerome Forissier 	[PTA_SOCKET_RECV] = socket_recv,
2316e9e277fSJerome Forissier 	[PTA_SOCKET_IOCTL] = socket_ioctl,
2326e9e277fSJerome Forissier };
2336e9e277fSJerome Forissier 
2346e9e277fSJerome Forissier /*
2356e9e277fSJerome Forissier  * Trusted Application Entry Points
2366e9e277fSJerome Forissier  */
2376e9e277fSJerome Forissier 
pta_socket_open_session(uint32_t param_types __unused,TEE_Param pParams[TEE_NUM_PARAMS]__unused,void ** sess_ctx)2386e9e277fSJerome Forissier static TEE_Result pta_socket_open_session(uint32_t param_types __unused,
2396e9e277fSJerome Forissier 			TEE_Param pParams[TEE_NUM_PARAMS] __unused,
2406e9e277fSJerome Forissier 			void **sess_ctx)
2416e9e277fSJerome Forissier {
24200b3b9a2SJens Wiklander 	struct ts_session *s = ts_get_calling_session();
2436e9e277fSJerome Forissier 
2446e9e277fSJerome Forissier 	/* Check that we're called from a TA */
24500b3b9a2SJens Wiklander 	if (!s || !is_user_ta_ctx(s->ctx))
2466e9e277fSJerome Forissier 		return TEE_ERROR_ACCESS_DENIED;
2476e9e277fSJerome Forissier 
2486e9e277fSJerome Forissier 	*sess_ctx = (void *)(vaddr_t)get_instance_id(s);
2496e9e277fSJerome Forissier 
2506e9e277fSJerome Forissier 	return TEE_SUCCESS;
2516e9e277fSJerome Forissier }
2526e9e277fSJerome Forissier 
pta_socket_close_session(void * sess_ctx)2536e9e277fSJerome Forissier static void pta_socket_close_session(void *sess_ctx)
2546e9e277fSJerome Forissier {
2556e9e277fSJerome Forissier 	TEE_Result res;
2566e9e277fSJerome Forissier 	struct thread_param tpm = {
2576e9e277fSJerome Forissier 		.attr = THREAD_PARAM_ATTR_VALUE_IN, .u.value = {
2586e9e277fSJerome Forissier 			.a = OPTEE_RPC_SOCKET_CLOSE_ALL, .b = (vaddr_t)sess_ctx,
2596e9e277fSJerome Forissier 		},
2606e9e277fSJerome Forissier 	};
2616e9e277fSJerome Forissier 
2626e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
2636e9e277fSJerome Forissier 	if (res != TEE_SUCCESS)
2646e9e277fSJerome Forissier 		DMSG("OPTEE_RPC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res);
2656e9e277fSJerome Forissier }
2666e9e277fSJerome Forissier 
pta_socket_invoke_command(void * sess_ctx,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])2676e9e277fSJerome Forissier static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id,
2686e9e277fSJerome Forissier 			uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS])
2696e9e277fSJerome Forissier {
2706e9e277fSJerome Forissier 	if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id])
2716e9e277fSJerome Forissier 		return ta_funcs[cmd_id]((vaddr_t)sess_ctx, param_types, params);
2726e9e277fSJerome Forissier 
2736e9e277fSJerome Forissier 	return TEE_ERROR_NOT_IMPLEMENTED;
2746e9e277fSJerome Forissier }
2756e9e277fSJerome Forissier 
2766e9e277fSJerome Forissier pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket",
2776e9e277fSJerome Forissier 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
2786e9e277fSJerome Forissier 		   .open_session_entry_point = pta_socket_open_session,
2796e9e277fSJerome Forissier 		   .close_session_entry_point = pta_socket_close_session,
2806e9e277fSJerome Forissier 		   .invoke_command_entry_point = pta_socket_invoke_command);
281