xref: /optee_os/core/tee/socket.c (revision 9bee8f2a5af7ad5219a65d6f12ff25771f3325c0)
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 = thread_rpc_shm_cache_alloc(THREAD_SHM_TYPE_APPLICATION,
37 					params[1].memref.size, &mobj);
38 	if (!va)
39 		return TEE_ERROR_OUT_OF_MEMORY;
40 
41 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
42 
43 	struct thread_param tpm[4] = {
44 		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_OPEN,
45 					 instance_id, 0),
46 		[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 		[2] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size),
51 		[3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0),
52 	};
53 
54 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 4, tpm);
55 	if (res == TEE_SUCCESS)
56 		params[3].value.a = tpm[3].u.value.a;
57 
58 	return res;
59 }
60 
61 static TEE_Result socket_close(uint32_t instance_id, uint32_t param_types,
62 			       TEE_Param params[TEE_NUM_PARAMS])
63 {
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 	struct thread_param tpm = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_CLOSE,
76 						     instance_id,
77 						     params[0].value.a);
78 
79 	return thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
80 }
81 
82 static TEE_Result socket_send(uint32_t instance_id, uint32_t param_types,
83 			      TEE_Param params[TEE_NUM_PARAMS])
84 {
85 	struct mobj *mobj;
86 	TEE_Result res;
87 	void *va;
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_TYPE_APPLICATION,
100 					params[1].memref.size, &mobj);
101 	if (!va)
102 		return TEE_ERROR_OUT_OF_MEMORY;
103 
104 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
105 
106 	struct thread_param tpm[3] = {
107 		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_SEND, instance_id,
108 					 params[0].value.a /* handle */),
109 		[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size),
110 		[2] = THREAD_PARAM_VALUE(INOUT, params[0].value.b, /* timeout */
111 					 0, 0),
112 	};
113 
114 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
115 	params[2].value.a = tpm[2].u.value.b; /* transmitted bytes */
116 
117 	return res;
118 }
119 
120 static TEE_Result socket_recv(uint32_t instance_id, uint32_t param_types,
121 			      TEE_Param params[TEE_NUM_PARAMS])
122 {
123 	struct mobj *mobj;
124 	TEE_Result res;
125 	void *va;
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 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_TYPE_APPLICATION,
138 					params[1].memref.size, &mobj);
139 	if (!va)
140 		return TEE_ERROR_OUT_OF_MEMORY;
141 
142 	struct thread_param tpm[3] = {
143 		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_RECV, instance_id,
144 					 params[0].value.a /* handle */),
145 		[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, params[1].memref.size),
146 		[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* timeout */,
147 					 0, 0),
148 	};
149 
150 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
151 
152 	if (tpm[1].u.memref.size > params[1].memref.size)
153 		return TEE_ERROR_GENERIC;
154 	params[1].memref.size = tpm[1].u.memref.size;
155 	if (params[1].memref.size)
156 		memcpy(params[1].memref.buffer, va, params[1].memref.size);
157 
158 	return res;
159 }
160 
161 static TEE_Result socket_ioctl(uint32_t instance_id, uint32_t param_types,
162 			       TEE_Param params[TEE_NUM_PARAMS])
163 {
164 	struct mobj *mobj;
165 	TEE_Result res;
166 	void *va;
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_TYPE_APPLICATION,
179 					params[1].memref.size, &mobj);
180 	if (!va)
181 		return TEE_ERROR_OUT_OF_MEMORY;
182 
183 	memcpy(va, params[1].memref.buffer, params[1].memref.size);
184 
185 	struct thread_param tpm[3] = {
186 		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_IOCTL,
187 					 instance_id,
188 					 params[0].value.a /* handle */),
189 		[1] = THREAD_PARAM_MEMREF(INOUT, mobj, 0,
190 					  params[1].memref.size),
191 		[2] = THREAD_PARAM_VALUE(IN,
192 					 params[0].value.b /* ioctl command */,
193 					 0, 0),
194 	};
195 
196 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
197 	if (tpm[1].u.memref.size <= params[1].memref.size)
198 		memcpy(params[1].memref.buffer, va, tpm[1].u.memref.size);
199 
200 	params[1].memref.size = tpm[1].u.memref.size;
201 
202 	return res;
203 }
204 
205 typedef TEE_Result (*ta_func)(uint32_t instance_id, uint32_t param_types,
206 			      TEE_Param params[TEE_NUM_PARAMS]);
207 
208 static const ta_func ta_funcs[] = {
209 	[PTA_SOCKET_OPEN] = socket_open,
210 	[PTA_SOCKET_CLOSE] = socket_close,
211 	[PTA_SOCKET_SEND] = socket_send,
212 	[PTA_SOCKET_RECV] = socket_recv,
213 	[PTA_SOCKET_IOCTL] = socket_ioctl,
214 };
215 
216 /*
217  * Trusted Application Entry Points
218  */
219 
220 static TEE_Result pta_socket_open_session(uint32_t param_types __unused,
221 			TEE_Param pParams[TEE_NUM_PARAMS] __unused,
222 			void **sess_ctx)
223 {
224 	struct tee_ta_session *s;
225 
226 	/* Check that we're called from a TA */
227 	s = tee_ta_get_calling_session();
228 	if (!s)
229 		return TEE_ERROR_ACCESS_DENIED;
230 
231 	*sess_ctx = (void *)(vaddr_t)get_instance_id(s);
232 
233 	return TEE_SUCCESS;
234 }
235 
236 static void pta_socket_close_session(void *sess_ctx)
237 {
238 	TEE_Result res;
239 	struct thread_param tpm = {
240 		.attr = THREAD_PARAM_ATTR_VALUE_IN, .u.value = {
241 			.a = OPTEE_RPC_SOCKET_CLOSE_ALL, .b = (vaddr_t)sess_ctx,
242 		},
243 	};
244 
245 	res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
246 	if (res != TEE_SUCCESS)
247 		DMSG("OPTEE_RPC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res);
248 }
249 
250 static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id,
251 			uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS])
252 {
253 	if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id])
254 		return ta_funcs[cmd_id]((vaddr_t)sess_ctx, param_types, params);
255 
256 	return TEE_ERROR_NOT_IMPLEMENTED;
257 }
258 
259 pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket",
260 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
261 		   .open_session_entry_point = pta_socket_open_session,
262 		   .close_session_entry_point = pta_socket_close_session,
263 		   .invoke_command_entry_point = pta_socket_invoke_command);
264