// SPDX-License-Identifier: BSD-2-Clause
|
/*
|
* Copyright (c) 2016, Linaro Limited
|
* All rights reserved.
|
*/
|
|
#include <pta_invoke_tests.h>
|
#include <string.h>
|
#include <ta_sdp_basic.h>
|
#include <tee_api.h>
|
#include <tee_internal_api_extensions.h>
|
#include <tee_internal_api.h>
|
#include <tee_ta_api.h>
|
#include <trace.h>
|
|
|
/*
|
* Basic Secure Data Path access test commands:
|
* - command INJECT: copy from non secure input into secure output.
|
* - command TRANSFROM: read, transform and write from/to secure in/out.
|
* - command DUMP: copy from secure input into non secure output.
|
*/
|
|
static TEE_Result cmd_inject(uint32_t types,
|
TEE_Param params[TEE_NUM_PARAMS])
|
{
|
TEE_Result rc = TEE_ERROR_GENERIC;
|
const int sec_idx = 1; /* highlight secure buffer index */
|
const int ns_idx = 0; /* highlight nonsecure buffer index */
|
|
if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
|
TEE_PARAM_TYPE_MEMREF_OUTPUT,
|
TEE_PARAM_TYPE_NONE,
|
TEE_PARAM_TYPE_NONE)) {
|
EMSG("bad parameters %x", (unsigned)types);
|
return TEE_ERROR_BAD_PARAMETERS;
|
}
|
|
if (params[sec_idx].memref.size < params[ns_idx].memref.size)
|
return TEE_ERROR_SHORT_BUFFER;
|
|
/*
|
* We could rely on the TEE to provide consistent buffer/size values
|
* to reference a buffer with a unique and consistent secure attribute
|
* value. Hence it is safe enough (and more optimal) to test only the
|
* secure attribute of a single byte of it. Yet, since the current
|
* test does not deal with performance, let check the secure attribute
|
* of each byte of the buffer.
|
*/
|
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
|
TEE_MEMORY_ACCESS_READ |
|
TEE_MEMORY_ACCESS_NONSECURE,
|
params[ns_idx].memref.buffer,
|
params[ns_idx].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CheckMemoryAccessRights(nsec) failed %x", rc);
|
return rc;
|
}
|
|
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
|
TEE_MEMORY_ACCESS_WRITE |
|
TEE_MEMORY_ACCESS_SECURE,
|
params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CheckMemoryAccessRights(secure) failed %x", rc);
|
return rc;
|
}
|
|
|
#ifdef CFG_CACHE_API
|
/*
|
* we should invalidate cache (here we assume buffer were not
|
* filled through cpu core caches. We flush buffers so that
|
* cache is not corrupted in cache target buffer not aligned
|
* on cache line size.
|
*/
|
rc = TEE_CacheFlush(params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
|
params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size, rc);
|
return rc;
|
}
|
#endif /* CFG_CACHE_API */
|
|
/* inject data */
|
TEE_MemMove(params[sec_idx].memref.buffer,
|
params[ns_idx].memref.buffer,
|
params[sec_idx].memref.size);
|
|
#ifdef CFG_CACHE_API
|
rc = TEE_CacheFlush(params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
|
params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size, rc);
|
return rc;
|
}
|
#endif /* CFG_CACHE_API */
|
|
return rc;
|
}
|
|
static TEE_Result cmd_transform(uint32_t types,
|
TEE_Param params[TEE_NUM_PARAMS])
|
{
|
TEE_Result rc = TEE_ERROR_GENERIC;
|
unsigned char *p = NULL;
|
size_t sz = 0;
|
|
if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
|
TEE_PARAM_TYPE_NONE,
|
TEE_PARAM_TYPE_NONE,
|
TEE_PARAM_TYPE_NONE))
|
return TEE_ERROR_BAD_PARAMETERS;
|
|
/*
|
* We could rely on the TEE to provide consistent buffer/size values
|
* to reference a buffer with a unique and consistent secure attribute
|
* value. Hence it is safe enough (and more optimal) to test only the
|
* secure attribute of a single byte of it. Yet, since the current
|
* test does not deal with performance, let check the secure attribute
|
* of each byte of the buffer.
|
*/
|
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
|
TEE_MEMORY_ACCESS_READ |
|
TEE_MEMORY_ACCESS_WRITE |
|
TEE_MEMORY_ACCESS_SECURE,
|
params[0].memref.buffer,
|
params[0].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CheckMemoryAccessRights(secure) failed %x", rc);
|
return rc;
|
}
|
|
|
#ifdef CFG_CACHE_API
|
/*
|
* we should invalidate cache (here we assume buffer were not
|
* filled through cpu core caches. We flush buffers so that
|
* cache is not corrupted in cache target buffer not aligned
|
* on cache line size.
|
*/
|
rc = TEE_CacheFlush(params[0].memref.buffer,
|
params[0].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
|
params[0].memref.buffer,
|
params[0].memref.size, rc);
|
return rc;
|
}
|
#endif /* CFG_CACHE_API */
|
|
/* transform the data */
|
p = (unsigned char *)params[0].memref.buffer;
|
sz = params[0].memref.size;
|
for (; sz; sz--, p++)
|
*p = ~(*p) + 1;
|
|
#ifdef CFG_CACHE_API
|
rc = TEE_CacheFlush(params[0].memref.buffer,
|
params[0].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
|
params[0].memref.buffer,
|
params[0].memref.size, rc);
|
return rc;
|
}
|
#endif /* CFG_CACHE_API */
|
|
return rc;
|
}
|
|
static TEE_Result cmd_dump(uint32_t types,
|
TEE_Param params[TEE_NUM_PARAMS])
|
{
|
TEE_Result rc = TEE_ERROR_GENERIC;
|
const int sec_idx = 0; /* highlight secure buffer index */
|
const int ns_idx = 1; /* highlight nonsecure buffer index */
|
|
if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
|
TEE_PARAM_TYPE_MEMREF_OUTPUT,
|
TEE_PARAM_TYPE_NONE,
|
TEE_PARAM_TYPE_NONE))
|
return TEE_ERROR_BAD_PARAMETERS;
|
|
if (params[ns_idx].memref.size < params[sec_idx].memref.size)
|
return TEE_ERROR_SHORT_BUFFER;
|
|
/*
|
* We could rely on the TEE to provide consistent buffer/size values
|
* to reference a buffer with a unique and consistent secure attribute
|
* value. Hence it is safe enough (and more optimal) to test only the
|
* secure attribute of a single byte of it. Yet, since the current
|
* test does not deal with performance, let check the secure attribute
|
* of each byte of the buffer.
|
*/
|
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
|
TEE_MEMORY_ACCESS_WRITE |
|
TEE_MEMORY_ACCESS_NONSECURE,
|
params[ns_idx].memref.buffer,
|
params[ns_idx].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CheckMemoryAccessRights(nsec) failed %x", rc);
|
return rc;
|
}
|
|
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
|
TEE_MEMORY_ACCESS_READ |
|
TEE_MEMORY_ACCESS_SECURE,
|
params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CheckMemoryAccessRights(secure) failed %x", rc);
|
return rc;
|
}
|
|
#ifdef CFG_CACHE_API
|
/*
|
* we should invalidate cache (here we assume buffer were not
|
* filled through cpu core caches. We flush buffers so that
|
* cache is not corrupted in cache target buffer not aligned
|
* on cache line size.
|
*/
|
rc = TEE_CacheFlush(params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size);
|
if (rc != TEE_SUCCESS) {
|
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
|
params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size, rc);
|
return rc;
|
}
|
#endif /* CFG_CACHE_API */
|
|
/* dump the data */
|
TEE_MemMove(params[ns_idx].memref.buffer,
|
params[sec_idx].memref.buffer,
|
params[sec_idx].memref.size);
|
|
return rc;
|
}
|
|
static TEE_Result cmd_invoke(uint32_t nParamTypes,
|
TEE_Param pParams[TEE_NUM_PARAMS],
|
uint32_t nCommandID)
|
{
|
const TEE_UUID uuid = TA_SDP_BASIC_UUID;
|
static TEE_TASessionHandle sess = TEE_HANDLE_NULL;
|
uint32_t ret_orig = 0;
|
TEE_Result res = TEE_ERROR_GENERIC;
|
|
if (sess == TEE_HANDLE_NULL) {
|
res = TEE_OpenTASession(&uuid, TEE_TIMEOUT_INFINITE, 0, NULL,
|
&sess, &ret_orig);
|
if (res != TEE_SUCCESS) {
|
EMSG("SDP basic test TA: TEE_OpenTASession() FAILED \n");
|
goto cleanup_return;
|
}
|
|
}
|
|
res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE,
|
nCommandID, nParamTypes, pParams, &ret_orig);
|
if (res != TEE_SUCCESS) {
|
EMSG("SDP basic test TA: TEE_OpenTASession() FAILED %x/%d\n",
|
res, ret_orig);
|
}
|
|
cleanup_return:
|
if (res != TEE_SUCCESS) {
|
TEE_CloseTASession(sess);
|
sess = TEE_HANDLE_NULL;
|
}
|
return res;
|
}
|
|
static TEE_Result cmd_invoke_pta(uint32_t nParamTypes,
|
TEE_Param pParams[TEE_NUM_PARAMS],
|
uint32_t nCommandID)
|
{
|
const TEE_UUID uuid = PTA_INVOKE_TESTS_UUID;
|
static TEE_TASessionHandle sess = TEE_HANDLE_NULL;
|
uint32_t ret_orig = 0;
|
TEE_Result res = TEE_ERROR_GENERIC;
|
|
if (sess == TEE_HANDLE_NULL) {
|
res = TEE_OpenTASession(&uuid, TEE_TIMEOUT_INFINITE, 0, NULL,
|
&sess, &ret_orig);
|
if (res != TEE_SUCCESS) {
|
EMSG("SDP basic test TA: TEE_OpenTASession() FAILED \n");
|
goto cleanup_return;
|
}
|
|
}
|
|
res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE,
|
nCommandID, nParamTypes, pParams, &ret_orig);
|
if (res != TEE_SUCCESS) {
|
EMSG("SDP basic test TA: TEE_OpenTASession() FAILED %x/%d\n",
|
res, ret_orig);
|
}
|
|
cleanup_return:
|
if (res != TEE_SUCCESS) {
|
TEE_CloseTASession(sess);
|
sess = TEE_HANDLE_NULL;
|
}
|
return res;
|
}
|
|
TEE_Result TA_CreateEntryPoint(void)
|
{
|
return TEE_SUCCESS;
|
}
|
|
void TA_DestroyEntryPoint(void)
|
{
|
}
|
|
TEE_Result TA_OpenSessionEntryPoint(uint32_t nParamTypes,
|
TEE_Param pParams[TEE_NUM_PARAMS],
|
void **ppSessionContext)
|
{
|
(void)nParamTypes;
|
(void)pParams;
|
(void)ppSessionContext;
|
return TEE_SUCCESS;
|
}
|
|
void TA_CloseSessionEntryPoint(void *pSessionContext)
|
{
|
(void)pSessionContext;
|
}
|
|
TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext,
|
uint32_t nCommandID, uint32_t nParamTypes,
|
TEE_Param pParams[TEE_NUM_PARAMS])
|
{
|
(void)pSessionContext;
|
|
switch (nCommandID) {
|
case TA_SDP_BASIC_CMD_INJECT:
|
return cmd_inject(nParamTypes, pParams);
|
case TA_SDP_BASIC_CMD_TRANSFORM:
|
return cmd_transform(nParamTypes, pParams);
|
case TA_SDP_BASIC_CMD_DUMP:
|
return cmd_dump(nParamTypes, pParams);
|
|
case TA_SDP_BASIC_CMD_INVOKE_INJECT:
|
return cmd_invoke(nParamTypes, pParams, TA_SDP_BASIC_CMD_INJECT);
|
case TA_SDP_BASIC_CMD_INVOKE_TRANSFORM:
|
return cmd_invoke(nParamTypes, pParams, TA_SDP_BASIC_CMD_TRANSFORM);
|
case TA_SDP_BASIC_CMD_INVOKE_DUMP:
|
return cmd_invoke(nParamTypes, pParams, TA_SDP_BASIC_CMD_DUMP);
|
|
case TA_SDP_BASIC_CMD_PTA_INJECT:
|
return cmd_invoke_pta(nParamTypes, pParams, PTA_INVOKE_TESTS_CMD_COPY_NSEC_TO_SEC);
|
case TA_SDP_BASIC_CMD_PTA_TRANSFORM:
|
return cmd_invoke_pta(nParamTypes, pParams, PTA_INVOKE_TESTS_CMD_READ_MODIFY_SEC);
|
case TA_SDP_BASIC_CMD_PTA_DUMP:
|
return cmd_invoke_pta(nParamTypes, pParams, PTA_INVOKE_TESTS_CMD_COPY_SEC_TO_NSEC);
|
|
default:
|
return TEE_ERROR_BAD_PARAMETERS;
|
}
|
}
|