Test integrity of TA
This patch adds a test case that corrupts a TA prior to loading it and
verifies that open-session returns TEEC_ERROR_SECURITY.
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Tested-by: Jens Wiklander <jens.wiklander@linaro.org> (QEMU)
Reviewed-by: Joakim Bech <joakim.bech@linaro.org>
Reviewed-by: Jerome Forissier <jerome.forissier@linaro.org>
diff --git a/host/xtest/xtest_1000.c b/host/xtest/xtest_1000.c
index 8f0f588..bbd3c39 100644
--- a/host/xtest/xtest_1000.c
+++ b/host/xtest/xtest_1000.c
@@ -22,6 +22,7 @@
#include "xtest_test.h"
#include "xtest_helpers.h"
+#include <signed_hdr.h>
#include <ta_crypt.h>
#include <ta_os_test.h>
@@ -512,7 +513,7 @@
static void uuid_to_full_name(char *buf, size_t blen, const TEEC_UUID *uuid,
const char *extra_suffix)
{
- static const char ta_dir[] = "/lib/teetz";
+ static const char ta_dir[] = "/lib/optee_armtz";
snprintf(buf, blen,
"%s/%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x.ta%s",
@@ -541,20 +542,64 @@
return !unlink(buf);
}
-static bool copy_file(FILE *src, FILE *dst)
+static bool rename_file(const TEEC_UUID *old_uuid, const char *old_extra_suffix,
+ const TEEC_UUID *new_uuid, const char *new_extra_suffix)
+{
+ char old_buf[PATH_MAX];
+ char new_buf[PATH_MAX];
+
+ uuid_to_full_name(old_buf, sizeof(old_buf), old_uuid, old_extra_suffix);
+ uuid_to_full_name(new_buf, sizeof(new_buf), new_uuid, new_extra_suffix);
+ return !rename(old_buf, new_buf);
+}
+
+static bool copy_file(const TEEC_UUID *src_uuid, const char *src_extra_suffix,
+ const TEEC_UUID *dst_uuid, const char *dst_extra_suffix)
{
char buf[4 * 1024];
+ FILE *src = open_ta_file(src_uuid, src_extra_suffix, "r");
+ FILE *dst = open_ta_file(dst_uuid, dst_extra_suffix, "w");
size_t r;
size_t w;
+ bool ret = false;
- while (true) {
- r = fread(buf, 1, sizeof(buf), src);
- if (!r)
- return !!feof(src);
- w = fwrite(buf, 1, r, dst);
- if (w != r)
- return false;
+ if (src && dst) {
+ do {
+ r = fread(buf, 1, sizeof(buf), src);
+ if (!r) {
+ ret = !!feof(src);
+ break;
+ }
+ w = fwrite(buf, 1, r, dst);
+ } while (w == r);
}
+
+ if (src)
+ fclose(src);
+ if (dst)
+ fclose(dst);
+ return ret;
+}
+
+static bool corrupt_file(FILE *f, long offs, uint8_t mask)
+{
+ uint8_t b;
+
+ if (fseek(f, offs, SEEK_SET))
+ return false;
+
+ if (fread(&b, 1, 1, f) != 1)
+ return false;
+
+ b ^= mask;
+
+ if (fseek(f, offs, SEEK_SET))
+ return false;
+
+ if (fwrite(&b, 1, 1, f) != 1)
+ return false;
+
+ return true;
}
static void load_fake_ta(ADBG_Case_t *c)
@@ -566,49 +611,64 @@
TEEC_Session session = { 0 };
TEEC_Result res;
uint32_t ret_orig;
- FILE *fsrc;
- FILE *fdst;
bool r;
- size_t n;
- fsrc = open_ta_file(&create_fail_test_ta_uuid, NULL, "r");
- if (!ADBG_EXPECT_NOT_NULL(c, fsrc))
- return;
- fdst = open_ta_file(&fake_uuid, NULL, "w");
- if (!ADBG_EXPECT_NOT_NULL(c, fdst)) {
- fclose(fsrc);
- return;
- }
- r = copy_file(fsrc, fdst);
- fclose(fsrc);
- fclose(fdst);
+ r = copy_file(&create_fail_test_ta_uuid, NULL, &fake_uuid, NULL);
if (ADBG_EXPECT_TRUE(c, r)) {
- /*
- * Run this several times to see that there's no memory leakage.
- */
- for (n = 0; n < 10; n++) {
- Do_ADBG_Log("n = %zu", n);
- res = xtest_teec_open_session(&session, &fake_uuid,
- NULL, &ret_orig);
- if (res == TEEC_SUCCESS)
- TEEC_CloseSession(&session);
- if (!ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_SECURITY,
- res))
- break;
- }
+ res = xtest_teec_open_session(&session, &fake_uuid, NULL,
+ &ret_orig);
+ if (res == TEEC_SUCCESS)
+ TEEC_CloseSession(&session);
+ ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_SECURITY, res);
}
ADBG_EXPECT_TRUE(c, rm_file(&fake_uuid, NULL));
}
+static bool load_corrupt_ta(ADBG_Case_t *c, long offs, uint8_t mask)
+{
+ TEEC_Session session = { 0 };
+ TEEC_Result res;
+ uint32_t ret_orig;
+ FILE *f;
+ bool r;
+
+ r = copy_file(&create_fail_test_ta_uuid, NULL,
+ &create_fail_test_ta_uuid, "save");
+ if (!ADBG_EXPECT_TRUE(c, r)) {
+ rm_file(&create_fail_test_ta_uuid, "save");
+ return false;
+ }
+
+ f = open_ta_file(&create_fail_test_ta_uuid, NULL, "r+");
+ if (!ADBG_EXPECT_NOT_NULL(c, f)) {
+ rm_file(&create_fail_test_ta_uuid, "save");
+ return false;
+ }
+ r = corrupt_file(f, offs, mask);
+ fclose(f);
+
+ if (ADBG_EXPECT_TRUE(c, r)) {
+ res = xtest_teec_open_session(&session,
+ &create_fail_test_ta_uuid,
+ NULL, &ret_orig);
+ if (res == TEEC_SUCCESS)
+ TEEC_CloseSession(&session);
+ r &= ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_SECURITY, res);
+ }
+
+ r &= ADBG_EXPECT_TRUE(c, rename_file(&create_fail_test_ta_uuid, "save",
+ &create_fail_test_ta_uuid, NULL));
+ return r;
+}
+
static void xtest_tee_test_1008(ADBG_Case_t *c)
{
TEEC_Session session = { 0 };
TEEC_Session session_crypt = { 0 };
uint32_t ret_orig;
-
Do_ADBG_BeginSubCase(c, "Invoke command");
{
(void)ADBG_EXPECT_TEEC_SUCCESS(c,
@@ -677,6 +737,26 @@
load_fake_ta(c);
Do_ADBG_EndSubCase(c, "Load fake uuid TA");
+ Do_ADBG_BeginSubCase(c, "Load corrupt TA");
+ ADBG_EXPECT_TRUE(c,
+ load_corrupt_ta(c, offsetof(struct shdr, magic), 1));
+ ADBG_EXPECT_TRUE(c,
+ load_corrupt_ta(c, offsetof(struct shdr, img_type), 1));
+ ADBG_EXPECT_TRUE(c,
+ load_corrupt_ta(c, offsetof(struct shdr, img_size), 1));
+ ADBG_EXPECT_TRUE(c,
+ load_corrupt_ta(c, offsetof(struct shdr, algo), 1));
+ ADBG_EXPECT_TRUE(c,
+ load_corrupt_ta(c, offsetof(struct shdr, hash_size), 1));
+ ADBG_EXPECT_TRUE(c,
+ load_corrupt_ta(c, offsetof(struct shdr, sig_size), 1));
+ ADBG_EXPECT_TRUE(c,
+ load_corrupt_ta(c, sizeof(struct shdr), 1)); /* hash */
+ ADBG_EXPECT_TRUE(c,
+ load_corrupt_ta(c, sizeof(struct shdr) + 32, 1)); /* sig */
+ ADBG_EXPECT_TRUE(c, load_corrupt_ta(c, 3000, 1)); /* payload */
+ ADBG_EXPECT_TRUE(c, load_corrupt_ta(c, 30000, 1)); /* payload */
+ Do_ADBG_EndSubCase(c, "Load corrupt TA");
}
#ifdef USER_SPACE