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 15 static uint32_t get_instance_id(struct ts_session *sess) 16 { 17 return sess->ctx->ops->get_instance_id(sess->ctx); 18 } 19 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 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 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 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 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 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 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 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