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 = &parameter_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, &parameter_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, &parameter_set->parameters[i],
497                                               &out_operation->params[i].tmpref);
498             break;
499         case TEEC_MEMREF_WHOLE:
500             rc = postprocess_whole_memref(&parameter_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, &parameter_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(&parameter_set, 0, sizeof(parameter_set));
639 
640     uint32_t teec_rc = preprocess_operation(operation, &parameter_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, &parameter_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(&parameter_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, &parameter_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, &parameter_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