1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016-2017, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <mm/mobj.h>
8 #include <kernel/pseudo_ta.h>
9 #include <optee_rpc_cmd.h>
10 #include <pta_socket.h>
11 #include <string.h>
12 #include <tee/tee_fs_rpc.h>
13 
get_instance_id(struct ts_session * sess)14 static uint32_t get_instance_id(struct ts_session *sess)
15 {
16 	return sess->ctx->ops->get_instance_id(sess->ctx);
17 }
18 
socket_open(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])19 static TEE_Result socket_open(uint32_t instance_id, uint32_t param_types,
20 			      TEE_Param params[TEE_NUM_PARAMS])
21 {
22 	struct thread_param tpm[4] = { };
23 	struct mobj *mobj = NULL;
24 	TEE_Result res = TEE_SUCCESS;
25 	void *va = NULL;
26 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
27 					  TEE_PARAM_TYPE_MEMREF_INPUT,
28 					  TEE_PARAM_TYPE_VALUE_INPUT,
29 					  TEE_PARAM_TYPE_VALUE_OUTPUT);
30 
31 	if (exp_pt != param_types) {
32 		DMSG("got param_types 0x%x, expected 0x%x",
33 		     param_types, exp_pt);
34 		return TEE_ERROR_BAD_PARAMETERS;
35 	}
36 
37 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
38 					THREAD_SHM_TYPE_APPLICATION,
39 					params[1].memref.size, &mobj);
40 	if (!va)
41 		return TEE_ERROR_OUT_OF_MEMORY;
42 
43 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
44 
45 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_OPEN, instance_id, 0);
46 	tpm[1] = THREAD_PARAM_VALUE(IN,
47 				    params[0].value.b, /* server port number */
48 				    params[2].value.a, /* protocol */
49 				    params[0].value.a  /* ip version */);
50 	tpm[2] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size);
51 	tpm[3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0);
52 
53 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 4, tpm);
54 	if (res == TEE_SUCCESS)
55 		params[3].value.a = tpm[3].u.value.a;
56 
57 	return res;
58 }
59 
socket_close(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])60 static TEE_Result socket_close(uint32_t instance_id, uint32_t param_types,
61 			       TEE_Param params[TEE_NUM_PARAMS])
62 {
63 	struct thread_param tpm = { };
64 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
65 					  TEE_PARAM_TYPE_NONE,
66 					  TEE_PARAM_TYPE_NONE,
67 					  TEE_PARAM_TYPE_NONE);
68 
69 	if (exp_pt != param_types) {
70 		DMSG("got param_types 0x%x, expected 0x%x",
71 		     param_types, exp_pt);
72 		return TEE_ERROR_BAD_PARAMETERS;
73 	}
74 
75 	tpm = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_CLOSE, instance_id,
76 				 params[0].value.a);
77 
78 	return thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
79 }
80 
socket_send(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])81 static TEE_Result socket_send(uint32_t instance_id, uint32_t param_types,
82 			      TEE_Param params[TEE_NUM_PARAMS])
83 {
84 	struct thread_param tpm[3] = { };
85 	struct mobj *mobj = NULL;
86 	TEE_Result res = TEE_SUCCESS;
87 	void *va = NULL;
88 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
89 					  TEE_PARAM_TYPE_MEMREF_INPUT,
90 					  TEE_PARAM_TYPE_VALUE_OUTPUT,
91 					  TEE_PARAM_TYPE_NONE);
92 
93 	if (exp_pt != param_types) {
94 		DMSG("got param_types 0x%x, expected 0x%x",
95 		     param_types, exp_pt);
96 		return TEE_ERROR_BAD_PARAMETERS;
97 	}
98 
99 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
100 					THREAD_SHM_TYPE_APPLICATION,
101 					params[1].memref.size, &mobj);
102 	if (!va)
103 		return TEE_ERROR_OUT_OF_MEMORY;
104 
105 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
106 
107 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_SEND, instance_id,
108 				    params[0].value.a /* handle */);
109 	tpm[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size);
110 	tpm[2] = THREAD_PARAM_VALUE(INOUT, params[0].value.b, /* timeout */
111 				     0, 0);
112 
113 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
114 	params[2].value.a = tpm[2].u.value.b; /* transmitted bytes */
115 
116 	return res;
117 }
118 
socket_recv(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])119 static TEE_Result socket_recv(uint32_t instance_id, uint32_t param_types,
120 			      TEE_Param params[TEE_NUM_PARAMS])
121 {
122 	struct thread_param tpm[3] = { };
123 	struct mobj *mobj = NULL;
124 	TEE_Result res = TEE_SUCCESS;
125 	void *va = NULL;
126 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
127 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
128 					  TEE_PARAM_TYPE_NONE,
129 					  TEE_PARAM_TYPE_NONE);
130 
131 	if (exp_pt != param_types) {
132 		DMSG("got param_types 0x%x, expected 0x%x",
133 		     param_types, exp_pt);
134 		return TEE_ERROR_BAD_PARAMETERS;
135 	}
136 
137 	if (params[1].memref.size) {
138 		va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
139 						THREAD_SHM_TYPE_APPLICATION,
140 						params[1].memref.size, &mobj);
141 		if (!va)
142 			return TEE_ERROR_OUT_OF_MEMORY;
143 	}
144 
145 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_RECV, instance_id,
146 				    params[0].value.a /* handle */);
147 	tpm[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, params[1].memref.size);
148 	tpm[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* timeout */, 0, 0);
149 
150 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
151 
152 	if (params[1].memref.size)
153 		memcpy(params[1].memref.buffer, va,
154 		       MIN(params[1].memref.size, tpm[1].u.memref.size));
155 	params[1].memref.size = tpm[1].u.memref.size;
156 
157 	return res;
158 }
159 
socket_ioctl(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])160 static TEE_Result socket_ioctl(uint32_t instance_id, uint32_t param_types,
161 			       TEE_Param params[TEE_NUM_PARAMS])
162 {
163 	struct thread_param tpm[3] = { };
164 	struct mobj *mobj = NULL;
165 	TEE_Result res = TEE_SUCCESS;
166 	void *va = NULL;
167 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
168 					  TEE_PARAM_TYPE_MEMREF_INOUT,
169 					  TEE_PARAM_TYPE_NONE,
170 					  TEE_PARAM_TYPE_NONE);
171 
172 	if (exp_pt != param_types) {
173 		DMSG("got param_types 0x%x, expected 0x%x",
174 		     param_types, exp_pt);
175 		return TEE_ERROR_BAD_PARAMETERS;
176 	}
177 
178 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
179 					THREAD_SHM_TYPE_APPLICATION,
180 					params[1].memref.size, &mobj);
181 	if (!va)
182 		return TEE_ERROR_OUT_OF_MEMORY;
183 
184 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
185 
186 	tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_IOCTL, instance_id,
187 				    params[0].value.a /* handle */);
188 	tpm[1] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, params[1].memref.size);
189 	tpm[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* ioctl command */,
190 				    0, 0);
191 
192 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
193 	if (tpm[1].u.memref.size <= params[1].memref.size)
194 		memcpy(params[1].memref.buffer, va, tpm[1].u.memref.size);
195 
196 	params[1].memref.size = tpm[1].u.memref.size;
197 
198 	return res;
199 }
200 
201 typedef TEE_Result (*ta_func)(uint32_t instance_id, uint32_t param_types,
202 			      TEE_Param params[TEE_NUM_PARAMS]);
203 
204 static const ta_func ta_funcs[] = {
205 	[PTA_SOCKET_OPEN] = socket_open,
206 	[PTA_SOCKET_CLOSE] = socket_close,
207 	[PTA_SOCKET_SEND] = socket_send,
208 	[PTA_SOCKET_RECV] = socket_recv,
209 	[PTA_SOCKET_IOCTL] = socket_ioctl,
210 };
211 
212 /*
213  * Trusted Application Entry Points
214  */
215 
pta_socket_open_session(uint32_t param_types __unused,TEE_Param pParams[TEE_NUM_PARAMS]__unused,void ** sess_ctx)216 static TEE_Result pta_socket_open_session(uint32_t param_types __unused,
217 			TEE_Param pParams[TEE_NUM_PARAMS] __unused,
218 			void **sess_ctx)
219 {
220 	struct ts_session *s = ts_get_calling_session();
221 
222 	/* Check that we're called from a TA */
223 	if (!s || !is_user_ta_ctx(s->ctx))
224 		return TEE_ERROR_ACCESS_DENIED;
225 
226 	*sess_ctx = (void *)(vaddr_t)get_instance_id(s);
227 
228 	return TEE_SUCCESS;
229 }
230 
pta_socket_close_session(void * sess_ctx)231 static void pta_socket_close_session(void *sess_ctx)
232 {
233 	TEE_Result res;
234 	struct thread_param tpm = {
235 		.attr = THREAD_PARAM_ATTR_VALUE_IN, .u.value = {
236 			.a = OPTEE_RPC_SOCKET_CLOSE_ALL, .b = (vaddr_t)sess_ctx,
237 		},
238 	};
239 
240 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
241 	if (res != TEE_SUCCESS)
242 		DMSG("OPTEE_RPC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res);
243 }
244 
pta_socket_invoke_command(void * sess_ctx,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])245 static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id,
246 			uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS])
247 {
248 	if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id])
249 		return ta_funcs[cmd_id]((vaddr_t)sess_ctx, param_types, params);
250 
251 	return TEE_ERROR_NOT_IMPLEMENTED;
252 }
253 
254 pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket",
255 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
256 		   .open_session_entry_point = pta_socket_open_session,
257 		   .close_session_entry_point = pta_socket_close_session,
258 		   .invoke_command_entry_point = pta_socket_invoke_command);
259