xref: /optee_os/core/tee/socket.c (revision 43be6453dd3e98d39721c8bc6725416772f4205c)
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 tee_ta_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 = tee_fs_rpc_cache_alloc(params[1].memref.size, &mobj);
37 	if (!va)
38 		return TEE_ERROR_OUT_OF_MEMORY;
39 
40 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
41 
42 	struct thread_param tpm[4] = {
43 		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_OPEN,
44 					 instance_id, 0),
45 		[1] = THREAD_PARAM_VALUE(IN,
46 				params[0].value.b, /* server port number */
47 				params[2].value.a, /* protocol */
48 				params[0].value.a  /* ip version */),
49 		[2] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size),
50 		[3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0),
51 	};
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 
60 static TEE_Result socket_close(uint32_t instance_id, uint32_t param_types,
61 			       TEE_Param params[TEE_NUM_PARAMS])
62 {
63 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
64 					  TEE_PARAM_TYPE_NONE,
65 					  TEE_PARAM_TYPE_NONE,
66 					  TEE_PARAM_TYPE_NONE);
67 
68 	if (exp_pt != param_types) {
69 		DMSG("got param_types 0x%x, expected 0x%x",
70 		     param_types, exp_pt);
71 		return TEE_ERROR_BAD_PARAMETERS;
72 	}
73 
74 	struct thread_param tpm = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_CLOSE,
75 						     instance_id,
76 						     params[0].value.a);
77 
78 	return thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
79 }
80 
81 static TEE_Result socket_send(uint32_t instance_id, uint32_t param_types,
82 			      TEE_Param params[TEE_NUM_PARAMS])
83 {
84 	struct mobj *mobj;
85 	TEE_Result res;
86 	void *va;
87 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
88 					  TEE_PARAM_TYPE_MEMREF_INPUT,
89 					  TEE_PARAM_TYPE_VALUE_OUTPUT,
90 					  TEE_PARAM_TYPE_NONE);
91 
92 	if (exp_pt != param_types) {
93 		DMSG("got param_types 0x%x, expected 0x%x",
94 		     param_types, exp_pt);
95 		return TEE_ERROR_BAD_PARAMETERS;
96 	}
97 
98 	va = tee_fs_rpc_cache_alloc(params[1].memref.size, &mobj);
99 	if (!va)
100 		return TEE_ERROR_OUT_OF_MEMORY;
101 
102 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
103 
104 	struct thread_param tpm[3] = {
105 		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_SEND, instance_id,
106 					 params[0].value.a /* handle */),
107 		[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size),
108 		[2] = THREAD_PARAM_VALUE(INOUT, params[0].value.b, /* timeout */
109 					 0, 0),
110 	};
111 
112 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
113 	params[2].value.a = tpm[2].u.value.b; /* transmitted bytes */
114 
115 	return res;
116 }
117 
118 static TEE_Result socket_recv(uint32_t instance_id, uint32_t param_types,
119 			      TEE_Param params[TEE_NUM_PARAMS])
120 {
121 	struct mobj *mobj;
122 	TEE_Result res;
123 	void *va;
124 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
125 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
126 					  TEE_PARAM_TYPE_NONE,
127 					  TEE_PARAM_TYPE_NONE);
128 
129 	if (exp_pt != param_types) {
130 		DMSG("got param_types 0x%x, expected 0x%x",
131 		     param_types, exp_pt);
132 		return TEE_ERROR_BAD_PARAMETERS;
133 	}
134 
135 	va = tee_fs_rpc_cache_alloc(params[1].memref.size, &mobj);
136 	if (!va)
137 		return TEE_ERROR_OUT_OF_MEMORY;
138 
139 	struct thread_param tpm[3] = {
140 		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_RECV, instance_id,
141 					 params[0].value.a /* handle */),
142 		[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, params[1].memref.size),
143 		[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* timeout */,
144 					 0, 0),
145 	};
146 
147 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
148 
149 	if (tpm[1].u.memref.size > params[1].memref.size)
150 		return TEE_ERROR_GENERIC;
151 	params[1].memref.size = tpm[1].u.memref.size;
152 	if (params[1].memref.size)
153 		memcpy(params[1].memref.buffer, va, params[1].memref.size);
154 
155 	return res;
156 }
157 
158 static TEE_Result socket_ioctl(uint32_t instance_id, uint32_t param_types,
159 			       TEE_Param params[TEE_NUM_PARAMS])
160 {
161 	struct mobj *mobj;
162 	TEE_Result res;
163 	void *va;
164 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
165 					  TEE_PARAM_TYPE_MEMREF_INOUT,
166 					  TEE_PARAM_TYPE_NONE,
167 					  TEE_PARAM_TYPE_NONE);
168 
169 	if (exp_pt != param_types) {
170 		DMSG("got param_types 0x%x, expected 0x%x",
171 		     param_types, exp_pt);
172 		return TEE_ERROR_BAD_PARAMETERS;
173 	}
174 
175 	va = tee_fs_rpc_cache_alloc(params[1].memref.size, &mobj);
176 	if (!va)
177 		return TEE_ERROR_OUT_OF_MEMORY;
178 
179 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
180 
181 	struct thread_param tpm[3] = {
182 		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_IOCTL,
183 					 instance_id,
184 					 params[0].value.a /* handle */),
185 		[1] = THREAD_PARAM_MEMREF(INOUT, mobj, 0,
186 					  params[1].memref.size),
187 		[2] = THREAD_PARAM_VALUE(IN,
188 					 params[0].value.b /* ioctl command */,
189 					 0, 0),
190 	};
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 
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 tee_ta_session *s;
221 
222 	/* Check that we're called from a TA */
223 	s = tee_ta_get_calling_session();
224 	if (!s)
225 		return TEE_ERROR_ACCESS_DENIED;
226 
227 	*sess_ctx = (void *)(vaddr_t)get_instance_id(s);
228 
229 	return TEE_SUCCESS;
230 }
231 
232 static void pta_socket_close_session(void *sess_ctx)
233 {
234 	TEE_Result res;
235 	struct thread_param tpm = {
236 		.attr = THREAD_PARAM_ATTR_VALUE_IN, .u.value = {
237 			.a = OPTEE_RPC_SOCKET_CLOSE_ALL, .b = (vaddr_t)sess_ctx,
238 		},
239 	};
240 
241 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
242 	if (res != TEE_SUCCESS)
243 		DMSG("OPTEE_RPC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res);
244 }
245 
246 static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id,
247 			uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS])
248 {
249 	if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id])
250 		return ta_funcs[cmd_id]((vaddr_t)sess_ctx, param_types, params);
251 
252 	return TEE_ERROR_NOT_IMPLEMENTED;
253 }
254 
255 pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket",
256 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
257 		   .open_session_entry_point = pta_socket_open_session,
258 		   .close_session_entry_point = pta_socket_close_session,
259 		   .invoke_command_entry_point = pta_socket_invoke_command);
260