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