blob: 76ed9746f5013266fb52a6151aae774aad3bd445 [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
*/
#include <compiler.h>
#include <kernel/pseudo_ta.h>
#include <kernel/panic.h>
#include <mm/core_memprot.h>
#include <pta_invoke_tests.h>
#include <string.h>
#include <tee/cache.h>
#include <tee_api_defines.h>
#include <tee_api_types.h>
#include <trace.h>
#include <types_ext.h>
#include "misc.h"
#define TA_NAME "invoke_tests.pta"
static TEE_Result test_trace(uint32_t param_types __unused,
TEE_Param params[TEE_NUM_PARAMS] __unused)
{
IMSG("pseudo TA \"%s\" says \"Hello world !\"", TA_NAME);
return TEE_SUCCESS;
}
static int test_v2p2v(void *va)
{
struct tee_ta_session *session;
paddr_t p;
void *v;
if (!va)
return 0;
if (tee_ta_get_current_session(&session))
panic();
p = virt_to_phys(va);
/* 0 is not a valid physical address */
if (!p)
return 1;
if (session->clnt_id.login == TEE_LOGIN_TRUSTED_APP) {
v = phys_to_virt(p, MEM_AREA_TA_VASPACE);
} else {
v = phys_to_virt(p, MEM_AREA_NSEC_SHM);
if (!v)
v = phys_to_virt(p, MEM_AREA_SDP_MEM);
if (!v)
v = phys_to_virt(p, MEM_AREA_SHM_VASPACE);
}
/*
* Return an error only the vaddr found mismatches input address.
* Finding a virtual address from a physical address cannot be painful
* in some case (i.e pager). Moreover this operation is more debug
* related. Thus do not report error if phys_to_virt failed
*/
if (v && va != v) {
EMSG("Failed to p2v/v2p on caller TA memref arguments");
EMSG("va %p -> pa 0x%" PRIxPA " -> va %p", va, p, v);
return 1;
}
return 0;
}
/*
* Supported tests on parameters
* (I, J, K, L refer to param index)
*
* Case 1: command parameters type are: 1 in/out value, 3 empty.
* => process outI.a = inI.a + inI.b
* Case 2: command parameters type are: 3 input value, 1 output value
* => process = outI.a = inJ.a + inK.a + inL.a
* Case 3: command parameters type are: 1 in/out memref, 3 empty.
* => process = outI[0] = sum(inI[0..len-1])
*/
static TEE_Result test_entry_params(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
{
size_t i;
uint8_t d8, *in;
/* case 1a: 1 input/output value argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_INOUT) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
p[0].value.a = p[0].value.a + p[0].value.b;
return TEE_SUCCESS;
}
/* case 1b: 1 input/output value argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_INOUT) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
p[1].value.a = p[1].value.a + p[1].value.b;
return TEE_SUCCESS;
}
/* case 1c: 1 input/output value argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_INOUT) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
p[2].value.a = p[2].value.a + p[2].value.b;
return TEE_SUCCESS;
}
/* case 1d: 1 input/output value argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_INOUT)) {
p[3].value.a = p[3].value.a + p[3].value.b;
return TEE_SUCCESS;
}
/* case 2a: 3 input value arguments, 1 output value argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_OUTPUT) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_INPUT)) {
p[0].value.a = p[1].value.a + p[2].value.a + p[3].value.a;
p[0].value.b = p[1].value.b + p[2].value.b + p[3].value.b;
return TEE_SUCCESS;
}
/* case 2a: 3 input value arguments, 1 output value argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_OUTPUT) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_INPUT)) {
p[1].value.a = p[0].value.a + p[2].value.a + p[3].value.a;
p[1].value.b = p[0].value.b + p[2].value.b + p[3].value.b;
return TEE_SUCCESS;
}
/* case 2a: 3 input value arguments, 1 output value argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_OUTPUT) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_INPUT)) {
p[2].value.a = p[0].value.a + p[1].value.a + p[3].value.a;
p[2].value.b = p[0].value.b + p[1].value.b + p[3].value.b;
return TEE_SUCCESS;
}
/* case 2a: 3 input value arguments, 1 output value argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_INPUT) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_OUTPUT)) {
p[3].value.a = p[0].value.a + p[1].value.a + p[2].value.a;
p[3].value.b = p[0].value.b + p[1].value.b + p[2].value.b;
return TEE_SUCCESS;
}
DMSG("expect memref params: %p/%" PRIu32 " - %p/%" PRIu32 "zu - %p/%" PRIu32 "zu - %p/%" PRIu32 "zu",
p[0].memref.buffer, p[0].memref.size,
p[1].memref.buffer, p[1].memref.size,
p[2].memref.buffer, p[2].memref.size,
p[3].memref.buffer, p[3].memref.size);
/* case 3a: 1 in/out memref argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_MEMREF_INOUT) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
in = (uint8_t *)p[0].memref.buffer;
if (test_v2p2v(in))
return TEE_ERROR_SECURITY;
d8 = 0;
for (i = 0; i < p[0].memref.size; i++)
d8 += in[i];
*(uint8_t *)p[0].memref.buffer = d8;
return TEE_SUCCESS;
}
/* case 3b: 1 in/out memref argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_MEMREF_INOUT) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
in = (uint8_t *)p[1].memref.buffer;
if (test_v2p2v(in))
return TEE_ERROR_SECURITY;
d8 = 0;
for (i = 0; i < p[1].memref.size; i++)
d8 += in[i];
*(uint8_t *)p[1].memref.buffer = d8;
return TEE_SUCCESS;
}
/* case 3c: 1 in/out memref argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_MEMREF_INOUT) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
in = (uint8_t *)p[2].memref.buffer;
if (test_v2p2v(in))
return TEE_ERROR_SECURITY;
d8 = 0;
for (i = 0; i < p[2].memref.size; i++)
d8 += in[i];
*(uint8_t *)p[2].memref.buffer = d8;
return TEE_SUCCESS;
}
/* case 3d: 1 in/out memref argument */
if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_MEMREF_INOUT)) {
in = (uint8_t *)p[3].memref.buffer;
if (test_v2p2v(in))
return TEE_ERROR_SECURITY;
d8 = 0;
for (i = 0; i < p[3].memref.size; i++)
d8 += in[i];
*(uint8_t *)p[3].memref.buffer = d8;
return TEE_SUCCESS;
}
EMSG("unexpected parameters");
return TEE_ERROR_BAD_PARAMETERS;
}
/*
* Test access to Secure Data Path memory from pseudo TAs
*/
static TEE_Result test_inject_sdp(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
{
char *src = p[0].memref.buffer;
char *dst = p[1].memref.buffer;
size_t sz = p[0].memref.size;
uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
TEE_PARAM_TYPE_MEMREF_OUTPUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE);
if (exp_pt != type) {
DMSG("bad parameter types");
return TEE_ERROR_BAD_PARAMETERS;
}
if (p[1].memref.size < sz) {
p[1].memref.size = sz;
return TEE_ERROR_SHORT_BUFFER;
}
if (!core_vbuf_is(CORE_MEM_NON_SEC, src, sz) ||
!core_vbuf_is(CORE_MEM_SDP_MEM, dst, sz)) {
DMSG("bad memref secure attribute");
return TEE_ERROR_BAD_PARAMETERS;
}
if (!sz)
return TEE_SUCCESS;
/* Check that core can p2v and v2p over memory reference arguments */
if (test_v2p2v(src) || test_v2p2v(src + sz - 1) ||
test_v2p2v(dst) || test_v2p2v(dst + sz - 1))
return TEE_ERROR_SECURITY;
if (cache_operation(TEE_CACHEFLUSH, dst, sz) != TEE_SUCCESS)
return TEE_ERROR_GENERIC;
memcpy(dst, src, sz);
if (cache_operation(TEE_CACHEFLUSH, dst, sz) != TEE_SUCCESS)
return TEE_ERROR_GENERIC;
return TEE_SUCCESS;
}
static TEE_Result test_transform_sdp(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
{
char *buf = p[0].memref.buffer;
size_t sz = p[0].memref.size;
uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE);
if (exp_pt != type) {
DMSG("bad parameter types");
return TEE_ERROR_BAD_PARAMETERS;
}
if (!core_vbuf_is(CORE_MEM_SDP_MEM, buf, sz)) {
DMSG("bad memref secure attribute");
return TEE_ERROR_BAD_PARAMETERS;
}
if (!sz)
return TEE_SUCCESS;
/* Check that core can p2v and v2p over memory reference arguments */
if (test_v2p2v(buf) || test_v2p2v(buf + sz - 1))
return TEE_ERROR_SECURITY;
if (cache_operation(TEE_CACHEFLUSH, buf, sz) != TEE_SUCCESS)
return TEE_ERROR_GENERIC;
for (; sz; sz--, buf++)
*buf = ~(*buf) + 1;
if (cache_operation(TEE_CACHEFLUSH, buf, sz) != TEE_SUCCESS)
return TEE_ERROR_GENERIC;
return TEE_SUCCESS;
}
static TEE_Result test_dump_sdp(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
{
char *src = p[0].memref.buffer;
char *dst = p[1].memref.buffer;
size_t sz = p[0].memref.size;
uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
TEE_PARAM_TYPE_MEMREF_OUTPUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE);
if (exp_pt != type) {
DMSG("bad parameter types");
return TEE_ERROR_BAD_PARAMETERS;
}
if (p[1].memref.size < sz) {
p[1].memref.size = sz;
return TEE_ERROR_SHORT_BUFFER;
}
if (!core_vbuf_is(CORE_MEM_SDP_MEM, src, sz) ||
!core_vbuf_is(CORE_MEM_NON_SEC, dst, sz)) {
DMSG("bad memref secure attribute");
return TEE_ERROR_BAD_PARAMETERS;
}
if (!sz)
return TEE_SUCCESS;
/* Check that core can p2v and v2p over memory reference arguments */
if (test_v2p2v(src) || test_v2p2v(src + sz - 1) ||
test_v2p2v(dst) || test_v2p2v(dst + sz - 1))
return TEE_ERROR_SECURITY;
if (cache_operation(TEE_CACHEFLUSH, dst, sz) != TEE_SUCCESS)
return TEE_ERROR_GENERIC;
memcpy(dst, src, sz);
if (cache_operation(TEE_CACHEFLUSH, dst, sz) != TEE_SUCCESS)
return TEE_ERROR_GENERIC;
return TEE_SUCCESS;
}
/*
* Trusted Application Entry Points
*/
static TEE_Result create_ta(void)
{
DMSG("create entry point for pseudo TA \"%s\"", TA_NAME);
return TEE_SUCCESS;
}
static void destroy_ta(void)
{
DMSG("destroy entry point for pseudo ta \"%s\"", TA_NAME);
}
static TEE_Result open_session(uint32_t nParamTypes __unused,
TEE_Param pParams[TEE_NUM_PARAMS] __unused,
void **ppSessionContext __unused)
{
DMSG("open entry point for pseudo ta \"%s\"", TA_NAME);
return TEE_SUCCESS;
}
static void close_session(void *pSessionContext __unused)
{
DMSG("close entry point for pseudo ta \"%s\"", TA_NAME);
}
static TEE_Result invoke_command(void *pSessionContext __unused,
uint32_t nCommandID, uint32_t nParamTypes,
TEE_Param pParams[TEE_NUM_PARAMS])
{
FMSG("command entry point for pseudo ta \"%s\"", TA_NAME);
switch (nCommandID) {
case PTA_INVOKE_TESTS_CMD_TRACE:
return test_trace(nParamTypes, pParams);
case PTA_INVOKE_TESTS_CMD_PARAMS:
return test_entry_params(nParamTypes, pParams);
case PTA_INVOKE_TESTS_CMD_COPY_NSEC_TO_SEC:
return test_inject_sdp(nParamTypes, pParams);
case PTA_INVOKE_TESTS_CMD_READ_MODIFY_SEC:
return test_transform_sdp(nParamTypes, pParams);
case PTA_INVOKE_TESTS_CMD_COPY_SEC_TO_NSEC:
return test_dump_sdp(nParamTypes, pParams);
case PTA_INVOKE_TESTS_CMD_SELF_TESTS:
return core_self_tests(nParamTypes, pParams);
#if defined(CFG_WITH_USER_TA)
case PTA_INVOKE_TESTS_CMD_FS_HTREE:
return core_fs_htree_tests(nParamTypes, pParams);
#endif
case PTA_INVOKE_TESTS_CMD_MUTEX:
return core_mutex_tests(nParamTypes, pParams);
case PTA_INVOKE_TESTS_CMD_LOCKDEP:
return core_lockdep_tests(nParamTypes, pParams);
default:
break;
}
return TEE_ERROR_BAD_PARAMETERS;
}
pseudo_ta_register(.uuid = PTA_INVOKE_TESTS_UUID, .name = TA_NAME,
.flags = PTA_DEFAULT_FLAGS | TA_FLAG_SECURE_DATA_PATH |
TA_FLAG_CONCURRENT | TA_FLAG_DEVICE_ENUM,
.create_entry_point = create_ta,
.destroy_entry_point = destroy_ta,
.open_session_entry_point = open_session,
.close_session_entry_point = close_session,
.invoke_command_entry_point = invoke_command);