xref: /optee_os/core/tee/socket.c (revision 7c94d5d65c3a31418d82b5fcad5ad33d493acd12)
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>
96e9e277fSJerome Forissier #include <optee_rpc_cmd.h>
106e9e277fSJerome Forissier #include <pta_socket.h>
116e9e277fSJerome Forissier #include <string.h>
126e9e277fSJerome Forissier #include <tee/tee_fs_rpc.h>
136e9e277fSJerome Forissier 
1400b3b9a2SJens Wiklander static uint32_t get_instance_id(struct ts_session *sess)
156e9e277fSJerome Forissier {
166e9e277fSJerome Forissier 	return sess->ctx->ops->get_instance_id(sess->ctx);
176e9e277fSJerome Forissier }
186e9e277fSJerome Forissier 
196e9e277fSJerome Forissier static TEE_Result socket_open(uint32_t instance_id, uint32_t param_types,
206e9e277fSJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS])
216e9e277fSJerome Forissier {
22*7c94d5d6SJens Wiklander 	struct thread_param tpm[4] = { };
23*7c94d5d6SJens Wiklander 	struct mobj *mobj = NULL;
24*7c94d5d6SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
25*7c94d5d6SJens Wiklander 	void *va = NULL;
266e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
276e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_INPUT,
286e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
296e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_VALUE_OUTPUT);
306e9e277fSJerome Forissier 
316e9e277fSJerome Forissier 	if (exp_pt != param_types) {
326e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
336e9e277fSJerome Forissier 		     param_types, exp_pt);
346e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
356e9e277fSJerome Forissier 	}
366e9e277fSJerome Forissier 
371a7d8eaeSJens Wiklander 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
381a7d8eaeSJens Wiklander 					THREAD_SHM_TYPE_APPLICATION,
399bee8f2aSJens Wiklander 					params[1].memref.size, &mobj);
406e9e277fSJerome Forissier 	if (!va)
416e9e277fSJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
426e9e277fSJerome Forissier 
436e9e277fSJerome Forissier 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
446e9e277fSJerome Forissier 
45*7c94d5d6SJens Wiklander 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_OPEN, instance_id, 0);
46*7c94d5d6SJens Wiklander 	tpm[1] = THREAD_PARAM_VALUE(IN,
476e9e277fSJerome Forissier 				    params[0].value.b, /* server port number */
486e9e277fSJerome Forissier 				    params[2].value.a, /* protocol */
49*7c94d5d6SJens Wiklander 				    params[0].value.a  /* ip version */);
50*7c94d5d6SJens Wiklander 	tpm[2] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size);
51*7c94d5d6SJens Wiklander 	tpm[3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0);
526e9e277fSJerome Forissier 
536e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 4, tpm);
546e9e277fSJerome Forissier 	if (res == TEE_SUCCESS)
556e9e277fSJerome Forissier 		params[3].value.a = tpm[3].u.value.a;
566e9e277fSJerome Forissier 
576e9e277fSJerome Forissier 	return res;
586e9e277fSJerome Forissier }
596e9e277fSJerome Forissier 
606e9e277fSJerome Forissier static TEE_Result socket_close(uint32_t instance_id, uint32_t param_types,
616e9e277fSJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS])
626e9e277fSJerome Forissier {
63*7c94d5d6SJens Wiklander 	struct thread_param tpm = { };
646e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
656e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE,
666e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE,
676e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE);
686e9e277fSJerome Forissier 
696e9e277fSJerome Forissier 	if (exp_pt != param_types) {
706e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
716e9e277fSJerome Forissier 		     param_types, exp_pt);
726e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
736e9e277fSJerome Forissier 	}
746e9e277fSJerome Forissier 
75*7c94d5d6SJens Wiklander 	tpm = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_CLOSE, instance_id,
766e9e277fSJerome Forissier 				 params[0].value.a);
776e9e277fSJerome Forissier 
786e9e277fSJerome Forissier 	return thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
796e9e277fSJerome Forissier }
806e9e277fSJerome Forissier 
816e9e277fSJerome Forissier static TEE_Result socket_send(uint32_t instance_id, uint32_t param_types,
826e9e277fSJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS])
836e9e277fSJerome Forissier {
84*7c94d5d6SJens Wiklander 	struct thread_param tpm[3] = { };
85*7c94d5d6SJens Wiklander 	struct mobj *mobj = NULL;
86*7c94d5d6SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
87*7c94d5d6SJens Wiklander 	void *va = NULL;
886e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
896e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_INPUT,
906e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_VALUE_OUTPUT,
916e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE);
926e9e277fSJerome Forissier 
936e9e277fSJerome Forissier 	if (exp_pt != param_types) {
946e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
956e9e277fSJerome Forissier 		     param_types, exp_pt);
966e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
976e9e277fSJerome Forissier 	}
986e9e277fSJerome Forissier 
991a7d8eaeSJens Wiklander 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1001a7d8eaeSJens Wiklander 					THREAD_SHM_TYPE_APPLICATION,
1019bee8f2aSJens Wiklander 					params[1].memref.size, &mobj);
1026e9e277fSJerome Forissier 	if (!va)
1036e9e277fSJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
1046e9e277fSJerome Forissier 
1056e9e277fSJerome Forissier 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
1066e9e277fSJerome Forissier 
107*7c94d5d6SJens Wiklander 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_SEND, instance_id,
108*7c94d5d6SJens Wiklander 				    params[0].value.a /* handle */);
109*7c94d5d6SJens Wiklander 	tpm[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size);
110*7c94d5d6SJens Wiklander 	tpm[2] = THREAD_PARAM_VALUE(INOUT, params[0].value.b, /* timeout */
111*7c94d5d6SJens Wiklander 				     0, 0);
1126e9e277fSJerome Forissier 
1136e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
1146e9e277fSJerome Forissier 	params[2].value.a = tpm[2].u.value.b; /* transmitted bytes */
1156e9e277fSJerome Forissier 
1166e9e277fSJerome Forissier 	return res;
1176e9e277fSJerome Forissier }
1186e9e277fSJerome Forissier 
1196e9e277fSJerome Forissier static TEE_Result socket_recv(uint32_t instance_id, uint32_t param_types,
1206e9e277fSJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS])
1216e9e277fSJerome Forissier {
122*7c94d5d6SJens Wiklander 	struct thread_param tpm[3] = { };
123e9907fd7SJens Wiklander 	struct mobj *mobj = NULL;
124e9907fd7SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
125e9907fd7SJens Wiklander 	void *va = NULL;
1266e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
1276e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
1286e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE,
1296e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE);
1306e9e277fSJerome Forissier 
1316e9e277fSJerome Forissier 	if (exp_pt != param_types) {
1326e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
1336e9e277fSJerome Forissier 		     param_types, exp_pt);
1346e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
1356e9e277fSJerome Forissier 	}
1366e9e277fSJerome Forissier 
137e9907fd7SJens Wiklander 	if (params[1].memref.size) {
1381a7d8eaeSJens Wiklander 		va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1391a7d8eaeSJens Wiklander 						THREAD_SHM_TYPE_APPLICATION,
1409bee8f2aSJens Wiklander 						params[1].memref.size, &mobj);
1416e9e277fSJerome Forissier 		if (!va)
1426e9e277fSJerome Forissier 			return TEE_ERROR_OUT_OF_MEMORY;
143e9907fd7SJens Wiklander 	}
1446e9e277fSJerome Forissier 
145*7c94d5d6SJens Wiklander 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_RECV, instance_id,
146*7c94d5d6SJens Wiklander 				    params[0].value.a /* handle */);
147*7c94d5d6SJens Wiklander 	tpm[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, params[1].memref.size);
148*7c94d5d6SJens Wiklander 	tpm[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* timeout */, 0, 0);
1496e9e277fSJerome Forissier 
1506e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
1516e9e277fSJerome Forissier 
1526e9e277fSJerome Forissier 	if (params[1].memref.size)
153e9907fd7SJens Wiklander 		memcpy(params[1].memref.buffer, va,
154e9907fd7SJens Wiklander 		       MIN(params[1].memref.size, tpm[1].u.memref.size));
155e9907fd7SJens Wiklander 	params[1].memref.size = tpm[1].u.memref.size;
1566e9e277fSJerome Forissier 
1576e9e277fSJerome Forissier 	return res;
1586e9e277fSJerome Forissier }
1596e9e277fSJerome Forissier 
1606e9e277fSJerome Forissier static TEE_Result socket_ioctl(uint32_t instance_id, uint32_t param_types,
1616e9e277fSJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS])
1626e9e277fSJerome Forissier {
163*7c94d5d6SJens Wiklander 	struct thread_param tpm[3] = { };
164*7c94d5d6SJens Wiklander 	struct mobj *mobj = NULL;
165*7c94d5d6SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
166*7c94d5d6SJens Wiklander 	void *va = NULL;
1676e9e277fSJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
1686e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_INOUT,
1696e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE,
1706e9e277fSJerome Forissier 					  TEE_PARAM_TYPE_NONE);
1716e9e277fSJerome Forissier 
1726e9e277fSJerome Forissier 	if (exp_pt != param_types) {
1736e9e277fSJerome Forissier 		DMSG("got param_types 0x%x, expected 0x%x",
1746e9e277fSJerome Forissier 		     param_types, exp_pt);
1756e9e277fSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
1766e9e277fSJerome Forissier 	}
1776e9e277fSJerome Forissier 
1781a7d8eaeSJens Wiklander 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1791a7d8eaeSJens Wiklander 					THREAD_SHM_TYPE_APPLICATION,
1809bee8f2aSJens Wiklander 					params[1].memref.size, &mobj);
1816e9e277fSJerome Forissier 	if (!va)
1826e9e277fSJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
1836e9e277fSJerome Forissier 
1846e9e277fSJerome Forissier 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
1856e9e277fSJerome Forissier 
186*7c94d5d6SJens Wiklander 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_IOCTL, instance_id,
187*7c94d5d6SJens Wiklander 				    params[0].value.a /* handle */);
188*7c94d5d6SJens Wiklander 	tpm[1] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, params[1].memref.size);
189*7c94d5d6SJens Wiklander 	tpm[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* ioctl command */,
190*7c94d5d6SJens Wiklander 				    0, 0);
1916e9e277fSJerome Forissier 
1926e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
1936e9e277fSJerome Forissier 	if (tpm[1].u.memref.size <= params[1].memref.size)
1946e9e277fSJerome Forissier 		memcpy(params[1].memref.buffer, va, tpm[1].u.memref.size);
1956e9e277fSJerome Forissier 
1966e9e277fSJerome Forissier 	params[1].memref.size = tpm[1].u.memref.size;
1976e9e277fSJerome Forissier 
1986e9e277fSJerome Forissier 	return res;
1996e9e277fSJerome Forissier }
2006e9e277fSJerome Forissier 
2016e9e277fSJerome Forissier typedef TEE_Result (*ta_func)(uint32_t instance_id, uint32_t param_types,
2026e9e277fSJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS]);
2036e9e277fSJerome Forissier 
2046e9e277fSJerome Forissier static const ta_func ta_funcs[] = {
2056e9e277fSJerome Forissier 	[PTA_SOCKET_OPEN] = socket_open,
2066e9e277fSJerome Forissier 	[PTA_SOCKET_CLOSE] = socket_close,
2076e9e277fSJerome Forissier 	[PTA_SOCKET_SEND] = socket_send,
2086e9e277fSJerome Forissier 	[PTA_SOCKET_RECV] = socket_recv,
2096e9e277fSJerome Forissier 	[PTA_SOCKET_IOCTL] = socket_ioctl,
2106e9e277fSJerome Forissier };
2116e9e277fSJerome Forissier 
2126e9e277fSJerome Forissier /*
2136e9e277fSJerome Forissier  * Trusted Application Entry Points
2146e9e277fSJerome Forissier  */
2156e9e277fSJerome Forissier 
2166e9e277fSJerome Forissier static TEE_Result pta_socket_open_session(uint32_t param_types __unused,
2176e9e277fSJerome Forissier 			TEE_Param pParams[TEE_NUM_PARAMS] __unused,
2186e9e277fSJerome Forissier 			void **sess_ctx)
2196e9e277fSJerome Forissier {
22000b3b9a2SJens Wiklander 	struct ts_session *s = ts_get_calling_session();
2216e9e277fSJerome Forissier 
2226e9e277fSJerome Forissier 	/* Check that we're called from a TA */
22300b3b9a2SJens Wiklander 	if (!s || !is_user_ta_ctx(s->ctx))
2246e9e277fSJerome Forissier 		return TEE_ERROR_ACCESS_DENIED;
2256e9e277fSJerome Forissier 
2266e9e277fSJerome Forissier 	*sess_ctx = (void *)(vaddr_t)get_instance_id(s);
2276e9e277fSJerome Forissier 
2286e9e277fSJerome Forissier 	return TEE_SUCCESS;
2296e9e277fSJerome Forissier }
2306e9e277fSJerome Forissier 
2316e9e277fSJerome Forissier static void pta_socket_close_session(void *sess_ctx)
2326e9e277fSJerome Forissier {
2336e9e277fSJerome Forissier 	TEE_Result res;
2346e9e277fSJerome Forissier 	struct thread_param tpm = {
2356e9e277fSJerome Forissier 		.attr = THREAD_PARAM_ATTR_VALUE_IN, .u.value = {
2366e9e277fSJerome Forissier 			.a = OPTEE_RPC_SOCKET_CLOSE_ALL, .b = (vaddr_t)sess_ctx,
2376e9e277fSJerome Forissier 		},
2386e9e277fSJerome Forissier 	};
2396e9e277fSJerome Forissier 
2406e9e277fSJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
2416e9e277fSJerome Forissier 	if (res != TEE_SUCCESS)
2426e9e277fSJerome Forissier 		DMSG("OPTEE_RPC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res);
2436e9e277fSJerome Forissier }
2446e9e277fSJerome Forissier 
2456e9e277fSJerome Forissier static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id,
2466e9e277fSJerome Forissier 			uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS])
2476e9e277fSJerome Forissier {
2486e9e277fSJerome Forissier 	if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id])
2496e9e277fSJerome Forissier 		return ta_funcs[cmd_id]((vaddr_t)sess_ctx, param_types, params);
2506e9e277fSJerome Forissier 
2516e9e277fSJerome Forissier 	return TEE_ERROR_NOT_IMPLEMENTED;
2526e9e277fSJerome Forissier }
2536e9e277fSJerome Forissier 
2546e9e277fSJerome Forissier pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket",
2556e9e277fSJerome Forissier 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
2566e9e277fSJerome Forissier 		   .open_session_entry_point = pta_socket_open_session,
2576e9e277fSJerome Forissier 		   .close_session_entry_point = pta_socket_close_session,
2586e9e277fSJerome Forissier 		   .invoke_command_entry_point = pta_socket_invoke_command);
259