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