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