Core: Add unpriv API to get caller client ID
Add tfm_core_get_caller_client_id(void) function to the unprivileged
TF-M core API. This function can only be called from secure partition.
Also add test case to test this function in the positive core test
suite.
Change-Id: I8dcd07b62f7bf8e43258695283cbb719a9357e48
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
diff --git a/secure_fw/core/tfm_handler.c b/secure_fw/core/tfm_handler.c
index 2e8b805..3085d7b 100644
--- a/secure_fw/core/tfm_handler.c
+++ b/secure_fw/core/tfm_handler.c
@@ -27,6 +27,9 @@
tfm_core_validate_secure_caller_handler(const uint32_t svc_args[]);
extern void
+ tfm_core_get_caller_client_id_handler(const uint32_t svc_args[]);
+
+extern void
tfm_core_memory_permission_check_handler(const uint32_t svc_args[]);
/* This SVC handler is called when a secure partition requests access to a
@@ -169,6 +172,9 @@
case TFM_SVC_VALIDATE_SECURE_CALLER:
tfm_core_validate_secure_caller_handler(svc_args);
break;
+ case TFM_SVC_GET_CALLER_CLIENT_ID:
+ tfm_core_get_caller_client_id_handler(svc_args);
+ break;
case TFM_SVC_MEMORY_CHECK:
tfm_core_memory_permission_check_handler(svc_args);
break;
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index 34af9a8..5491386 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -10,6 +10,7 @@
#include <stdbool.h>
#include "cmsis.h"
#include "tfm_secure_api.h"
+#include "tfm_nspm.h"
#include "secure_utilities.h"
#include "uart_stdout.h"
#include "secure_fw/spm/spm_api.h"
@@ -89,6 +90,8 @@
uint32_t partition_state;
uint32_t partition_flags;
struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
+ uint32_t caller_partition_id;
+ int32_t client_id;
/* Check partition idx validity */
if (caller_partition_idx == SPM_INVALID_PARTITION_IDX) {
@@ -119,10 +122,11 @@
curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
partition_state = curr_part_data->partition_state;
partition_flags = tfm_spm_partition_get_flags(partition_idx);
+ caller_partition_id = tfm_spm_partition_get_partition_id(
+ caller_partition_idx);
if ((tfm_secure_api_initializing) &&
- (tfm_spm_partition_get_partition_id(caller_partition_idx)
- == TFM_SP_CORE_ID) &&
+ (caller_partition_id == TFM_SP_CORE_ID) &&
(partition_state == SPM_PARTITION_STATE_UNINIT)) {
#if TFM_LVL != 1
/* Make thread mode unprivileged while untrusted partition init is
@@ -163,6 +167,18 @@
caller_partition_idx);
tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
+ if ((caller_flags&SPM_PART_FLAG_SECURE)) {
+ tfm_spm_partition_set_caller_client_id(partition_idx,
+ caller_partition_id);
+ } else {
+ client_id = tfm_nspm_get_current_client_id();
+ if (client_id >= 0)
+ {
+ return TFM_SECURE_LOCK_FAILED;
+ }
+ tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
+ }
+
#if (TFM_LVL != 1) && (TFM_LVL != 2)
/* Dynamic partitioning is only done is TFM level 3 */
tfm_spm_partition_sandbox_deconfig(caller_partition_idx);
@@ -461,6 +477,115 @@
}
svc_args[0] = res;
}
+/**
+ * \brief Check whether a buffer is ok for writing to by the privileged API
+ * function.
+ *
+ * This function checks whether the caller partition owns the buffer, can write
+ * to it, and the buffer has proper alignment.
+ *
+ * \param[in] partition_idx Partition index
+ * \param[in] start_addr The start address of the buffer
+ * \param[in] len The length of the buffer
+ * \param[in] alignment The expected alignment (in bits)
+ *
+ * \return 1 if the check passes, 0 otherwise.
+ *
+ * \note For a 0 long buffer the check fails.
+ */
+static int32_t check_buffer_access(uint32_t partition_idx,
+ void* start_addr, size_t len,
+ uint32_t alignment)
+{
+ uintptr_t start_addr_value = (uintptr_t)start_addr;
+ uintptr_t end_addr_value = (uintptr_t)start_addr + len;
+ uintptr_t alignment_mask;
+
+ alignment_mask = (((uintptr_t)1) << alignment) - 1;
+
+ /* Check that the pointer is aligned properly */
+ if (start_addr_value & alignment_mask) {
+ /* not aligned, return error */
+ return 0;
+ }
+
+ /* Protect against overflow (and zero len) */
+ if (end_addr_value <= start_addr_value)
+ {
+ return 0;
+ }
+
+#if TFM_LVL == 1
+ /* For privileged partition execution, all secure data memory and stack
+ * is accessible
+ */
+ if (start_addr_value >= S_DATA_START &&
+ end_addr_value <= (S_DATA_START + S_DATA_SIZE)) {
+ return 1;
+ }
+#else
+ /* For non-privileged execution the partition's data and stack is
+ * accessible
+ */
+ if (start_addr_value >=
+ tfm_spm_partition_get_stack_bottom(partition_idx) &&
+ end_addr_value <=
+ tfm_spm_partition_get_stack_top(partition_idx)) {
+ return 1;
+ }
+ if (start_addr_value >=
+ tfm_spm_partition_get_rw_start(partition_idx) &&
+ end_addr_value <=
+ tfm_spm_partition_get_rw_limit(partition_idx)) {
+ return 1;
+ }
+ if (start_addr_value >=
+ tfm_spm_partition_get_zi_start(partition_idx) &&
+ end_addr_value <=
+ tfm_spm_partition_get_zi_limit(partition_idx)) {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+void tfm_core_get_caller_client_id_handler(uint32_t *svc_args)
+{
+ uintptr_t result_ptr_value = svc_args[0];
+ uint32_t running_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ const uint32_t running_partition_flags =
+ tfm_spm_partition_get_flags(running_partition_idx);
+ const struct spm_partition_runtime_data_t *curr_part_data =
+ tfm_spm_partition_get_runtime_data(running_partition_idx);
+ int res = 0;
+
+ if (!(running_partition_flags&SPM_PART_FLAG_SECURE)) {
+ /* This handler shouldn't be called from outside partition context.
+ * Partitions are only allowed to run while S domain is locked.
+ */
+ svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
+ return;
+ }
+
+ /* Make sure that the output pointer points to a memory area that is owned
+ * by the partition
+ */
+ res = check_buffer_access(running_partition_idx,
+ (void*)result_ptr_value,
+ sizeof(curr_part_data->caller_client_id),
+ 2);
+ if (!res) {
+ /* Not in accessible range, return error */
+ svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
+ return;
+ }
+
+ *((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
+
+ /* Store return value in r0 */
+ svc_args[0] = TFM_SUCCESS;
+}
void tfm_core_memory_permission_check_handler(uint32_t *svc_args)
{
diff --git a/secure_fw/core/tfm_secure_api.h b/secure_fw/core/tfm_secure_api.h
index 3d4a9ae..25e76f8 100644
--- a/secure_fw/core/tfm_secure_api.h
+++ b/secure_fw/core/tfm_secure_api.h
@@ -73,6 +73,8 @@
extern int32_t tfm_core_validate_secure_caller(void);
+extern int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id);
+
extern int32_t tfm_core_memory_permission_check(
void *ptr, uint32_t size, int32_t access);
diff --git a/secure_fw/core/tfm_svc.h b/secure_fw/core/tfm_svc.h
index 419ee66..9c4d1a5 100644
--- a/secure_fw/core/tfm_svc.h
+++ b/secure_fw/core/tfm_svc.h
@@ -14,6 +14,7 @@
TFM_SVC_SFN_REQUEST = 0,
TFM_SVC_SFN_RETURN,
TFM_SVC_VALIDATE_SECURE_CALLER,
+ TFM_SVC_GET_CALLER_CLIENT_ID,
TFM_SVC_MEMORY_CHECK,
TFM_SVC_SET_SHARE_AREA,
TFM_SVC_PRINT,
diff --git a/secure_fw/core/tfm_unpriv_api.c b/secure_fw/core/tfm_unpriv_api.c
index ceac806..6817c36 100644
--- a/secure_fw/core/tfm_unpriv_api.c
+++ b/secure_fw/core/tfm_unpriv_api.c
@@ -109,6 +109,15 @@
}
__attribute__((naked))
+int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id)
+{
+ __ASM(
+ "SVC %0\n"
+ "BX LR\n"
+ : : "I" (TFM_SVC_GET_CALLER_CLIENT_ID));
+}
+
+__attribute__((naked))
int32_t tfm_core_validate_secure_caller(void)
{
__ASM(
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index ff68245..77bf5be 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -210,6 +210,30 @@
return g_spm_partition_db.partitions[partition_idx].memory_data.stack_top;
}
+uint32_t tfm_spm_partition_get_zi_start(uint32_t partition_idx)
+{
+ return g_spm_partition_db.partitions[partition_idx].
+ memory_data.zi_start;
+}
+
+uint32_t tfm_spm_partition_get_zi_limit(uint32_t partition_idx)
+{
+ return g_spm_partition_db.partitions[partition_idx].
+ memory_data.zi_limit;
+}
+
+uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx)
+{
+ return g_spm_partition_db.partitions[partition_idx].
+ memory_data.rw_start;
+}
+
+uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx)
+{
+ return g_spm_partition_db.partitions[partition_idx].
+ memory_data.rw_limit;
+}
+
void tfm_spm_partition_set_stack(uint32_t partition_idx, uint32_t stack_ptr)
{
g_spm_partition_db.partitions[partition_idx].
@@ -260,6 +284,13 @@
caller_partition_idx = caller_partition_idx;
}
+void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
+ int32_t caller_client_id)
+{
+ g_spm_partition_db.partitions[partition_idx].runtime_data.
+ caller_client_id = caller_client_id;
+}
+
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
uint32_t share)
{
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index 67cbfbf..f0034af 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -42,6 +42,7 @@
struct spm_partition_runtime_data_t {
uint32_t partition_state;
uint32_t caller_partition_idx;
+ int32_t caller_client_id;
uint32_t share;
uint32_t stack_ptr;
uint32_t lr;
@@ -125,6 +126,52 @@
uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx);
/**
+ * \brief Get the start of the zero-initialised region for a partition
+ *
+ * \param[in] partition_idx Partition idx
+ *
+ * \return Start of the zero-initialised region
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ */
+uint32_t tfm_spm_partition_get_zi_start(uint32_t partition_idx);
+
+/**
+ * \brief Get the limit of the zero-initialised region for a partition
+ *
+ * \param[in] partition_idx Partition idx
+ *
+ * \return Limit of the zero-initialised region
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ * \note The address returned is not part of the region.
+ */
+uint32_t tfm_spm_partition_get_zi_limit(uint32_t partition_idx);
+
+/**
+ * \brief Get the start of the read-write region for a partition
+ *
+ * \param[in] partition_idx Partition idx
+ *
+ * \return Start of the read-write region
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ */
+uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx);
+
+/**
+ * \brief Get the limit of the read-write region for a partition
+ *
+ * \param[in] partition_idx Partition idx
+ *
+ * \return Limit of the read-write region
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ * \note The address returned is not part of the region.
+ */
+uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx);
+
+/**
* \brief Get the current runtime data of a partition
*
* \param[in] partition_idx Partition index
@@ -189,6 +236,17 @@
uint32_t caller_partition_idx);
/**
+* \brief Set the caller client ID for a given partition
+*
+* \param[in] partition_idx Partition index
+* \param[in] caller_client_id The ID of the calling client
+*
+* \note This function doesn't check if any of the partition_idxs are valid.
+*/
+void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
+ int32_t caller_client_id);
+
+/**
* \brief Set the buffer share region of the partition
*
* \param[in] partition_idx Partition index