1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <arpa/inet.h>
6 #include <fcntl.h>
7 #include <string.h>
8 #include <unistd.h>
9
10 #include <zircon/assert.h>
11 #include <zircon/process.h>
12 #include <zircon/syscalls.h>
13
14 #include <fuchsia/hardware/tee/c/fidl.h>
15 #include <lib/fdio/util.h>
16
17 #include <tee-client-api/tee_client_api.h>
18
19 #define DEFAULT_TEE "/dev/class/tee/000"
20
21 #define GET_PARAM_TYPE_FOR_INDEX(param_types, index) \
22 ((param_types >> (4 * index)) & 0xF)
23
is_shared_mem_flag_inout(uint32_t flags)24 static inline bool is_shared_mem_flag_inout(uint32_t flags) {
25 const uint32_t inout_flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
26 return (flags & inout_flags) == inout_flags;
27 }
28
is_direction_input(fuchsia_hardware_tee_Direction direction)29 static inline bool is_direction_input(fuchsia_hardware_tee_Direction direction) {
30 return ((direction == fuchsia_hardware_tee_Direction_INPUT) ||
31 (direction == fuchsia_hardware_tee_Direction_INOUT));
32 }
33
is_direction_output(fuchsia_hardware_tee_Direction direction)34 static inline bool is_direction_output(fuchsia_hardware_tee_Direction direction) {
35 return ((direction == fuchsia_hardware_tee_Direction_OUTPUT) ||
36 (direction == fuchsia_hardware_tee_Direction_INOUT));
37 }
38
is_global_platform_compliant(zx_handle_t tee_channel)39 static bool is_global_platform_compliant(zx_handle_t tee_channel) {
40 fuchsia_hardware_tee_OsInfo os_info;
41 zx_status_t status = fuchsia_hardware_tee_DeviceGetOsInfo(tee_channel, &os_info);
42
43 return status == ZX_OK ? os_info.is_global_platform_compliant : false;
44 }
45
convert_teec_uuid_to_zx_uuid(const TEEC_UUID * teec_uuid,fuchsia_hardware_tee_Uuid * out_uuid)46 static void convert_teec_uuid_to_zx_uuid(const TEEC_UUID* teec_uuid,
47 fuchsia_hardware_tee_Uuid* out_uuid) {
48 ZX_DEBUG_ASSERT(teec_uuid);
49 ZX_DEBUG_ASSERT(out_uuid);
50 out_uuid->time_low = teec_uuid->timeLow;
51 out_uuid->time_mid = teec_uuid->timeMid;
52 out_uuid->time_hi_and_version = teec_uuid->timeHiAndVersion;
53 memcpy(out_uuid->clock_seq_and_node, teec_uuid->clockSeqAndNode,
54 sizeof(out_uuid->clock_seq_and_node));
55 }
56
convert_status_to_result(zx_status_t status)57 static TEEC_Result convert_status_to_result(zx_status_t status) {
58 switch (status) {
59 case ZX_ERR_PEER_CLOSED:
60 return TEEC_ERROR_COMMUNICATION;
61 case ZX_ERR_INVALID_ARGS:
62 return TEEC_ERROR_BAD_PARAMETERS;
63 case ZX_ERR_NOT_SUPPORTED:
64 return TEEC_ERROR_NOT_SUPPORTED;
65 case ZX_ERR_NO_MEMORY:
66 return TEEC_ERROR_OUT_OF_MEMORY;
67 case ZX_OK:
68 return TEEC_SUCCESS;
69 }
70 return TEEC_ERROR_GENERIC;
71 }
72
convert_zx_to_teec_return_origin(fuchsia_hardware_tee_ReturnOrigin return_origin)73 static uint32_t convert_zx_to_teec_return_origin(fuchsia_hardware_tee_ReturnOrigin return_origin) {
74 switch (return_origin) {
75 case fuchsia_hardware_tee_ReturnOrigin_COMMUNICATION:
76 return TEEC_ORIGIN_COMMS;
77 case fuchsia_hardware_tee_ReturnOrigin_TRUSTED_OS:
78 return TEEC_ORIGIN_TEE;
79 case fuchsia_hardware_tee_ReturnOrigin_TRUSTED_APPLICATION:
80 return TEEC_ORIGIN_TRUSTED_APP;
81 default:
82 return TEEC_ORIGIN_API;
83 }
84 }
85
close_all_vmos(const fuchsia_hardware_tee_ParameterSet * parameter_set)86 static void close_all_vmos(const fuchsia_hardware_tee_ParameterSet* parameter_set) {
87 ZX_DEBUG_ASSERT(parameter_set);
88
89 for (size_t i = 0; i < parameter_set->count; i++) {
90 const fuchsia_hardware_tee_Parameter* param = ¶meter_set->parameters[i];
91 if (param->tag == fuchsia_hardware_tee_ParameterTag_buffer) {
92 zx_handle_close(param->buffer.vmo);
93 }
94 }
95 }
96
preprocess_value(uint32_t param_type,const TEEC_Value * teec_value,fuchsia_hardware_tee_Parameter * out_zx_param)97 static void preprocess_value(uint32_t param_type, const TEEC_Value* teec_value,
98 fuchsia_hardware_tee_Parameter* out_zx_param) {
99 ZX_DEBUG_ASSERT(teec_value);
100 ZX_DEBUG_ASSERT(out_zx_param);
101
102 fuchsia_hardware_tee_Direction direction = 0;
103 switch (param_type) {
104 case TEEC_VALUE_INPUT:
105 direction = fuchsia_hardware_tee_Direction_INPUT;
106 break;
107 case TEEC_VALUE_OUTPUT:
108 direction = fuchsia_hardware_tee_Direction_OUTPUT;
109 break;
110 case TEEC_VALUE_INOUT:
111 direction = fuchsia_hardware_tee_Direction_INOUT;
112 break;
113 default:
114 ZX_PANIC("Unknown param type");
115 }
116
117 out_zx_param->tag = fuchsia_hardware_tee_ParameterTag_value;
118 out_zx_param->value.direction = direction;
119 if (is_direction_input(direction)) {
120 // The TEEC_Value type only includes two generic fields, whereas the Fuchsia TEE interface
121 // supports three. The c field cannot be used by the TEE Client API.
122 out_zx_param->value.a = teec_value->a;
123 out_zx_param->value.b = teec_value->b;
124 out_zx_param->value.c = 0;
125 }
126 }
127
preprocess_temporary_memref(uint32_t param_type,const TEEC_TempMemoryReference * temp_memory_ref,fuchsia_hardware_tee_Parameter * out_zx_param)128 static TEEC_Result preprocess_temporary_memref(uint32_t param_type,
129 const TEEC_TempMemoryReference* temp_memory_ref,
130 fuchsia_hardware_tee_Parameter* out_zx_param) {
131 ZX_DEBUG_ASSERT(temp_memory_ref);
132 ZX_DEBUG_ASSERT(out_zx_param);
133
134 fuchsia_hardware_tee_Direction direction;
135 switch (param_type) {
136 case TEEC_MEMREF_TEMP_INPUT:
137 direction = fuchsia_hardware_tee_Direction_INPUT;
138 break;
139 case TEEC_MEMREF_TEMP_OUTPUT:
140 direction = fuchsia_hardware_tee_Direction_OUTPUT;
141 break;
142 case TEEC_MEMREF_TEMP_INOUT:
143 direction = fuchsia_hardware_tee_Direction_INOUT;
144 break;
145 default:
146 ZX_PANIC("TEE Client API Unknown parameter type\n");
147 }
148
149 zx_handle_t vmo;
150
151 if (!temp_memory_ref->buffer) {
152 // A null buffer marked as output is a valid request to determine the necessary size of the
153 // output buffer. It is an error for any sort of input.
154 if (is_direction_input(direction)) {
155 return TEEC_ERROR_BAD_PARAMETERS;
156 }
157 vmo = ZX_HANDLE_INVALID;
158 } else {
159 // We either have data to input or have a buffer to output data to, so create a VMO for it.
160 zx_status_t status = zx_vmo_create(temp_memory_ref->size, 0, &vmo);
161 if (status != ZX_OK) {
162 return convert_status_to_result(status);
163 }
164
165 // If the memory reference is used as an input, then we must copy the data from the user
166 // provided buffer into the VMO. There is no need to do this for parameters that are output
167 // only.
168 if (is_direction_input(direction)) {
169 status = zx_vmo_write(vmo, temp_memory_ref->buffer, 0, temp_memory_ref->size);
170 if (status != ZX_OK) {
171 zx_handle_close(vmo);
172 return convert_status_to_result(status);
173 }
174 }
175 }
176
177 out_zx_param->tag = fuchsia_hardware_tee_ParameterTag_buffer;
178 out_zx_param->buffer.direction = direction;
179 out_zx_param->buffer.vmo = vmo;
180 out_zx_param->buffer.offset = 0;
181 out_zx_param->buffer.size = temp_memory_ref->size;
182 return TEEC_SUCCESS;
183 }
184
preprocess_whole_memref(const TEEC_RegisteredMemoryReference * memory_ref,fuchsia_hardware_tee_Parameter * out_zx_param)185 static TEEC_Result preprocess_whole_memref(const TEEC_RegisteredMemoryReference* memory_ref,
186 fuchsia_hardware_tee_Parameter* out_zx_param) {
187 ZX_DEBUG_ASSERT(memory_ref);
188 ZX_DEBUG_ASSERT(out_zx_param);
189
190 if (!memory_ref->parent) {
191 return TEEC_ERROR_BAD_PARAMETERS;
192 }
193
194 TEEC_SharedMemory* shared_mem = memory_ref->parent;
195 fuchsia_hardware_tee_Direction direction;
196 if (is_shared_mem_flag_inout(shared_mem->flags)) {
197 direction = fuchsia_hardware_tee_Direction_INOUT;
198 } else if (shared_mem->flags & TEEC_MEM_INPUT) {
199 direction = fuchsia_hardware_tee_Direction_INPUT;
200 } else if (shared_mem->flags & TEEC_MEM_OUTPUT) {
201 direction = fuchsia_hardware_tee_Direction_OUTPUT;
202 } else {
203 return TEEC_ERROR_BAD_PARAMETERS;
204 }
205
206 zx_handle_t vmo;
207 zx_status_t status = zx_handle_duplicate(shared_mem->imp.vmo, ZX_RIGHT_SAME_RIGHTS, &vmo);
208 if (status != ZX_OK) {
209 return convert_status_to_result(status);
210 }
211
212 out_zx_param->tag = fuchsia_hardware_tee_ParameterTag_buffer;
213 out_zx_param->buffer.direction = direction;
214 out_zx_param->buffer.vmo = vmo;
215 out_zx_param->buffer.offset = 0;
216 out_zx_param->buffer.size = shared_mem->size;
217
218 return TEEC_SUCCESS;
219 }
220
preprocess_partial_memref(uint32_t param_type,const TEEC_RegisteredMemoryReference * memory_ref,fuchsia_hardware_tee_Parameter * out_zx_param)221 static TEEC_Result preprocess_partial_memref(uint32_t param_type,
222 const TEEC_RegisteredMemoryReference* memory_ref,
223 fuchsia_hardware_tee_Parameter* out_zx_param) {
224 ZX_DEBUG_ASSERT(memory_ref);
225 ZX_DEBUG_ASSERT(out_zx_param);
226
227 if (!memory_ref->parent) {
228 return TEEC_ERROR_BAD_PARAMETERS;
229 }
230
231 uint32_t expected_shm_flags = 0;
232 fuchsia_hardware_tee_Direction direction = 0;
233 switch (param_type) {
234 case TEEC_MEMREF_PARTIAL_INPUT:
235 expected_shm_flags = TEEC_MEM_INPUT;
236 direction = fuchsia_hardware_tee_Direction_INPUT;
237 break;
238 case TEEC_MEMREF_PARTIAL_OUTPUT:
239 expected_shm_flags = TEEC_MEM_OUTPUT;
240 direction = fuchsia_hardware_tee_Direction_OUTPUT;
241 break;
242 case TEEC_MEMREF_PARTIAL_INOUT:
243 expected_shm_flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
244 direction = fuchsia_hardware_tee_Direction_INOUT;
245 break;
246 default:
247 ZX_DEBUG_ASSERT(param_type == TEEC_MEMREF_PARTIAL_INPUT ||
248 param_type == TEEC_MEMREF_PARTIAL_OUTPUT ||
249 param_type == TEEC_MEMREF_PARTIAL_INOUT);
250 }
251
252 TEEC_SharedMemory* shared_mem = memory_ref->parent;
253
254 if ((shared_mem->flags & expected_shm_flags) != expected_shm_flags) {
255 return TEEC_ERROR_BAD_PARAMETERS;
256 }
257
258 zx_handle_t vmo;
259 zx_status_t status = zx_handle_duplicate(shared_mem->imp.vmo, ZX_RIGHT_SAME_RIGHTS, &vmo);
260 if (status != ZX_OK) {
261 return convert_status_to_result(status);
262 }
263
264 out_zx_param->tag = fuchsia_hardware_tee_ParameterTag_buffer;
265 out_zx_param->buffer.direction = direction;
266 out_zx_param->buffer.vmo = vmo;
267 out_zx_param->buffer.offset = memory_ref->offset;
268 out_zx_param->buffer.size = memory_ref->size;
269
270 return TEEC_SUCCESS;
271 }
272
preprocess_operation(const TEEC_Operation * operation,fuchsia_hardware_tee_ParameterSet * out_parameter_set)273 static TEEC_Result preprocess_operation(const TEEC_Operation* operation,
274 fuchsia_hardware_tee_ParameterSet* out_parameter_set) {
275 if (!operation) {
276 return TEEC_SUCCESS;
277 }
278
279 TEEC_Result rc = TEEC_SUCCESS;
280 for (size_t i = 0; i < TEEC_NUM_PARAMS_MAX; i++) {
281 uint32_t param_type = GET_PARAM_TYPE_FOR_INDEX(operation->paramTypes, i);
282
283 switch (param_type) {
284 case TEEC_NONE:
285 out_parameter_set->parameters[i].tag = fuchsia_hardware_tee_ParameterTag_none;
286 break;
287 case TEEC_VALUE_INPUT:
288 case TEEC_VALUE_OUTPUT:
289 case TEEC_VALUE_INOUT:
290 preprocess_value(param_type, &operation->params[i].value,
291 &out_parameter_set->parameters[i]);
292 break;
293 case TEEC_MEMREF_TEMP_INPUT:
294 case TEEC_MEMREF_TEMP_OUTPUT:
295 case TEEC_MEMREF_TEMP_INOUT:
296 rc = preprocess_temporary_memref(param_type, &operation->params[i].tmpref,
297 &out_parameter_set->parameters[i]);
298 break;
299 case TEEC_MEMREF_WHOLE:
300 rc = preprocess_whole_memref(&operation->params[i].memref,
301 &out_parameter_set->parameters[i]);
302 break;
303 case TEEC_MEMREF_PARTIAL_INPUT:
304 case TEEC_MEMREF_PARTIAL_OUTPUT:
305 case TEEC_MEMREF_PARTIAL_INOUT:
306 rc = preprocess_partial_memref(param_type, &operation->params[i].memref,
307 &out_parameter_set->parameters[i]);
308 break;
309 default:
310 rc = TEEC_ERROR_BAD_PARAMETERS;
311 break;
312 }
313
314 if (rc != TEEC_SUCCESS) {
315 // Close out any VMOs we already opened for the parameters we did parse
316 close_all_vmos(out_parameter_set);
317 return rc;
318 }
319 }
320
321 out_parameter_set->count = TEEC_NUM_PARAMS_MAX;
322
323 return rc;
324 }
325
postprocess_value(uint32_t param_type,const fuchsia_hardware_tee_Parameter * zx_param,TEEC_Value * out_teec_value)326 static TEEC_Result postprocess_value(uint32_t param_type,
327 const fuchsia_hardware_tee_Parameter* zx_param,
328 TEEC_Value* out_teec_value) {
329 ZX_DEBUG_ASSERT(zx_param);
330 ZX_DEBUG_ASSERT(out_teec_value);
331 ZX_DEBUG_ASSERT(param_type == TEEC_VALUE_INPUT ||
332 param_type == TEEC_VALUE_OUTPUT ||
333 param_type == TEEC_VALUE_INOUT);
334
335 if (zx_param->tag != fuchsia_hardware_tee_ParameterTag_value) {
336 return TEEC_ERROR_BAD_PARAMETERS;
337 }
338
339 const fuchsia_hardware_tee_Value* zx_value = &zx_param->value;
340
341 // Validate that the direction of the returned parameter matches the expected.
342 if ((param_type == TEEC_VALUE_INPUT) &&
343 (zx_value->direction != fuchsia_hardware_tee_Direction_INPUT)) {
344 return TEEC_ERROR_BAD_PARAMETERS;
345 }
346 if ((param_type == TEEC_VALUE_OUTPUT) &&
347 (zx_value->direction != fuchsia_hardware_tee_Direction_OUTPUT)) {
348 return TEEC_ERROR_BAD_PARAMETERS;
349 }
350 if ((param_type == TEEC_VALUE_INOUT) &&
351 (zx_value->direction != fuchsia_hardware_tee_Direction_INOUT)) {
352 return TEEC_ERROR_BAD_PARAMETERS;
353 }
354
355 // The TEEC_Value type only includes two generic fields, whereas the Fuchsia TEE interface
356 // supports three. The c field cannot be used by the TEE Client API.
357 out_teec_value->a = zx_value->a;
358 out_teec_value->b = zx_value->b;
359 return TEEC_SUCCESS;
360 }
361
postprocess_temporary_memref(uint32_t param_type,const fuchsia_hardware_tee_Parameter * zx_param,TEEC_TempMemoryReference * out_temp_memory_ref)362 static TEEC_Result postprocess_temporary_memref(uint32_t param_type,
363 const fuchsia_hardware_tee_Parameter* zx_param,
364 TEEC_TempMemoryReference* out_temp_memory_ref) {
365 ZX_DEBUG_ASSERT(zx_param);
366 ZX_DEBUG_ASSERT(out_temp_memory_ref);
367 ZX_DEBUG_ASSERT(param_type == TEEC_MEMREF_TEMP_INPUT ||
368 param_type == TEEC_MEMREF_TEMP_OUTPUT ||
369 param_type == TEEC_MEMREF_TEMP_INOUT);
370
371 if (zx_param->tag != fuchsia_hardware_tee_ParameterTag_buffer) {
372 return TEEC_ERROR_BAD_PARAMETERS;
373 }
374
375 const fuchsia_hardware_tee_Buffer* zx_buffer = &zx_param->buffer;
376
377 if ((param_type == TEEC_MEMREF_TEMP_INPUT) &&
378 (zx_buffer->direction != fuchsia_hardware_tee_Direction_INPUT)) {
379 return TEEC_ERROR_BAD_PARAMETERS;
380 }
381 if ((param_type == TEEC_MEMREF_TEMP_OUTPUT) &&
382 (zx_buffer->direction != fuchsia_hardware_tee_Direction_OUTPUT)) {
383 return TEEC_ERROR_BAD_PARAMETERS;
384 }
385 if ((param_type == TEEC_MEMREF_TEMP_INOUT) &&
386 (zx_buffer->direction != fuchsia_hardware_tee_Direction_INOUT)) {
387 return TEEC_ERROR_BAD_PARAMETERS;
388 }
389
390 TEEC_Result rc = TEEC_SUCCESS;
391 if (is_direction_output(zx_buffer->direction)) {
392 // For output buffers, if we don't have enough space in the temporary memory reference to
393 // copy the data out, we still need to update the size to indicate to the user how large of
394 // a buffer they need to perform the requested operation.
395 if (out_temp_memory_ref->buffer && out_temp_memory_ref->size >= zx_buffer->size) {
396 zx_status_t status = zx_vmo_read(zx_buffer->vmo,
397 out_temp_memory_ref->buffer,
398 zx_buffer->offset,
399 zx_buffer->size);
400 rc = convert_status_to_result(status);
401 }
402 out_temp_memory_ref->size = zx_buffer->size;
403 }
404
405 return rc;
406 }
407
postprocess_whole_memref(const fuchsia_hardware_tee_Parameter * zx_param,TEEC_RegisteredMemoryReference * out_memory_ref)408 static TEEC_Result postprocess_whole_memref(const fuchsia_hardware_tee_Parameter* zx_param,
409 TEEC_RegisteredMemoryReference* out_memory_ref) {
410 ZX_DEBUG_ASSERT(zx_param);
411 ZX_DEBUG_ASSERT(out_memory_ref);
412 ZX_DEBUG_ASSERT(out_memory_ref->parent);
413
414 if (zx_param->tag != fuchsia_hardware_tee_ParameterTag_buffer) {
415 return TEEC_ERROR_BAD_PARAMETERS;
416 }
417
418 const fuchsia_hardware_tee_Buffer* zx_buffer = &zx_param->buffer;
419
420 if (is_direction_output(zx_buffer->direction)) {
421 out_memory_ref->size = zx_buffer->size;
422 }
423
424 return TEEC_SUCCESS;
425 }
426
postprocess_partial_memref(uint32_t param_type,const fuchsia_hardware_tee_Parameter * zx_param,TEEC_RegisteredMemoryReference * out_memory_ref)427 static TEEC_Result postprocess_partial_memref(uint32_t param_type,
428 const fuchsia_hardware_tee_Parameter* zx_param,
429 TEEC_RegisteredMemoryReference* out_memory_ref) {
430 ZX_DEBUG_ASSERT(zx_param);
431 ZX_DEBUG_ASSERT(out_memory_ref);
432 ZX_DEBUG_ASSERT(param_type == TEEC_MEMREF_PARTIAL_INPUT ||
433 param_type == TEEC_MEMREF_PARTIAL_OUTPUT ||
434 param_type == TEEC_MEMREF_PARTIAL_INOUT);
435
436 if (zx_param->tag != fuchsia_hardware_tee_ParameterTag_buffer) {
437 return TEEC_ERROR_BAD_PARAMETERS;
438 }
439
440 const fuchsia_hardware_tee_Buffer* zx_buffer = &zx_param->buffer;
441
442 if ((param_type == TEEC_MEMREF_PARTIAL_INPUT) &&
443 (zx_buffer->direction != fuchsia_hardware_tee_Direction_INPUT)) {
444 return TEEC_ERROR_BAD_PARAMETERS;
445 }
446 if ((param_type == TEEC_MEMREF_PARTIAL_OUTPUT) &&
447 (zx_buffer->direction != fuchsia_hardware_tee_Direction_OUTPUT)) {
448 return TEEC_ERROR_BAD_PARAMETERS;
449 }
450 if ((param_type == TEEC_MEMREF_PARTIAL_INOUT) &&
451 (zx_buffer->direction != fuchsia_hardware_tee_Direction_INOUT)) {
452 return TEEC_ERROR_BAD_PARAMETERS;
453 }
454
455 if (is_direction_output(zx_buffer->direction)) {
456 out_memory_ref->size = zx_buffer->size;
457 }
458
459 return TEEC_SUCCESS;
460 }
461
postprocess_operation(const fuchsia_hardware_tee_ParameterSet * parameter_set,TEEC_Operation * out_operation)462 static TEEC_Result postprocess_operation(const fuchsia_hardware_tee_ParameterSet* parameter_set,
463 TEEC_Operation* out_operation) {
464
465 if (!out_operation) {
466 return TEEC_SUCCESS;
467 }
468
469 TEEC_Result rc = TEEC_SUCCESS;
470 for (size_t i = 0; i < TEEC_NUM_PARAMS_MAX; i++) {
471 uint32_t param_type = GET_PARAM_TYPE_FOR_INDEX(out_operation->paramTypes, i);
472
473 // This check catches the case where we did not receive all the parameters back that we
474 // expected. Once in_param_index hits the parameter_set count, we've parsed all the
475 // parameters that came back.
476 if (i >= parameter_set->count) {
477 rc = TEEC_ERROR_BAD_PARAMETERS;
478 break;
479 }
480
481 switch (param_type) {
482 case TEEC_NONE:
483 if (parameter_set->parameters[i].tag != fuchsia_hardware_tee_ParameterTag_none) {
484 rc = TEEC_ERROR_BAD_PARAMETERS;
485 }
486 break;
487 case TEEC_VALUE_INPUT:
488 case TEEC_VALUE_OUTPUT:
489 case TEEC_VALUE_INOUT:
490 rc = postprocess_value(param_type, ¶meter_set->parameters[i],
491 &out_operation->params[i].value);
492 break;
493 case TEEC_MEMREF_TEMP_INPUT:
494 case TEEC_MEMREF_TEMP_OUTPUT:
495 case TEEC_MEMREF_TEMP_INOUT:
496 rc = postprocess_temporary_memref(param_type, ¶meter_set->parameters[i],
497 &out_operation->params[i].tmpref);
498 break;
499 case TEEC_MEMREF_WHOLE:
500 rc = postprocess_whole_memref(¶meter_set->parameters[i],
501 &out_operation->params[i].memref);
502 break;
503 case TEEC_MEMREF_PARTIAL_INPUT:
504 case TEEC_MEMREF_PARTIAL_OUTPUT:
505 case TEEC_MEMREF_PARTIAL_INOUT:
506 rc = postprocess_partial_memref(param_type, ¶meter_set->parameters[i],
507 &out_operation->params[i].memref);
508 break;
509 default:
510 rc = TEEC_ERROR_BAD_PARAMETERS;
511 }
512
513 if (rc != TEEC_SUCCESS) {
514 break;
515 }
516 }
517
518 close_all_vmos(parameter_set);
519
520 return rc;
521 }
522
TEEC_InitializeContext(const char * name,TEEC_Context * context)523 TEEC_Result TEEC_InitializeContext(const char* name, TEEC_Context* context) {
524
525 if (!context) {
526 return TEEC_ERROR_BAD_PARAMETERS;
527 }
528
529 const char* tee_device = (name != NULL) ? name : DEFAULT_TEE;
530
531 int fd = open(tee_device, O_RDWR);
532 if (fd < 0) {
533 return TEEC_ERROR_ITEM_NOT_FOUND;
534 }
535
536 zx_handle_t tee_channel;
537 zx_status_t status = fdio_get_service_handle(fd, &tee_channel);
538 // Irregardless of the success or failure of fdio_get_service_handle, the original file
539 // descriptor is effectively closed.
540 if (status != ZX_OK) {
541 return TEEC_ERROR_COMMUNICATION;
542 }
543
544 if (!is_global_platform_compliant(tee_channel)) {
545 // This API is only designed to support TEEs that are Global Platform compliant.
546 zx_handle_close(tee_channel);
547 return TEEC_ERROR_NOT_SUPPORTED;
548 }
549 context->imp.tee_channel = tee_channel;
550
551 return TEEC_SUCCESS;
552 }
553
TEEC_FinalizeContext(TEEC_Context * context)554 void TEEC_FinalizeContext(TEEC_Context* context) {
555 if (context) {
556 zx_handle_close(context->imp.tee_channel);
557 }
558 }
559
TEEC_RegisterSharedMemory(TEEC_Context * context,TEEC_SharedMemory * sharedMem)560 TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context* context, TEEC_SharedMemory* sharedMem) {
561 /* This function is supposed to register an existing buffer for use as shared memory. We don't
562 * have a way of discovering the VMO handle for an arbitrary address, so implementing this would
563 * require an extra VMO that would be copied into at invocation. Since we currently don't have
564 * any use cases for this function and TEEC_AllocateSharedMemory should be the preferred method
565 * of acquiring shared memory, we're going to leave this unimplemented for now. */
566 return TEEC_ERROR_NOT_IMPLEMENTED;
567 }
568
TEEC_AllocateSharedMemory(TEEC_Context * context,TEEC_SharedMemory * sharedMem)569 TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context* context, TEEC_SharedMemory* sharedMem) {
570 if (!context || !sharedMem) {
571 return TEEC_ERROR_BAD_PARAMETERS;
572 }
573
574 if (sharedMem->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)) {
575 return TEEC_ERROR_BAD_PARAMETERS;
576 }
577
578 memset(&sharedMem->imp, 0, sizeof(sharedMem->imp));
579
580 size_t size = sharedMem->size;
581
582 zx_handle_t vmo = ZX_HANDLE_INVALID;
583 zx_status_t status = zx_vmo_create(size, ZX_VMO_NON_RESIZABLE, &vmo);
584 if (status != ZX_OK) {
585 return convert_status_to_result(status);
586 }
587
588 zx_vaddr_t mapped_addr;
589 status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size,
590 &mapped_addr);
591 if (status != ZX_OK) {
592 zx_handle_close(vmo);
593 return convert_status_to_result(status);
594 }
595
596 sharedMem->buffer = (void*)mapped_addr;
597 sharedMem->imp.vmo = vmo;
598 sharedMem->imp.mapped_addr = mapped_addr;
599 sharedMem->imp.mapped_size = size;
600
601 return TEEC_SUCCESS;
602 }
603
TEEC_ReleaseSharedMemory(TEEC_SharedMemory * sharedMem)604 void TEEC_ReleaseSharedMemory(TEEC_SharedMemory* sharedMem) {
605 if (!sharedMem) {
606 return;
607 }
608 zx_vmar_unmap(zx_vmar_root_self(), sharedMem->imp.mapped_addr, sharedMem->imp.mapped_size);
609 zx_handle_close(sharedMem->imp.vmo);
610 }
611
TEEC_OpenSession(TEEC_Context * context,TEEC_Session * session,const TEEC_UUID * destination,uint32_t connectionMethod,const void * connectionData,TEEC_Operation * operation,uint32_t * returnOrigin)612 TEEC_Result TEEC_OpenSession(TEEC_Context* context,
613 TEEC_Session* session,
614 const TEEC_UUID* destination,
615 uint32_t connectionMethod,
616 const void* connectionData,
617 TEEC_Operation* operation,
618 uint32_t* returnOrigin) {
619 if (!context || !session || !destination) {
620 if (returnOrigin) {
621 *returnOrigin = TEEC_ORIGIN_API;
622 }
623 return TEEC_ERROR_BAD_PARAMETERS;
624 }
625
626 if (connectionMethod != TEEC_LOGIN_PUBLIC) {
627 // TODO(rjascani): Investigate whether non public login is needed.
628 if (returnOrigin) {
629 *returnOrigin = TEEC_ORIGIN_API;
630 }
631 return TEEC_ERROR_NOT_IMPLEMENTED;
632 }
633
634 fuchsia_hardware_tee_Uuid trusted_app;
635 convert_teec_uuid_to_zx_uuid(destination, &trusted_app);
636
637 fuchsia_hardware_tee_ParameterSet parameter_set;
638 memset(¶meter_set, 0, sizeof(parameter_set));
639
640 uint32_t teec_rc = preprocess_operation(operation, ¶meter_set);
641 if (teec_rc != TEEC_SUCCESS) {
642 if (returnOrigin) {
643 *returnOrigin = TEEC_ORIGIN_COMMS;
644 }
645 return teec_rc;
646 }
647
648 // Outputs
649 uint32_t out_session_id;
650 fuchsia_hardware_tee_Result out_result;
651 memset(&out_result, 0, sizeof(out_result));
652
653 zx_status_t status = fuchsia_hardware_tee_DeviceOpenSession(
654 context->imp.tee_channel, &trusted_app, ¶meter_set, &out_session_id, &out_result);
655
656 if (status != ZX_OK) {
657 if (returnOrigin) {
658 *returnOrigin = TEEC_ORIGIN_COMMS;
659 }
660 return convert_status_to_result(status);
661 }
662
663 teec_rc = postprocess_operation(&out_result.parameter_set, operation);
664 if (teec_rc != TEEC_SUCCESS) {
665 if (returnOrigin) {
666 *returnOrigin = TEEC_ORIGIN_COMMS;
667 }
668 return teec_rc;
669 }
670
671 if (out_result.return_code == TEEC_SUCCESS) {
672 session->imp.session_id = out_session_id;
673 session->imp.context_imp = &context->imp;
674 }
675
676 if (returnOrigin) {
677 *returnOrigin = convert_zx_to_teec_return_origin(out_result.return_origin);
678 }
679
680 return out_result.return_code;
681 }
682
TEEC_CloseSession(TEEC_Session * session)683 void TEEC_CloseSession(TEEC_Session* session) {
684 if (!session || !session->imp.context_imp) {
685 return;
686 }
687
688 // TEEC_CloseSession simply swallows errors, so no need to check here.
689 fuchsia_hardware_tee_DeviceCloseSession(session->imp.context_imp->tee_channel,
690 session->imp.session_id);
691 session->imp.context_imp = NULL;
692 }
693
TEEC_InvokeCommand(TEEC_Session * session,uint32_t commandID,TEEC_Operation * operation,uint32_t * returnOrigin)694 TEEC_Result TEEC_InvokeCommand(TEEC_Session* session,
695 uint32_t commandID,
696 TEEC_Operation* operation,
697 uint32_t* returnOrigin) {
698 if (!session || !session->imp.context_imp) {
699 if (returnOrigin) {
700 *returnOrigin = TEEC_ORIGIN_API;
701 }
702 return TEEC_ERROR_BAD_PARAMETERS;
703 }
704
705 fuchsia_hardware_tee_ParameterSet parameter_set;
706 memset(¶meter_set, 0, sizeof(parameter_set));
707
708 fuchsia_hardware_tee_Result out_result;
709 memset(&out_result, 0, sizeof(out_result));
710
711 uint32_t teec_rc = preprocess_operation(operation, ¶meter_set);
712 if (teec_rc != TEEC_SUCCESS) {
713 if (returnOrigin) {
714 *returnOrigin = TEEC_ORIGIN_COMMS;
715 }
716 return teec_rc;
717 }
718
719 zx_status_t status = fuchsia_hardware_tee_DeviceInvokeCommand(
720 session->imp.context_imp->tee_channel, session->imp.session_id, commandID, ¶meter_set,
721 &out_result);
722
723 if (status != ZX_OK) {
724 if (returnOrigin) {
725 *returnOrigin = TEEC_ORIGIN_COMMS;
726 }
727 return convert_status_to_result(status);
728 }
729
730 teec_rc = postprocess_operation(&out_result.parameter_set, operation);
731
732 if (teec_rc != TEEC_SUCCESS) {
733 if (returnOrigin) {
734 *returnOrigin = TEEC_ORIGIN_COMMS;
735 }
736 return teec_rc;
737 }
738
739 if (returnOrigin) {
740 *returnOrigin = convert_zx_to_teec_return_origin(out_result.return_origin);
741 }
742
743 return out_result.return_code;
744 }
745
TEEC_RequestCancellation(TEEC_Operation * operation)746 void TEEC_RequestCancellation(TEEC_Operation* operation) {}
747