1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2018-2019, Linaro Limited
4 * Copyright (c) 2020, Arm Limited.
5 * Copyright (c) 2020, Open Mobile Platform LLC
6 */
7
8 #include <assert.h>
9 #include <crypto/crypto.h>
10 #include <kernel/handle.h>
11 #include <kernel/huk_subkey.h>
12 #include <kernel/ldelf_loader.h>
13 #include <kernel/misc.h>
14 #include <kernel/msg_param.h>
15 #include <kernel/pseudo_ta.h>
16 #include <kernel/tpm.h>
17 #include <kernel/ts_store.h>
18 #include <kernel/user_mode_ctx.h>
19 #include <ldelf.h>
20 #include <mm/file.h>
21 #include <mm/fobj.h>
22 #include <mm/vm.h>
23 #include <pta_system.h>
24 #include <stdlib_ext.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <tee_api_defines_extensions.h>
28 #include <tee_api_defines.h>
29 #include <tee/tee_supp_plugin_rpc.h>
30 #include <tee/uuid.h>
31 #include <util.h>
32
33 static unsigned int system_pnum;
34
system_rng_reseed(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])35 static TEE_Result system_rng_reseed(uint32_t param_types,
36 TEE_Param params[TEE_NUM_PARAMS])
37 {
38 size_t entropy_sz = 0;
39 uint8_t *entropy_input = NULL;
40 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
41 TEE_PARAM_TYPE_NONE,
42 TEE_PARAM_TYPE_NONE,
43 TEE_PARAM_TYPE_NONE);
44
45 if (exp_pt != param_types)
46 return TEE_ERROR_BAD_PARAMETERS;
47 entropy_input = params[0].memref.buffer;
48 entropy_sz = params[0].memref.size;
49
50 if (!entropy_sz || !entropy_input)
51 return TEE_ERROR_BAD_PARAMETERS;
52
53 crypto_rng_add_event(CRYPTO_RNG_SRC_NONSECURE, &system_pnum,
54 entropy_input, entropy_sz);
55 return TEE_SUCCESS;
56 }
57
system_derive_ta_unique_key(struct user_mode_ctx * uctx,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])58 static TEE_Result system_derive_ta_unique_key(struct user_mode_ctx *uctx,
59 uint32_t param_types,
60 TEE_Param params[TEE_NUM_PARAMS])
61 {
62 size_t data_len = sizeof(TEE_UUID);
63 TEE_Result res = TEE_ERROR_GENERIC;
64 uint8_t *data = NULL;
65 uint32_t access_flags = 0;
66 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
67 TEE_PARAM_TYPE_MEMREF_OUTPUT,
68 TEE_PARAM_TYPE_NONE,
69 TEE_PARAM_TYPE_NONE);
70
71 if (exp_pt != param_types)
72 return TEE_ERROR_BAD_PARAMETERS;
73
74 if (params[0].memref.size > TA_DERIVED_EXTRA_DATA_MAX_SIZE ||
75 params[1].memref.size < TA_DERIVED_KEY_MIN_SIZE ||
76 params[1].memref.size > TA_DERIVED_KEY_MAX_SIZE)
77 return TEE_ERROR_BAD_PARAMETERS;
78
79 /*
80 * The derived key shall not end up in non-secure memory by
81 * mistake.
82 *
83 * Note that we're allowing shared memory as long as it's
84 * secure. This is needed because a TA always uses shared memory
85 * when communicating with another TA.
86 */
87 access_flags = TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER |
88 TEE_MEMORY_ACCESS_SECURE;
89 res = vm_check_access_rights(uctx, access_flags,
90 (uaddr_t)params[1].memref.buffer,
91 params[1].memref.size);
92 if (res != TEE_SUCCESS)
93 return TEE_ERROR_SECURITY;
94
95 /* Take extra data into account. */
96 if (ADD_OVERFLOW(data_len, params[0].memref.size, &data_len))
97 return TEE_ERROR_SECURITY;
98
99 data = calloc(data_len, 1);
100 if (!data)
101 return TEE_ERROR_OUT_OF_MEMORY;
102
103 memcpy(data, &uctx->ts_ctx->uuid, sizeof(TEE_UUID));
104
105 /* Append the user provided data */
106 memcpy(data + sizeof(TEE_UUID), params[0].memref.buffer,
107 params[0].memref.size);
108
109 res = huk_subkey_derive(HUK_SUBKEY_UNIQUE_TA, data, data_len,
110 params[1].memref.buffer,
111 params[1].memref.size);
112 free_wipe(data);
113
114 return res;
115 }
116
system_map_zi(struct user_mode_ctx * uctx,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])117 static TEE_Result system_map_zi(struct user_mode_ctx *uctx,
118 uint32_t param_types,
119 TEE_Param params[TEE_NUM_PARAMS])
120 {
121 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
122 TEE_PARAM_TYPE_VALUE_INOUT,
123 TEE_PARAM_TYPE_VALUE_INPUT,
124 TEE_PARAM_TYPE_NONE);
125 uint32_t prot = TEE_MATTR_URW | TEE_MATTR_PRW;
126 TEE_Result res = TEE_ERROR_GENERIC;
127 struct mobj *mobj = NULL;
128 uint32_t pad_begin = 0;
129 uint32_t vm_flags = 0;
130 struct fobj *f = NULL;
131 uint32_t pad_end = 0;
132 size_t num_bytes = 0;
133 vaddr_t va = 0;
134
135 if (exp_pt != param_types)
136 return TEE_ERROR_BAD_PARAMETERS;
137 if (params[0].value.b & ~PTA_SYSTEM_MAP_FLAG_SHAREABLE)
138 return TEE_ERROR_BAD_PARAMETERS;
139
140 if (params[0].value.b & PTA_SYSTEM_MAP_FLAG_SHAREABLE)
141 vm_flags |= VM_FLAG_SHAREABLE;
142
143 num_bytes = params[0].value.a;
144 va = reg_pair_to_64(params[1].value.a, params[1].value.b);
145 pad_begin = params[2].value.a;
146 pad_end = params[2].value.b;
147
148 f = fobj_ta_mem_alloc(ROUNDUP_DIV(num_bytes, SMALL_PAGE_SIZE));
149 if (!f)
150 return TEE_ERROR_OUT_OF_MEMORY;
151 mobj = mobj_with_fobj_alloc(f, NULL);
152 fobj_put(f);
153 if (!mobj)
154 return TEE_ERROR_OUT_OF_MEMORY;
155 res = vm_map_pad(uctx, &va, num_bytes, prot, vm_flags,
156 mobj, 0, pad_begin, pad_end, 0);
157 mobj_put(mobj);
158 if (!res)
159 reg_pair_from_64(va, ¶ms[1].value.a, ¶ms[1].value.b);
160
161 return res;
162 }
163
system_unmap(struct user_mode_ctx * uctx,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])164 static TEE_Result system_unmap(struct user_mode_ctx *uctx, uint32_t param_types,
165 TEE_Param params[TEE_NUM_PARAMS])
166 {
167 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
168 TEE_PARAM_TYPE_VALUE_INPUT,
169 TEE_PARAM_TYPE_NONE,
170 TEE_PARAM_TYPE_NONE);
171 TEE_Result res = TEE_SUCCESS;
172 uint32_t vm_flags = 0;
173 vaddr_t end_va = 0;
174 vaddr_t va = 0;
175 size_t sz = 0;
176
177 if (exp_pt != param_types)
178 return TEE_ERROR_BAD_PARAMETERS;
179
180 if (params[0].value.b)
181 return TEE_ERROR_BAD_PARAMETERS;
182
183 va = reg_pair_to_64(params[1].value.a, params[1].value.b);
184 sz = ROUNDUP(params[0].value.a, SMALL_PAGE_SIZE);
185
186 /*
187 * The vm_get_flags() and vm_unmap() are supposed to detect or
188 * handle overflow directly or indirectly. However, this function
189 * an API function so an extra guard here is in order. If nothing
190 * else to make it easier to review the code.
191 */
192 if (ADD_OVERFLOW(va, sz, &end_va))
193 return TEE_ERROR_BAD_PARAMETERS;
194
195 res = vm_get_flags(uctx, va, sz, &vm_flags);
196 if (res)
197 return res;
198 if (vm_flags & VM_FLAG_PERMANENT)
199 return TEE_ERROR_ACCESS_DENIED;
200
201 return vm_unmap(uctx, va, sz);
202 }
203
system_dlopen(struct user_mode_ctx * uctx,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])204 static TEE_Result system_dlopen(struct user_mode_ctx *uctx,
205 uint32_t param_types,
206 TEE_Param params[TEE_NUM_PARAMS])
207 {
208 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
209 TEE_PARAM_TYPE_VALUE_INPUT,
210 TEE_PARAM_TYPE_NONE,
211 TEE_PARAM_TYPE_NONE);
212 TEE_Result res = TEE_ERROR_GENERIC;
213 struct ts_session *s = NULL;
214 TEE_UUID *uuid = NULL;
215 uint32_t flags = 0;
216
217 if (exp_pt != param_types)
218 return TEE_ERROR_BAD_PARAMETERS;
219
220 uuid = params[0].memref.buffer;
221 if (!uuid || params[0].memref.size != sizeof(*uuid))
222 return TEE_ERROR_BAD_PARAMETERS;
223
224 flags = params[1].value.a;
225
226 s = ts_pop_current_session();
227 res = ldelf_dlopen(uctx, uuid, flags);
228 ts_push_current_session(s);
229
230 return res;
231 }
232
system_dlsym(struct user_mode_ctx * uctx,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])233 static TEE_Result system_dlsym(struct user_mode_ctx *uctx, uint32_t param_types,
234 TEE_Param params[TEE_NUM_PARAMS])
235 {
236 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
237 TEE_PARAM_TYPE_MEMREF_INPUT,
238 TEE_PARAM_TYPE_VALUE_OUTPUT,
239 TEE_PARAM_TYPE_NONE);
240 TEE_Result res = TEE_ERROR_GENERIC;
241 struct ts_session *s = NULL;
242 const char *sym = NULL;
243 TEE_UUID *uuid = NULL;
244 size_t maxlen = 0;
245 vaddr_t va = 0;
246
247 if (exp_pt != param_types)
248 return TEE_ERROR_BAD_PARAMETERS;
249
250 uuid = params[0].memref.buffer;
251 if (!uuid || params[0].memref.size != sizeof(*uuid))
252 return TEE_ERROR_BAD_PARAMETERS;
253
254 sym = params[1].memref.buffer;
255 if (!sym)
256 return TEE_ERROR_BAD_PARAMETERS;
257 maxlen = params[1].memref.size;
258
259 s = ts_pop_current_session();
260 res = ldelf_dlsym(uctx, uuid, sym, maxlen, &va);
261 ts_push_current_session(s);
262
263 if (!res)
264 reg_pair_from_64(va, ¶ms[2].value.a, ¶ms[2].value.b);
265
266 return res;
267 }
268
system_get_tpm_event_log(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])269 static TEE_Result system_get_tpm_event_log(uint32_t param_types,
270 TEE_Param params[TEE_NUM_PARAMS])
271 {
272 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
273 TEE_PARAM_TYPE_NONE,
274 TEE_PARAM_TYPE_NONE,
275 TEE_PARAM_TYPE_NONE);
276 size_t size = 0;
277 TEE_Result res = TEE_SUCCESS;
278
279 if (exp_pt != param_types)
280 return TEE_ERROR_BAD_PARAMETERS;
281
282 size = params[0].memref.size;
283 res = tpm_get_event_log(params[0].memref.buffer, &size);
284 params[0].memref.size = size;
285
286 return res;
287 }
288
system_supp_plugin_invoke(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])289 static TEE_Result system_supp_plugin_invoke(uint32_t param_types,
290 TEE_Param params[TEE_NUM_PARAMS])
291 {
292 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
293 TEE_PARAM_TYPE_VALUE_INPUT,
294 TEE_PARAM_TYPE_MEMREF_INOUT,
295 TEE_PARAM_TYPE_VALUE_OUTPUT);
296 TEE_Result res = TEE_ERROR_GENERIC;
297 size_t outlen = 0;
298
299 if (exp_pt != param_types)
300 return TEE_ERROR_BAD_PARAMETERS;
301
302 res = tee_invoke_supp_plugin_rpc(params[0].memref.buffer, /* uuid */
303 params[1].value.a, /* cmd */
304 params[1].value.b, /* sub_cmd */
305 params[2].memref.buffer, /* data */
306 params[2].memref.size, /* in len */
307 &outlen);
308 params[3].value.a = (uint32_t)outlen;
309
310 return res;
311 }
312
open_session(uint32_t param_types __unused,TEE_Param params[TEE_NUM_PARAMS]__unused,void ** sess_ctx __unused)313 static TEE_Result open_session(uint32_t param_types __unused,
314 TEE_Param params[TEE_NUM_PARAMS] __unused,
315 void **sess_ctx __unused)
316 {
317 struct ts_session *s = NULL;
318
319 /* Check that we're called from a user TA */
320 s = ts_get_calling_session();
321 if (!s)
322 return TEE_ERROR_ACCESS_DENIED;
323 if (!is_user_ta_ctx(s->ctx))
324 return TEE_ERROR_ACCESS_DENIED;
325
326 return TEE_SUCCESS;
327 }
328
invoke_command(void * sess_ctx __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])329 static TEE_Result invoke_command(void *sess_ctx __unused, uint32_t cmd_id,
330 uint32_t param_types,
331 TEE_Param params[TEE_NUM_PARAMS])
332 {
333 struct ts_session *s = ts_get_calling_session();
334 struct user_mode_ctx *uctx = to_user_mode_ctx(s->ctx);
335
336 switch (cmd_id) {
337 case PTA_SYSTEM_ADD_RNG_ENTROPY:
338 return system_rng_reseed(param_types, params);
339 case PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY:
340 return system_derive_ta_unique_key(uctx, param_types, params);
341 case PTA_SYSTEM_MAP_ZI:
342 return system_map_zi(uctx, param_types, params);
343 case PTA_SYSTEM_UNMAP:
344 return system_unmap(uctx, param_types, params);
345 case PTA_SYSTEM_DLOPEN:
346 return system_dlopen(uctx, param_types, params);
347 case PTA_SYSTEM_DLSYM:
348 return system_dlsym(uctx, param_types, params);
349 case PTA_SYSTEM_GET_TPM_EVENT_LOG:
350 return system_get_tpm_event_log(param_types, params);
351 case PTA_SYSTEM_SUPP_PLUGIN_INVOKE:
352 return system_supp_plugin_invoke(param_types, params);
353 default:
354 break;
355 }
356
357 return TEE_ERROR_NOT_IMPLEMENTED;
358 }
359
360 pseudo_ta_register(.uuid = PTA_SYSTEM_UUID, .name = "system.pta",
361 .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
362 .open_session_entry_point = open_session,
363 .invoke_command_entry_point = invoke_command);
364