From cf363b9f6ba59b61132c5e47ce987604b9208283 Mon Sep 17 00:00:00 2001 From: Hernan Gatta Date: Fri, 8 May 2020 23:58:25 -0700 Subject: [PATCH] xtest: regression 1100: add OCALL tests Add 10 tests that check the behaviour of the OCALL functionality. The tests in question are detailed below: OCALL without parameters: ------------------------- Performs an OCALL without any parameters. OCALL with value parameters (in/inout/out/in): ---------------------------------------------- Performs an OCALL with value parameters and in parameter directions, verifying that the values are transferred correctly between normal world and secure world. OCALL with memref parameters (in/inout/out/in): ----------------------------------------------- Performs an OCALL with memref parameters and in parameter directions, verifying that the bufers are transferred correctly between normal world and secure world. Close session during OCALL: --------------------------- Performs an OCALL that closes the session through which the original function invocation was performed. Ascertains that the OCALL is cancelled and that the session is closed. Finalize context during OCALL: ------------------------------ Performs an OCALL that finalizes the context through which the original function invocation was performed. Ascertains that the OCALL is cancelled and that the session that was originally used to perform the function invocation is closed as a result of the context being finalized. NULL memref param: ------------------ Verifies that OCALLs can carry memref parameters with NULL buffers in all directions. NULL memref param (mixed params): --------------------------------- Verifies that OCALLs can carry memref parameters with NULL buffers alongside value and non-NULL memref parameters in various directions. NULL memref param (invalid params): ----------------------------------- Verifies that attempting to perform an OCALL with memref parameters with a NULL buffer and a non-zero size and with a non-NULL buffer and a zero size fails at the Internal Core API layer. OCALL during session open: -------------------------- Ascertains that the CA can receive an OCALL during session open. Finalize context during session open OCALL: ------------------------------------------- Performs an OCALL during session open that finalizes the context via which the session was being opened, verifies that the OCALL is cancelled, and that the session fails to open. Signed-off-by: Hernan Gatta --- Android.mk | 3 +- host/xtest/CMakeLists.txt | 4 + host/xtest/Makefile | 5 + host/xtest/regression_1100.c | 481 ++++++++++++++++++++++ host/xtest/xtest_test.c | 5 + host/xtest/xtest_test.h | 2 + ta/CMakeLists.txt | 1 + ta/Makefile | 4 + ta/ocall/Android.mk | 4 + ta/ocall/Makefile | 2 + ta/ocall/include/ta_ocall.h | 26 ++ ta/ocall/include/ta_ocall_data.h | 60 +++ ta/ocall/include/ta_ocall_test.h | 50 +++ ta/ocall/include/user_ta_header_defines.h | 21 + ta/ocall/sub.mk | 3 + ta/ocall/ta_entry.c | 137 ++++++ ta/ocall/ta_ocall.c | 402 ++++++++++++++++++ 17 files changed, 1209 insertions(+), 1 deletion(-) create mode 100644 host/xtest/regression_1100.c create mode 100644 ta/ocall/Android.mk create mode 100644 ta/ocall/Makefile create mode 100644 ta/ocall/include/ta_ocall.h create mode 100644 ta/ocall/include/ta_ocall_data.h create mode 100644 ta/ocall/include/ta_ocall_test.h create mode 100644 ta/ocall/include/user_ta_header_defines.h create mode 100644 ta/ocall/sub.mk create mode 100644 ta/ocall/ta_entry.c create mode 100644 ta/ocall/ta_ocall.c diff --git a/Android.mk b/Android.mk index 1a7c8f5bf..cb92ca4ab 100644 --- a/Android.mk +++ b/Android.mk @@ -103,7 +103,8 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/host/xtest \ $(LOCAL_PATH)/ta/aes_perf/include \ $(LOCAL_PATH)/ta/socket/include \ $(LOCAL_PATH)/ta/sdp_basic/include \ - $(LOCAL_PATH)/ta/tpm_log_test/include + $(LOCAL_PATH)/ta/tpm_log_test/include \ + $(LOCAL_PATH)/ta/ocall/include # Include configuration file generated by OP-TEE OS (CFG_* macros) LOCAL_CFLAGS += -I $(TA_DEV_KIT_DIR)/host_include -include conf.h diff --git a/host/xtest/CMakeLists.txt b/host/xtest/CMakeLists.txt index 290beacbb..d6f3a2bf3 100644 --- a/host/xtest/CMakeLists.txt +++ b/host/xtest/CMakeLists.txt @@ -110,6 +110,10 @@ if (CFG_PKCS11_TA) list (APPEND SRC pkcs11_1000.c) endif() +if (CFG_OCALL) + list (APPEND SRC regression_1100.c) +endif() + ################################################################################ # Built binary ################################################################################ diff --git a/host/xtest/Makefile b/host/xtest/Makefile index 0b0a4d4b9..74ebe8a28 100644 --- a/host/xtest/Makefile +++ b/host/xtest/Makefile @@ -110,6 +110,10 @@ srcs += gp_7000.c \ gp_9000.c endif +ifeq ($(CFG_OCALL),y) +srcs += regression_1100.c +endif + objs := $(patsubst %.c,$(out-dir)/xtest/%.o, $(srcs)) CFLAGS += -I./ @@ -136,6 +140,7 @@ CFLAGS += -I../../ta/aes_perf/include CFLAGS += -I../../ta/socket/include CFLAGS += -I../../ta/sdp_basic/include CFLAGS += -I../../ta/tpm_log_test/include +CFLAGS += -I../../ta/ocall/include ifdef CFG_GP_PACKAGE_PATH CFLAGS += -I../../ta/GP_TTA_Arithmetical diff --git a/host/xtest/regression_1100.c b/host/xtest/regression_1100.c new file mode 100644 index 000000000..894d294d4 --- /dev/null +++ b/host/xtest/regression_1100.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020, Microsoft Corporation + */ + +#include +#include +#include +#include +#include + +#include "xtest_helpers.h" +#include "xtest_test.h" + +static ADBG_Case_t *local_c; + +static bool no_ecall_params_no_ocall_params_reply; +static bool no_ecall_params_ocall_value_params_reply; +static bool no_ecall_params_ocall_memref_params_reply; +static bool null_memref_params_reply; +static bool null_memref_params_mixed_reply; +static bool null_memref_params_invalid_reply; +static bool session_open_ocall_reply; +static bool session_open_ocall_premature_ctx_finalize_reply; + +static TEEC_Result +ocall_handler(TEEC_UUID *taUUID, uint32_t commandId, uint32_t paramTypes, + TEEC_Parameter params[TEEC_CONFIG_PAYLOAD_REF_COUNT], + void *ctx_data, void *session_data) +{ + uint32_t exp_pt; + + ADBG_EXPECT_EQUAL(local_c, &ocall_ta_uuid, taUUID, + sizeof(*taUUID)); + + switch (commandId) { + case CA_OCALL_CMD_NO_ECALL_PARAMS_NO_OCALL_PARAMS: + no_ecall_params_no_ocall_params_reply = true; + + exp_pt = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, + TEEC_NONE); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + break; + + case CA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_VALUE_PARAMS: + no_ecall_params_ocall_value_params_reply = true; + + exp_pt = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INOUT, + TEEC_VALUE_OUTPUT, TEEC_VALUE_INPUT); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + + ADBG_EXPECT_COMPARE_UNSIGNED(local_c, + params[0].value.a, ==, ocall_test_val1_in_a); + ADBG_EXPECT_COMPARE_UNSIGNED(local_c, + params[0].value.b, ==, ocall_test_val1_in_b); + ADBG_EXPECT_COMPARE_UNSIGNED(local_c, + params[1].value.a, ==, ocall_test_val2_in_a); + ADBG_EXPECT_COMPARE_UNSIGNED(local_c, + params[1].value.b, ==, ocall_test_val2_in_b); + ADBG_EXPECT_COMPARE_UNSIGNED(local_c, + params[3].value.a, ==, ocall_test_val4_in_a); + ADBG_EXPECT_COMPARE_UNSIGNED(local_c, + params[3].value.b, ==, ocall_test_val4_in_b); + + params[1].value.a = ocall_test_val2_out_a; + params[1].value.b = ocall_test_val2_out_b; + params[2].value.a = ocall_test_val3_out_a; + params[2].value.b = ocall_test_val3_out_b; + break; + + case CA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_MEMREF_PARAMS: + no_ecall_params_ocall_memref_params_reply = true; + + exp_pt = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_INOUT, + TEEC_MEMREF_TEMP_OUTPUT, + TEEC_MEMREF_TEMP_INPUT); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + + ADBG_EXPECT_BUFFER(local_c, ocall_test_buf1_in, + sizeof(ocall_test_buf1_in), + params[0].tmpref.buffer, + params[0].tmpref.size); + ADBG_EXPECT_BUFFER(local_c, ocall_test_buf2_in, + sizeof(ocall_test_buf2_in), + params[1].tmpref.buffer, + params[1].tmpref.size); + ADBG_EXPECT_BUFFER(local_c, ocall_test_buf4_in, + sizeof(ocall_test_buf4_in), + params[3].tmpref.buffer, + params[3].tmpref.size); + + if (!ADBG_EXPECT_COMPARE_UNSIGNED(local_c, + params[1].tmpref.size, ==, + sizeof(ocall_test_buf2_out)) || + !ADBG_EXPECT_COMPARE_UNSIGNED(local_c, + params[2].tmpref.size, ==, + sizeof(ocall_test_buf3_out))) + return TEE_ERROR_BAD_PARAMETERS; + + memcpy(params[1].tmpref.buffer, ocall_test_buf2_out, + sizeof(ocall_test_buf2_out)); + memcpy(params[2].tmpref.buffer, ocall_test_buf3_out, + sizeof(ocall_test_buf3_out)); + break; + + case CA_OCALL_CMD_PREMATURE_SESSION_CLOSE: + exp_pt = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, + TEEC_NONE); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + ADBG_EXPECT_NOT_NULL(local_c, session_data); + TEEC_CloseSession((TEEC_Session *)session_data); + break; + + case CA_OCALL_CMD_PREMATURE_CONTEXT_FINALIZE: + exp_pt = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, + TEEC_NONE); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + ADBG_EXPECT_NOT_NULL(local_c, ctx_data); + TEEC_FinalizeContext((TEEC_Context *)ctx_data); + break; + + case CA_OCALL_CMD_NULL_MEMREF_PARAMS: + null_memref_params_reply = true; + + exp_pt = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_INOUT, + TEEC_MEMREF_TEMP_OUTPUT, + TEEC_NONE); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + ADBG_EXPECT_BUFFER(local_c, NULL, 0, params[0].tmpref.buffer, + params[0].tmpref.size); + ADBG_EXPECT_BUFFER(local_c, NULL, 0, params[1].tmpref.buffer, + params[1].tmpref.size); + ADBG_EXPECT_BUFFER(local_c, NULL, 0, params[2].tmpref.buffer, + params[2].tmpref.size); + break; + + case CA_OCALL_CMD_NULL_MEMREF_PARAMS_MIXED: + null_memref_params_mixed_reply = true; + + exp_pt = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_INOUT, + TEEC_MEMREF_TEMP_OUTPUT, + TEEC_VALUE_OUTPUT); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + + ADBG_EXPECT_BUFFER(local_c, NULL, 0, params[0].tmpref.buffer, + params[0].tmpref.size); + ADBG_EXPECT_BUFFER(local_c, ocall_test_buf2_in, + sizeof(ocall_test_buf2_in), + params[1].tmpref.buffer, + params[1].tmpref.size); + ADBG_EXPECT_BUFFER(local_c, NULL, 0, params[2].tmpref.buffer, + params[2].tmpref.size); + + memcpy(params[1].tmpref.buffer, ocall_test_buf2_out, + sizeof(ocall_test_buf2_out)); + params[3].value.a = ocall_test_val5_out_a; + params[3].value.b = ocall_test_val5_out_b; + break; + + case CA_OCALL_CMD_NULL_MEMREF_PARAMS_INVALID: + /* + * Should not be called; the OCALL should fail to send at the + * TA due to invalid parameters. + */ + null_memref_params_invalid_reply = true; + break; + + case CA_OCALL_CMD_OPEN_SESSION_OCALL: + session_open_ocall_reply = true; + + exp_pt = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, + TEEC_NONE); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + break; + + case CA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE: + session_open_ocall_premature_ctx_finalize_reply = true; + + exp_pt = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, + TEEC_NONE); + ADBG_EXPECT(local_c, exp_pt, paramTypes); + ADBG_EXPECT_NOT_NULL(local_c, ctx_data); + TEEC_FinalizeContext((TEEC_Context *)ctx_data); + break; + + default: + return TEEC_ERROR_BAD_PARAMETERS; + } + + return TEEC_SUCCESS; +} + +static bool test_premature_session_close_prologue(ADBG_Case_t *c) +{ + TEEC_Context ctx = {}; + TEEC_Session sess = {}; + uint32_t ret_orig = 0; + bool ret = false; + + TEEC_ContextSettingOCall ocall_setting = { ocall_handler, &ctx }; + TEEC_ContextSetting ctx_settings[] = { + { .type = TEEC_CONTEXT_SETTING_OCALL, + .u.ocall = &ocall_setting } + }; + + TEEC_SessionSettingData data_setting = { &sess }; + TEEC_SessionSetting sess_settings[] = { + { .type = TEEC_SESSION_SETTING_DATA, + .u.data = &data_setting } + }; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InitializeContext2(xtest_tee_name, &ctx, ctx_settings, 1))) + goto no_ctx; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_OpenSession2(&ctx, &sess, &ocall_ta_uuid, + TEEC_LOGIN_PUBLIC, NULL, NULL, &ret_orig, + sess_settings, 1))) + goto no_sess; + + if (!ADBG_EXPECT_TEEC_RESULT(c, + TEE_ERROR_GENERIC, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_PREMATURE_SESSION_CLOSE, + NULL, &ret_orig))) + goto no_invoke; + + ret = true; + + /* The session will have been closed by the OCALL handler */ + goto no_sess; + +no_invoke: + TEEC_CloseSession(&sess); +no_sess: + TEEC_FinalizeContext(&ctx); +no_ctx: + return ret; +} + +static bool test_premature_context_finalize_prologue(ADBG_Case_t *c) +{ + TEEC_Context ctx = {}; + TEEC_Session sess = {}; + uint32_t ret_orig = 0; + bool ret = false; + + TEEC_ContextSettingOCall ocall_setting = { ocall_handler, &ctx }; + TEEC_ContextSetting ctx_settings[] = { + { .type = TEEC_CONTEXT_SETTING_OCALL, + .u.ocall = &ocall_setting } + }; + + TEEC_SessionSettingData data_setting = { &sess }; + TEEC_SessionSetting sess_settings[] = { + { .type = TEEC_SESSION_SETTING_DATA, + .u.data = &data_setting } + }; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InitializeContext2(xtest_tee_name, &ctx, ctx_settings, 1))) + goto no_ctx; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_OpenSession2(&ctx, &sess, &ocall_ta_uuid, + TEEC_LOGIN_PUBLIC, NULL, NULL, &ret_orig, + sess_settings, 1))) + goto no_sess; + + if (!ADBG_EXPECT_TEEC_RESULT(c, + TEE_ERROR_GENERIC, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_PREMATURE_CONTEXT_FINALIZE, + NULL, &ret_orig))) + goto no_invoke; + + ret = true; + + /* The context will have been finalized by the OCALL handler */ + goto no_ctx; + +no_invoke: + TEEC_CloseSession(&sess); +no_sess: + TEEC_FinalizeContext(&ctx); +no_ctx: + return ret; +} + +static bool test_ocall_during_session_open(ADBG_Case_t *c) +{ + TEEC_Context ctx = {}; + TEEC_Session sess = {}; + uint32_t ret_orig = 0; + TEEC_Operation op = { 0 }; + bool ret = false; + + TEEC_ContextSettingOCall ocall_setting = { ocall_handler, &ctx }; + TEEC_ContextSetting ctx_settings[] = { + { .type = TEEC_CONTEXT_SETTING_OCALL, + .u.ocall = &ocall_setting } + }; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InitializeContext2(xtest_tee_name, &ctx, ctx_settings, 1))) + return false; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, + TEEC_NONE, TEEC_NONE); + op.params[0].value.a = TA_OCALL_CMD_OPEN_SESSION_OCALL; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_OpenSession(&ctx, &sess, &ocall_ta_uuid, TEEC_LOGIN_PUBLIC, + NULL, &op, &ret_orig))) + goto no_sess; + + /* Executes after the OCALL handler */ + ADBG_EXPECT_BOOLEAN(c, true, session_open_ocall_reply); + + TEEC_CloseSession(&sess); + ret = true; + +no_sess: + TEEC_FinalizeContext(&ctx); + return ret; +} + +static bool text_ctx_finalize_during_session_open_ocall(ADBG_Case_t *c) +{ + TEEC_Context ctx = {}; + TEEC_Session sess = {}; + uint32_t ret_orig = 0; + TEEC_Operation op = { 0 }; + bool ret = false; + + TEEC_ContextSettingOCall ocall_setting = { ocall_handler, &ctx }; + TEEC_ContextSetting ctx_settings[] = { + { .type = TEEC_CONTEXT_SETTING_OCALL, + .u.ocall = &ocall_setting } + }; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InitializeContext2(xtest_tee_name, &ctx, ctx_settings, 1))) + return false; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, + TEEC_NONE, TEEC_NONE); + op.params[0].value.a = + TA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE; + + if (!ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_GENERIC, + TEEC_OpenSession(&ctx, &sess, &ocall_ta_uuid, TEEC_LOGIN_PUBLIC, + NULL, &op, &ret_orig))) + goto no_sess; + + /* Executes after the OCALL handler */ + ADBG_EXPECT_BOOLEAN(c, true, + session_open_ocall_premature_ctx_finalize_reply); + + /* + * The OCALL handler will have closed the session by finalizing the + * context. + */ + ret = true; + +no_sess: + TEEC_FinalizeContext(&ctx); + return ret; +} + +static void xtest_tee_test_1101(ADBG_Case_t *c) +{ + TEEC_Context ctx = {}; + TEEC_Session sess = {}; + uint32_t ret_orig = 0; + + TEEC_ContextSettingOCall ocall_setting = { ocall_handler, &ctx }; + TEEC_ContextSetting ctx_settings[] = { + { .type = TEEC_CONTEXT_SETTING_OCALL, + .u.ocall = &ocall_setting } + }; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InitializeContext2(xtest_tee_name, &ctx, ctx_settings, 1))) + return; + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_OpenSession(&ctx, &sess, &ocall_ta_uuid, + TEEC_LOGIN_PUBLIC, NULL, NULL, &ret_orig))) + goto out; + + local_c = c; + + Do_ADBG_BeginSubCase(c, "OCALL without parameters"); + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_NO_ECALL_PARAMS_NO_OCALL_PARAMS, + NULL, &ret_orig)); + ADBG_EXPECT_BOOLEAN(c, true, no_ecall_params_no_ocall_params_reply); + Do_ADBG_EndSubCase(c, "OCALL without parameters"); + + Do_ADBG_BeginSubCase(c, "OCALL with value parameters (in/inout/out/in)"); + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_VALUE_PARAMS, + NULL, &ret_orig)); + ADBG_EXPECT_BOOLEAN(c, true, no_ecall_params_ocall_value_params_reply); + Do_ADBG_EndSubCase(c, "OCALL with value parameters (in/inout/out/in)"); + + Do_ADBG_BeginSubCase(c, "OCALL with memref parameters (in/inout/out/in)"); + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_MEMREF_PARAMS, + NULL, &ret_orig)); + ADBG_EXPECT_BOOLEAN(c, true, no_ecall_params_ocall_memref_params_reply); + Do_ADBG_EndSubCase(c, "OCALL with memref parameters (in/inout/out/in)"); + + Do_ADBG_BeginSubCase(c, "Close session during OCALL"); + if (test_premature_session_close_prologue(c)) + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_GET_PREMATURE_SESSION_CLOSE_STATUS, + NULL, &ret_orig)); + Do_ADBG_EndSubCase(c, "Close session during OCALL"); + + Do_ADBG_BeginSubCase(c, "Finalize context during OCALL"); + if (test_premature_context_finalize_prologue(c)) + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_GET_PREMATURE_CONTEXT_FINALIZE_STATUS, + NULL, &ret_orig)); + Do_ADBG_EndSubCase(c, "Finalize context during OCALL"); + + Do_ADBG_BeginSubCase(c, "NULL memref param"); + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_NULL_MEMREF_PARAMS, + NULL, &ret_orig)); + ADBG_EXPECT_BOOLEAN(c, true, null_memref_params_reply); + Do_ADBG_EndSubCase(c, "NULL memref param"); + + Do_ADBG_BeginSubCase(c, "NULL memref param (mixed params)"); + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_NULL_MEMREF_PARAMS_MIXED, + NULL, &ret_orig)); + ADBG_EXPECT_BOOLEAN(c, true, null_memref_params_mixed_reply); + Do_ADBG_EndSubCase(c, "NULL memref param (mixed params)"); + + Do_ADBG_BeginSubCase(c, "NULL memref param (invalid params)"); + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_NULL_MEMREF_PARAMS_INVALID, + NULL, &ret_orig)); + ADBG_EXPECT_BOOLEAN(c, false, null_memref_params_invalid_reply); + Do_ADBG_EndSubCase(c, "NULL memref param (invalid params)"); + + Do_ADBG_BeginSubCase(c, "OCALL during session open"); + ADBG_EXPECT_BOOLEAN(c, true, test_ocall_during_session_open(c)); + Do_ADBG_EndSubCase(c, "OCALL during session open"); + + Do_ADBG_BeginSubCase(c, "Finalize context during session open OCALL"); + ADBG_EXPECT_BOOLEAN(c, true, + text_ctx_finalize_during_session_open_ocall(c)); + ADBG_EXPECT_TEEC_SUCCESS(c, + TEEC_InvokeCommand(&sess, + TA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE_STATUS, + NULL, &ret_orig)); + Do_ADBG_EndSubCase(c, "Finalize context during session open OCALL"); + + TEEC_CloseSession(&sess); + +out: + TEEC_FinalizeContext(&ctx); +} +ADBG_CASE_DEFINE(regression, 1100, xtest_tee_test_1101, + "Test OCALLs"); diff --git a/host/xtest/xtest_test.c b/host/xtest/xtest_test.c index d13e96d11..3dfcd34ac 100644 --- a/host/xtest/xtest_test.c +++ b/host/xtest/xtest_test.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include <__tee_isocket_defines.h> #include <__tee_tcpsocket_defines.h> @@ -196,3 +197,7 @@ const TEEC_UUID storage_benchmark_ta_uuid = TA_STORAGE_BENCHMARK_UUID; const TEEC_UUID socket_ta_uuid = TA_SOCKET_UUID; const TEEC_UUID sdp_basic_ta_uuid = TA_SDP_BASIC_UUID; const TEEC_UUID tpm_log_test_ta_uuid = TA_TPM_LOG_TEST_UUID; +const TEEC_UUID ocall_ta_uuid = TA_OCALL_UUID; +#ifdef WITH_GP_TESTS +const TEEC_UUID gp_tta_ds_uuid = TA_TTA_DS_UUID; +#endif diff --git a/host/xtest/xtest_test.h b/host/xtest/xtest_test.h index aed4ca075..71a835da6 100644 --- a/host/xtest/xtest_test.h +++ b/host/xtest/xtest_test.h @@ -8,6 +8,7 @@ #define XTEST_TEST_H #include #include +#include #ifdef CFG_PKCS11_TA #include @@ -133,6 +134,7 @@ extern const TEEC_UUID storage_benchmark_ta_uuid; extern const TEEC_UUID socket_ta_uuid; extern const TEEC_UUID sdp_basic_ta_uuid; extern const TEEC_UUID tpm_log_test_ta_uuid; +extern const TEEC_UUID ocall_ta_uuid; extern char *xtest_tee_name; #endif /*XTEST_TEST_H*/ diff --git a/ta/CMakeLists.txt b/ta/CMakeLists.txt index 6f0d904ea..5cd3ac00b 100644 --- a/ta/CMakeLists.txt +++ b/ta/CMakeLists.txt @@ -20,4 +20,5 @@ target_include_directories(${PROJECT_NAME} INTERFACE socket/include INTERFACE storage_benchmark/include INTERFACE tpm_log_test/include + INTERFACE ocall/include ) diff --git a/ta/Makefile b/ta/Makefile index 814593a9d..21c88adbf 100644 --- a/ta/Makefile +++ b/ta/Makefile @@ -36,6 +36,10 @@ ifeq ($(CFG_SECURE_DATA_PATH),y) TA_DIRS += sdp_basic endif +ifeq ($(CFG_OCALL),y) +TA_DIRS += ocall +endif + ifdef CFG_GP_PACKAGE_PATH TA_DIRS += GP_TTA_Arithmetical \ GP_TTA_Crypto \ diff --git a/ta/ocall/Android.mk b/ta/ocall/Android.mk new file mode 100644 index 000000000..ba9309a2e --- /dev/null +++ b/ta/ocall/Android.mk @@ -0,0 +1,4 @@ +LOCAL_PATH := $(call my-dir) + +local_module := 616906e4-2fa8-44c6-a698-2cf2d35b99f9.ta +include $(BUILD_OPTEE_MK) diff --git a/ta/ocall/Makefile b/ta/ocall/Makefile new file mode 100644 index 000000000..f131bf753 --- /dev/null +++ b/ta/ocall/Makefile @@ -0,0 +1,2 @@ +BINARY = 616906e4-2fa8-44c6-a698-2cf2d35b99f9 +include ../ta_common.mk diff --git a/ta/ocall/include/ta_ocall.h b/ta/ocall/include/ta_ocall.h new file mode 100644 index 000000000..2dfff0291 --- /dev/null +++ b/ta/ocall/include/ta_ocall.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020, Microsoft Corporation + */ + +#ifndef TA_OCALL_H +#define TA_OCALL_H + +#include + +extern bool g_close_session_entry_point_called; +extern bool g_test_premature_context_finalize_during_session_open_ocall_ok; + +TEE_Result test_no_ecall_params_no_ocall_params(uint32_t param_types); +TEE_Result test_no_ecall_params_ocall_value_params(uint32_t param_types); +TEE_Result test_no_ecall_params_ocall_memref_params(uint32_t param_types); +TEE_Result test_null_memref_params(uint32_t param_types); +TEE_Result test_null_memref_params_mixed(uint32_t param_types); +TEE_Result test_null_memref_params_invalid(uint32_t param_types); +TEE_Result test_premature_session_close(uint32_t param_types); +TEE_Result get_premature_session_close_status(uint32_t param_types); +TEE_Result test_premature_context_finalize(uint32_t param_types); +TEE_Result get_premature_context_finalize_status(uint32_t param_types); +TEE_Result get_premature_context_finalize_during_session_open_ocall_status(uint32_t param_types); + +#endif /*TA_OCALL_H */ diff --git a/ta/ocall/include/ta_ocall_data.h b/ta/ocall/include/ta_ocall_data.h new file mode 100644 index 000000000..6f89eb212 --- /dev/null +++ b/ta/ocall/include/ta_ocall_data.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020, Microsoft Corporation + */ + +#ifndef TA_OCALL_DATA_H +#define TA_OCALL_DATA_H + +/* + * Test values (in/out specified from the TA's point of view) + */ + +static const uint32_t ocall_test_val1_in_a = 0; +static const uint32_t ocall_test_val1_in_b = 0xffffffff; + +static const uint32_t ocall_test_val2_in_a = 0xacd0281f; +static const uint32_t ocall_test_val2_in_b = 104826; + +static const uint32_t ocall_test_val2_out_a = 9; +static const uint32_t ocall_test_val2_out_b = 0x98f5d1ce; + +static const uint32_t ocall_test_val3_out_a = 0x71fae3db; +static const uint32_t ocall_test_val3_out_b = 10394; + +static const uint32_t ocall_test_val4_in_a = 0xfffffffe; +static const uint32_t ocall_test_val4_in_b = 1; + +static const uint32_t ocall_test_val5_out_a = 0xfd185; +static const uint32_t ocall_test_val5_out_b = 0; + +/* + * Test buffers (in/out specified from the TA's point of view) + */ + +/* 1 byte */ +static const char ocall_test_buf1_in[] = { 0xe3 }; + +/* 8 bytes */ +static const char ocall_test_buf2_in[] = { + 0x5a, 0xc9, 0x5f, 0x4a, 0x79, 0x39, 0x88, 0xb8 +}; +static const char ocall_test_buf2_out[] = { + 0x37, 0x52, 0x26, 0xab, 0x57, 0x9f, 0xc9, 0xd1 +}; + +/* 16 bytes */ +static const char ocall_test_buf3_out[] = { + 0x03, 0x63, 0x23, 0xc2, 0x80, 0x5c, 0x5b, 0xd6, + 0xcf, 0xaf, 0xfd, 0x7c, 0x2f, 0x4d, 0xcf, 0x47, +}; + +/* 32 bytes */ +static const char ocall_test_buf4_in[] = { + 0xc8, 0x62, 0x93, 0x9b, 0x37, 0xd5, 0x3a, 0xd9, + 0x65, 0xb1, 0xea, 0x36, 0x97, 0x7d, 0x36, 0x30, + 0xff, 0x94, 0x00, 0xa3, 0xc1, 0x59, 0x7f, 0x34, + 0x47, 0x5d, 0x8e, 0x77, 0xe8, 0x2a, 0x83, 0x06, +}; + +#endif /*TA_OCALL_DATA_H */ diff --git a/ta/ocall/include/ta_ocall_test.h b/ta/ocall/include/ta_ocall_test.h new file mode 100644 index 000000000..9770edc0d --- /dev/null +++ b/ta/ocall/include/ta_ocall_test.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020, Microsoft Corporation + */ + +#ifndef TA_OCALL_TEST_H +#define TA_OCALL_TEST_H + +/* This UUID was generated with uuidgen */ +#define TA_OCALL_UUID { 0x616906e4, 0x2fa8, 0x44c6, \ + { 0xa6, 0x98, 0x2c, 0xf2, 0xd3, 0x5b, 0x99, 0xf9 } } + +/* Command IDs understood by the TA */ +#define TA_OCALL_CMD_NO_ECALL_PARAMS_NO_OCALL_PARAMS 0 +#define TA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_VALUE_PARAMS 1 +#define TA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_MEMREF_PARAMS 2 +#define TA_OCALL_CMD_NULL_MEMREF_PARAMS 3 +#define TA_OCALL_CMD_NULL_MEMREF_PARAMS_MIXED 4 +#define TA_OCALL_CMD_NULL_MEMREF_PARAMS_INVALID 5 +#define TA_OCALL_CMD_PREMATURE_SESSION_CLOSE 6 +#define TA_OCALL_CMD_GET_PREMATURE_SESSION_CLOSE_STATUS 7 +#define TA_OCALL_CMD_PREMATURE_CONTEXT_FINALIZE 8 +#define TA_OCALL_CMD_GET_PREMATURE_CONTEXT_FINALIZE_STATUS 9 +#define TA_OCALL_CMD_OPEN_SESSION_OCALL 10 +#define TA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE 11 +#define TA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE_STATUS 12 + +/* Command IDs understood by the CA */ +#define CA_OCALL_CMD_NO_ECALL_PARAMS_NO_OCALL_PARAMS \ + TA_OCALL_CMD_NO_ECALL_PARAMS_NO_OCALL_PARAMS +#define CA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_VALUE_PARAMS \ + TA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_VALUE_PARAMS +#define CA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_MEMREF_PARAMS \ + TA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_MEMREF_PARAMS +#define CA_OCALL_CMD_NULL_MEMREF_PARAMS \ + TA_OCALL_CMD_NULL_MEMREF_PARAMS +#define CA_OCALL_CMD_NULL_MEMREF_PARAMS_MIXED \ + TA_OCALL_CMD_NULL_MEMREF_PARAMS_MIXED +#define CA_OCALL_CMD_NULL_MEMREF_PARAMS_INVALID \ + TA_OCALL_CMD_NULL_MEMREF_PARAMS_INVALID +#define CA_OCALL_CMD_PREMATURE_SESSION_CLOSE \ + TA_OCALL_CMD_PREMATURE_SESSION_CLOSE +#define CA_OCALL_CMD_PREMATURE_CONTEXT_FINALIZE \ + TA_OCALL_CMD_PREMATURE_CONTEXT_FINALIZE +#define CA_OCALL_CMD_OPEN_SESSION_OCALL \ + TA_OCALL_CMD_OPEN_SESSION_OCALL +#define CA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE \ + TA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE + +#endif /*TA_OCALL_TEST_H */ diff --git a/ta/ocall/include/user_ta_header_defines.h b/ta/ocall/include/user_ta_header_defines.h new file mode 100644 index 000000000..92968a7d8 --- /dev/null +++ b/ta/ocall/include/user_ta_header_defines.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020, Microsoft Corporation + */ + +#ifndef USER_TA_HEADER_DEFINES_H +#define USER_TA_HEADER_DEFINES_H + +#include +#include + +#define TA_UUID TA_OCALL_UUID + +#define TA_FLAGS (TA_FLAG_SINGLE_INSTANCE | \ + TA_FLAG_MULTI_SESSION | \ + TA_FLAG_INSTANCE_KEEP_ALIVE) + +#define TA_STACK_SIZE (4 * 1024) +#define TA_DATA_SIZE (64 * 1024) + +#endif /* USER_TA_HEADER_DEFINES_H */ diff --git a/ta/ocall/sub.mk b/ta/ocall/sub.mk new file mode 100644 index 000000000..08dc4c01f --- /dev/null +++ b/ta/ocall/sub.mk @@ -0,0 +1,3 @@ +global-incdirs-y += include +srcs-y += ta_entry.c +srcs-y += ta_ocall.c diff --git a/ta/ocall/ta_entry.c b/ta/ocall/ta_entry.c new file mode 100644 index 000000000..036085c34 --- /dev/null +++ b/ta/ocall/ta_entry.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020, Microsoft Corporation + */ + +#include +#include +#include +#include +#include +#include + +/* + * Trusted Application Entry Points + */ + +/* Called each time a new instance is created */ +TEE_Result TA_CreateEntryPoint(void) +{ + DMSG("TA_CreateEntryPoint"); + return TEE_SUCCESS; +} + +/* Called each time an instance is destroyed */ +void TA_DestroyEntryPoint(void) +{ + DMSG("TA_DestroyEntryPoint"); +} + +/* Called each time a session is opened */ +TEE_Result TA_OpenSessionEntryPoint(uint32_t nParamTypes, + TEE_Param pParams[4], + void **ppSessionContext __unused) +{ + TEE_Result res; + uint32_t eorig; + + const uint32_t expected_pt1 = TEE_PARAM_TYPES( + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + const uint32_t expected_pt2 = TEE_PARAM_TYPES( + TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + + DMSG("TA_OpenSessionEntryPoint"); + + if (nParamTypes == expected_pt1) + return TEE_SUCCESS; + + if (nParamTypes != expected_pt2) + return TEE_ERROR_BAD_PARAMETERS; + + switch (pParams[0].value.a) { + case TA_OCALL_CMD_OPEN_SESSION_OCALL: + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_OPEN_SESSION_OCALL, 0, + NULL, &eorig); + if (res != TEE_SUCCESS) + EMSG("TEE_InvokeCACommand failed with code 0x%x origin 0x%x", + res, eorig); + break; + + case TA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE: + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE, + 0, NULL, &eorig); + if (res != TEE_ERROR_TARGET_DEAD || eorig != TEE_ORIGIN_COMMS) { + EMSG("TEE_InvokeCACommand failed with wrong code 0x%x and/or origin 0x%x", + res, eorig); + return res; + } + + g_test_premature_context_finalize_during_session_open_ocall_ok = true; + + break; + + default: + return TEE_ERROR_BAD_PARAMETERS; + } + + return res; +} + +/* Called each time a session is closed */ +void TA_CloseSessionEntryPoint(void *pSessionContext) +{ + (void)pSessionContext; + g_close_session_entry_point_called = true; + DMSG("TA_CloseSessionEntryPoint"); +} + +/* Called when a command is invoked */ +TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext, + uint32_t nCommandID, uint32_t nParamTypes, + TEE_Param pParams[4]) +{ + (void)pSessionContext; + (void)pParams; + + switch (nCommandID) { + case TA_OCALL_CMD_NO_ECALL_PARAMS_NO_OCALL_PARAMS: + return test_no_ecall_params_no_ocall_params(nParamTypes); + + case TA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_VALUE_PARAMS: + return test_no_ecall_params_ocall_value_params(nParamTypes); + + case TA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_MEMREF_PARAMS: + return test_no_ecall_params_ocall_memref_params(nParamTypes); + + case TA_OCALL_CMD_PREMATURE_SESSION_CLOSE: + return test_premature_session_close(nParamTypes); + + case TA_OCALL_CMD_GET_PREMATURE_SESSION_CLOSE_STATUS: + return get_premature_session_close_status(nParamTypes); + + case TA_OCALL_CMD_PREMATURE_CONTEXT_FINALIZE: + return test_premature_context_finalize(nParamTypes); + + case TA_OCALL_CMD_GET_PREMATURE_CONTEXT_FINALIZE_STATUS: + return get_premature_context_finalize_status(nParamTypes); + + case TA_OCALL_CMD_NULL_MEMREF_PARAMS: + return test_null_memref_params(nParamTypes); + + case TA_OCALL_CMD_NULL_MEMREF_PARAMS_MIXED: + return test_null_memref_params_mixed(nParamTypes); + + case TA_OCALL_CMD_NULL_MEMREF_PARAMS_INVALID: + return test_null_memref_params_invalid(nParamTypes); + + case TA_OCALL_CMD_OPEN_SESSION_OCALL_PREMATURE_CONTEXT_FINALIZE_STATUS: + return get_premature_context_finalize_during_session_open_ocall_status(nParamTypes); + + default: + return TEE_ERROR_BAD_PARAMETERS; + } +} diff --git a/ta/ocall/ta_ocall.c b/ta/ocall/ta_ocall.c new file mode 100644 index 000000000..39d80be68 --- /dev/null +++ b/ta/ocall/ta_ocall.c @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020, Microsoft Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +bool g_close_session_entry_point_called; +bool g_test_premature_context_finalize_during_session_open_ocall_ok; + +TEE_Result test_no_ecall_params_no_ocall_params(uint32_t param_types) +{ + TEE_Result res; + uint32_t eorig; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_NO_ECALL_PARAMS_NO_OCALL_PARAMS, + 0, NULL, &eorig); + if (res != TEE_SUCCESS) + EMSG("TEE_InvokeCACommand failed with code 0x%x origin 0x%x", + res, eorig); + + return res; +} + +TEE_Result test_no_ecall_params_ocall_value_params(uint32_t param_types) +{ + TEE_Param ocall_params[TEE_NUM_PARAMS]; + TEE_Result res; + uint32_t eorig; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + const uint32_t ocall_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INOUT, + TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_VALUE_INPUT); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + ocall_params[0].value.a = ocall_test_val1_in_a; + ocall_params[0].value.b = ocall_test_val1_in_b; + + ocall_params[1].value.a = ocall_test_val2_in_a; + ocall_params[1].value.b = ocall_test_val2_in_b; + + ocall_params[3].value.a = ocall_test_val4_in_a; + ocall_params[3].value.b = ocall_test_val4_in_b; + + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_VALUE_PARAMS, + ocall_pt, ocall_params, &eorig); + if (res != TEE_SUCCESS) { + EMSG("TEE_InvokeCACommand failed with code 0x%x origin 0x%x", + res, eorig); + return res; + } + + if (ocall_params[1].value.a != ocall_test_val2_out_a || + ocall_params[1].value.b != ocall_test_val2_out_b || + ocall_params[2].value.a != ocall_test_val3_out_a || + ocall_params[2].value.b != ocall_test_val3_out_b) + return TEE_ERROR_BAD_PARAMETERS; + + return res; +} + +TEE_Result test_no_ecall_params_ocall_memref_params(uint32_t param_types) +{ + TEE_Param ocall_params[TEE_NUM_PARAMS]; + TEE_Result res; + uint32_t eorig; + + char ocall_test_buf2_in_local[8]; + char ocall_test_buf3_in[16] = { 0 }; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + const uint32_t ocall_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_MEMREF_INPUT); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + memcpy(ocall_test_buf2_in_local, ocall_test_buf2_in, + sizeof(ocall_test_buf2_in_local)); + + ocall_params[0].memref.buffer = (void *)ocall_test_buf1_in; + ocall_params[0].memref.size = sizeof(ocall_test_buf1_in); + + ocall_params[1].memref.buffer = (void *)ocall_test_buf2_in_local; + ocall_params[1].memref.size = sizeof(ocall_test_buf2_in_local); + + ocall_params[2].memref.buffer = (void *)ocall_test_buf3_in; + ocall_params[2].memref.size = sizeof(ocall_test_buf3_in); + + ocall_params[3].memref.buffer = (void *)ocall_test_buf4_in; + ocall_params[3].memref.size = sizeof(ocall_test_buf4_in); + + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_NO_ECALL_PARAMS_OCALL_MEMREF_PARAMS, + ocall_pt, ocall_params, &eorig); + if (res != TEE_SUCCESS) { + EMSG("TEE_InvokeCACommand failed with code 0x%x origin 0x%x", + res, eorig); + return res; + } + + if (ocall_params[1].memref.size != sizeof(ocall_test_buf2_out) || + ocall_params[2].memref.size != sizeof(ocall_test_buf3_out)) + return TEE_ERROR_BAD_PARAMETERS; + + if (TEE_MemCompare(ocall_params[1].memref.buffer, ocall_test_buf2_out, + sizeof(ocall_test_buf2_out))) + return TEE_ERROR_BAD_PARAMETERS; + + if (TEE_MemCompare(ocall_params[2].memref.buffer, ocall_test_buf3_out, + sizeof(ocall_test_buf3_out))) + return TEE_ERROR_BAD_PARAMETERS; + + return TEE_SUCCESS; +} + +static bool g_test_premature_session_close_ok; +TEE_Result test_premature_session_close(uint32_t param_types) +{ + TEE_Result res; + uint32_t eorig; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_PREMATURE_SESSION_CLOSE, + 0, NULL, &eorig); + if (res != TEE_ERROR_TARGET_DEAD || eorig != TEE_ORIGIN_COMMS) { + EMSG("TEE_InvokeCACommand failed with wrong code 0x%x and/or origin 0x%x", + res, eorig); + return res; + } + + g_test_premature_session_close_ok = true; + + return TEE_SUCCESS; +} + +TEE_Result get_premature_session_close_status(uint32_t param_types) +{ + TEE_Result res; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + if (g_close_session_entry_point_called && + g_test_premature_session_close_ok) + res = TEE_SUCCESS; + else + res = TEE_ERROR_BAD_STATE; + + g_close_session_entry_point_called = false; + g_test_premature_session_close_ok = false; + + return res; +} + +static bool g_test_premature_context_finalize_ok; +TEE_Result test_premature_context_finalize(uint32_t param_types) +{ + TEE_Result res; + uint32_t eorig; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_PREMATURE_CONTEXT_FINALIZE, + 0, NULL, &eorig); + if (res != TEE_ERROR_TARGET_DEAD || eorig != TEE_ORIGIN_COMMS) { + EMSG("TEE_InvokeCACommand failed with wrong code 0x%x and/or origin 0x%x", + res, eorig); + return res; + } + + g_test_premature_context_finalize_ok = true; + + return TEE_SUCCESS; +} + +TEE_Result get_premature_context_finalize_status(uint32_t param_types) +{ + TEE_Result res; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + if (g_close_session_entry_point_called && + g_test_premature_context_finalize_ok) + res = TEE_SUCCESS; + else + res = TEE_ERROR_BAD_STATE; + + g_close_session_entry_point_called = false; + g_test_premature_context_finalize_ok = false; + + return res; +} + +TEE_Result test_null_memref_params(uint32_t param_types) +{ + TEE_Param ocall_params[TEE_NUM_PARAMS]; + TEE_Result res; + uint32_t eorig; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + const uint32_t ocall_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + ocall_params[0].memref.buffer = NULL; + ocall_params[0].memref.size = 0; + + ocall_params[1].memref.buffer = NULL; + ocall_params[1].memref.size = 0; + + ocall_params[2].memref.buffer = NULL; + ocall_params[2].memref.size = 0; + + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_NULL_MEMREF_PARAMS, + ocall_pt, ocall_params, &eorig); + if (res != TEE_SUCCESS) { + EMSG("TEE_InvokeCACommand failed with code 0x%x origin 0x%x", + res, eorig); + return res; + } + + return TEE_SUCCESS; +} + +TEE_Result test_null_memref_params_mixed(uint32_t param_types) +{ + TEE_Param ocall_params[TEE_NUM_PARAMS]; + TEE_Result res; + uint32_t eorig; + + char ocall_test_buf2_in_local[8]; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + const uint32_t ocall_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + memcpy(ocall_test_buf2_in_local, ocall_test_buf2_in, + sizeof(ocall_test_buf2_in_local)); + + ocall_params[0].memref.buffer = NULL; + ocall_params[0].memref.size = 0; + + ocall_params[1].memref.buffer = (void *)ocall_test_buf2_in_local; + ocall_params[1].memref.size = sizeof(ocall_test_buf2_in_local); + + ocall_params[2].memref.buffer = NULL; + ocall_params[2].memref.size = 0; + + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_NULL_MEMREF_PARAMS_MIXED, + ocall_pt, ocall_params, &eorig); + if (res != TEE_SUCCESS) { + EMSG("TEE_InvokeCACommand failed with code 0x%x origin 0x%x", + res, eorig); + return res; + } + + if (ocall_params[1].memref.size != sizeof(ocall_test_buf2_out)) + return TEE_ERROR_BAD_PARAMETERS; + + if (TEE_MemCompare(ocall_params[1].memref.buffer, ocall_test_buf2_out, + sizeof(ocall_test_buf2_out))) + return TEE_ERROR_BAD_PARAMETERS; + + if (ocall_params[3].value.a != ocall_test_val5_out_a || + ocall_params[3].value.b != ocall_test_val5_out_b) + return TEE_ERROR_BAD_PARAMETERS; + + return TEE_SUCCESS; +} + +TEE_Result test_null_memref_params_invalid(uint32_t param_types) +{ + TEE_Param ocall_params[TEE_NUM_PARAMS]; + TEE_Result res; + uint32_t eorig; + + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + const uint32_t ocall_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + ocall_params[0].memref.buffer = NULL; + ocall_params[0].memref.size = UINT32_MAX; + + ocall_params[1].memref.buffer = (void *)ocall_params; + ocall_params[1].memref.size = 0; + + res = TEE_InvokeCACommand(TEE_TIMEOUT_INFINITE, + CA_OCALL_CMD_NULL_MEMREF_PARAMS_INVALID, + ocall_pt, ocall_params, &eorig); + if (res != TEE_ERROR_BAD_PARAMETERS || eorig != TEE_ORIGIN_API) { + EMSG("TEE_InvokeCACommand failed with wrong code 0x%x and/or origin 0x%x", + res, eorig); + return res; + } + + return TEE_SUCCESS; +} + +TEE_Result +get_premature_context_finalize_during_session_open_ocall_status(uint32_t param_types) +{ + const uint32_t expected_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != expected_pt) + return TEE_ERROR_BAD_PARAMETERS; + + if (g_test_premature_context_finalize_during_session_open_ocall_ok) { + g_test_premature_context_finalize_during_session_open_ocall_ok = false; + return TEE_SUCCESS; + } + + return TEE_ERROR_BAD_STATE; +}