xtest: add --clear-storage option
When unexpected errors occur in the secure storage tests
(regression_6xxx) some persistent objects might be left over, causing
errors in further tests which expect to start from a clean state.
This situation cannot be addressed fully by error handling in xtest or
in the storage TA, because there are unrecoverable conditions (data
abort, kill -9...). Instead, implement a new --clear-storage option
which invokes the storage TA to enumerate and delete any objects it may
own. The TA is invoked twice (because the same code is exposed via two
UUIDS), and each invocation iterates on the two possible filesystems
(TEE_STORAGE_PRIVATE_REE, TEE_STORAGE_PRIVATE_RPMB).
Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
Reviewed-by: Joakim Bech <joakim.bech@linaro.org>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Etienne Carriere <etienne.carriere@foss.st.com>
diff --git a/Android.mk b/Android.mk
index feb05c6..4c1ebec 100644
--- a/Android.mk
+++ b/Android.mk
@@ -45,6 +45,7 @@
aes_perf.c \
benchmark_1000.c \
benchmark_2000.c \
+ clear_storage.c \
regression_4000.c \
regression_4100.c \
regression_5000.c \
diff --git a/host/xtest/CMakeLists.txt b/host/xtest/CMakeLists.txt
index 776787b..e45fae5 100644
--- a/host/xtest/CMakeLists.txt
+++ b/host/xtest/CMakeLists.txt
@@ -48,6 +48,7 @@
aes_perf.c
benchmark_1000.c
benchmark_2000.c
+ clear_storage.c
regression_1000.c
regression_4000.c
regression_4100.c
diff --git a/host/xtest/Makefile b/host/xtest/Makefile
index 8505629..ce55c3f 100644
--- a/host/xtest/Makefile
+++ b/host/xtest/Makefile
@@ -70,6 +70,7 @@
aes_perf.c \
benchmark_1000.c \
benchmark_2000.c \
+ clear_storage.c \
regression_4000.c \
regression_4100.c \
regression_5000.c \
diff --git a/host/xtest/clear_storage.c b/host/xtest/clear_storage.c
new file mode 100644
index 0000000..3dcf195
--- /dev/null
+++ b/host/xtest/clear_storage.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <err.h>
+#include <ta_storage.h>
+#include <tee_client_api.h>
+#include <stdlib.h>
+#include <util.h>
+
+#include "clear_storage.h"
+
+static int clear_storage_for_ta(TEEC_UUID *uuid)
+{
+ TEEC_Result res = TEEC_ERROR_GENERIC;
+ TEEC_Context ctx = { };
+ TEEC_Session sess = { };
+ TEEC_Operation op = { };
+ uint32_t eo = 0;
+
+ res = TEEC_InitializeContext(NULL, &ctx);
+ if (res)
+ errx(EXIT_FAILURE, "TEEC_InitializeContext: %#"PRIx32, res);
+
+ res = TEEC_OpenSession(&ctx, &sess, uuid, TEEC_LOGIN_PUBLIC, NULL,
+ NULL, &eo);
+ if (res)
+ errx(EXIT_FAILURE,
+ "TEEC_OpenSession: res %#"PRIx32" err_orig %#"PRIx32,
+ res, eo);
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE,
+ TEEC_NONE);
+ res = TEEC_InvokeCommand(&sess, TA_STORAGE_CMD_CLEAR_STORAGE, &op, &eo);
+ if (res)
+ errx(EXIT_FAILURE,
+ "TEEC_InvokeCommand: res %#"PRIx32" err_orig %#"PRIx32,
+ res, eo);
+
+ TEEC_CloseSession(&sess);
+ TEEC_FinalizeContext(&ctx);
+ return 0;
+}
+
+int clear_storage(void)
+{
+ TEEC_UUID uuid[] = { TA_STORAGE_UUID, TA_STORAGE2_UUID };
+ size_t i = 0;
+ int res = 0;
+
+ for (i = 0; i < ARRAY_SIZE(uuid); i++) {
+ res = clear_storage_for_ta(uuid + i);
+ if (res)
+ break;
+ }
+ return res;
+}
diff --git a/host/xtest/clear_storage.h b/host/xtest/clear_storage.h
new file mode 100644
index 0000000..9f049f7
--- /dev/null
+++ b/host/xtest/clear_storage.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef CLEAR_STORAGE_H
+#define CLEAR_STORAGE_H
+
+int clear_storage(void);
+
+#endif /*CLEAR_STORAGE_H*/
diff --git a/host/xtest/xtest_main.c b/host/xtest/xtest_main.c
index 9771ae0..457f6f6 100644
--- a/host/xtest/xtest_main.c
+++ b/host/xtest/xtest_main.c
@@ -24,11 +24,11 @@
#include "xtest_helpers.h"
/* include here shandalone tests */
+#include "clear_storage.h"
#include "crypto_common.h"
#include "install_ta.h"
#include "stats.h"
-
ADBG_SUITE_DEFINE(benchmark);
#ifdef WITH_GP_TESTS
ADBG_SUITE_DEFINE(gp);
@@ -109,6 +109,8 @@
printf("\t--sdp-basic [opts] Basic Secure Data Path test setup ('-h' for usage)\n");
#endif
printf("\t--stats [opts] Various statistics ('-h' for usage)\n");
+ printf("\t--clear-storage Delete any persistent objects that may have been\n");
+ printf("\t left over by a previous run of this application\n");
printf("\n");
printf("Examples:\n");
printf("\txtest -t regression 4001 4003\n");
@@ -169,6 +171,8 @@
#endif
else if (argc > 1 && !strcmp(argv[1], "--stats"))
return stats_runner_cmd_parser(argc - 1, &argv[1]);
+ else if (argc == 2 && !strcmp(argv[1], "--clear-storage"))
+ return clear_storage();
while ((opt = getopt(argc, argv, "d:l:t:h")) != -1) {
switch (opt) {
diff --git a/ta/include/ta_storage.h b/ta/include/ta_storage.h
index 96bc560..f494f5c 100644
--- a/ta/include/ta_storage.h
+++ b/ta/include/ta_storage.h
@@ -50,5 +50,6 @@
#define TA_STORAGE_CMD_CREATE_ID_IN_SHM 23
#define TA_STORAGE_CMD_CREATEOVER_ID_IN_SHM 24
#define TA_STORAGE_CMD_RENAME_ID_IN_SHM 25
+#define TA_STORAGE_CMD_CLEAR_STORAGE 26
#endif /*__TA_STORAGE_H*/
diff --git a/ta/storage/include/storage.h b/ta/storage/include/storage.h
index ecbda8a..50a99d6 100644
--- a/ta/storage/include/storage.h
+++ b/ta/storage/include/storage.h
@@ -39,5 +39,7 @@
TEE_Result ta_storage_cmd_reset_obj(uint32_t param_types, TEE_Param params[4]);
TEE_Result ta_storage_cmd_get_obj_info(uint32_t param_types,
TEE_Param params[4]);
+TEE_Result ta_storage_cmd_clear_storage(uint32_t param_types,
+ TEE_Param params[4]);
#endif /*STORAGE_H */
diff --git a/ta/storage/storage.c b/ta/storage/storage.c
index 93548a3..f570732 100644
--- a/ta/storage/storage.c
+++ b/ta/storage/storage.c
@@ -8,7 +8,9 @@
#include "ta_storage.h"
#include <tee_api.h>
+#include <tee_api_defines_extensions.h>
#include <trace.h>
+#include <user_ta_header_defines.h>
#define ASSERT_PARAM_TYPE(pt) \
do { \
@@ -662,3 +664,77 @@
return res;
}
+
+static TEE_Result clear_storage(uint32_t storage_id)
+{
+ TEE_ObjectEnumHandle oe = TEE_HANDLE_NULL;
+ TEE_Result enum_res = TEE_ERROR_GENERIC;
+ TEE_ObjectHandle o = TEE_HANDLE_NULL;
+ TEE_Result res = TEE_ERROR_GENERIC;
+ TEE_UUID uuid = TA_UUID;
+ TEE_ObjectInfo oi = { };
+ size_t obj_id_sz = 0;
+ void *obj_id = NULL;
+ size_t i = 0;
+
+ IMSG("Clearing TA storage (UUID: %pUl, storage ID: 0x%x)",
+ (void *)&uuid, storage_id);
+ res = TEE_AllocatePersistentObjectEnumerator(&oe);
+ if (res)
+ return res;
+ res = TEE_StartPersistentObjectEnumerator(oe, storage_id);
+ if (res == TEE_ERROR_ITEM_NOT_FOUND) {
+ IMSG("No object found");
+ res = TEE_SUCCESS;
+ goto out;
+ }
+ if (res)
+ goto out;
+ obj_id = TEE_Malloc(TEE_OBJECT_ID_MAX_LEN, 0);
+ if (!obj_id) {
+ res = TEE_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ while (true) {
+ enum_res = TEE_GetNextPersistentObject(oe, &oi, obj_id,
+ &obj_id_sz);
+ if (enum_res == TEE_ERROR_ITEM_NOT_FOUND)
+ break;
+ if (enum_res) {
+ res = enum_res;
+ break;
+ }
+ IMSG("Deleting persistent object #%zu", i);
+ res = TEE_OpenPersistentObject(storage_id, obj_id, obj_id_sz,
+ TEE_DATA_FLAG_ACCESS_WRITE_META,
+ &o);
+ if (res)
+ break;
+ TEE_CloseAndDeletePersistentObject1(o);
+ i++;
+ }
+
+out:
+ TEE_FreePersistentObjectEnumerator(oe);
+ TEE_Free(obj_id);
+ return res;
+}
+
+TEE_Result ta_storage_cmd_clear_storage(uint32_t param_types,
+ TEE_Param params[4])
+{
+ uint32_t id[] = { TEE_STORAGE_PRIVATE_REE, TEE_STORAGE_PRIVATE_RPMB };
+ TEE_Result res = TEE_ERROR_GENERIC;
+ size_t i = 0;
+
+ (void)param_types;
+ (void)params;
+
+ for (i = 0; i < sizeof(id) / sizeof(id[0]); i++) {
+ res = clear_storage(id[i]);
+ if (res)
+ break;
+ }
+ return res;
+}
diff --git a/ta/storage/ta_entry.c b/ta/storage/ta_entry.c
index c507c61..f3a93db 100644
--- a/ta/storage/ta_entry.c
+++ b/ta/storage/ta_entry.c
@@ -119,6 +119,9 @@
case TA_STORAGE_CMD_GET_OBJ_INFO:
return ta_storage_cmd_get_obj_info(nParamTypes, pParams);
+ case TA_STORAGE_CMD_CLEAR_STORAGE:
+ return ta_storage_cmd_clear_storage(nParamTypes, pParams);
+
default:
return TEE_ERROR_BAD_PARAMETERS;
}