aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSummer Qin <summer.qin@arm.com>2018-09-26 17:10:41 +0800
committerEdison Ai <edison.ai@arm.com>2019-01-26 10:31:44 +0800
commit2bfd2a0e786217c9043b703f0eb773c0ab240d7d (patch)
tree712004835c8d75f34b3ec5fc0d919faf9f9ad885
parentc74f11c251c9b69db22694c45320158fc176717b (diff)
downloadtrusted-firmware-m-2bfd2a0e786217c9043b703f0eb773c0ab240d7d.tar.gz
Core: Add memory check function for IPC
In IPC, memory data could come from secure or non-secure side, and the added function will check the memory limit for both of them. It is used to check the parameter(memory reference) for IPC client and service APIs. Change-Id: If2a19a29e489267f2be935abac60764777736a12 Signed-off-by: Summer Qin <summer.qin@arm.com>
-rw-r--r--secure_fw/core/ipc/include/tfm_internal_defines.h1
-rw-r--r--secure_fw/core/ipc/include/tfm_spm.h13
-rw-r--r--secure_fw/core/ipc/tfm_spm.c82
3 files changed, 96 insertions, 0 deletions
diff --git a/secure_fw/core/ipc/include/tfm_internal_defines.h b/secure_fw/core/ipc/include/tfm_internal_defines.h
index 625b80cd56..a5382c5780 100644
--- a/secure_fw/core/ipc/include/tfm_internal_defines.h
+++ b/secure_fw/core/ipc/include/tfm_internal_defines.h
@@ -12,6 +12,7 @@
#define IPC_ERROR_BAD_PARAMETERS (INT32_MIN)
#define IPC_ERROR_SHORT_BUFFER (INT32_MIN + 1)
#define IPC_ERROR_VERSION (INT32_MIN + 2)
+#define IPC_ERROR_MEMORY_CHECK (INT32_MIN + 3)
#define IPC_ERROR_GENERIC (INT32_MIN + 0x1F)
#endif
diff --git a/secure_fw/core/ipc/include/tfm_spm.h b/secure_fw/core/ipc/include/tfm_spm.h
index a475b89f12..e9e18d04d4 100644
--- a/secure_fw/core/ipc/include/tfm_spm.h
+++ b/secure_fw/core/ipc/include/tfm_spm.h
@@ -273,6 +273,19 @@ int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
uint32_t minor_version);
+/**
+ * \brief Check the memory reference is valid.
+ *
+ * \param[in] buffer Pointer of memory reference
+ * \param[in] len Length of memory reference in bytes
+ * \param[in] ns_caller From non-secure caller
+ *
+ * \retval IPC_SUCCESS Success
+ * \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
+ * \retval IPC_ERROR_MEMORY_CHECK Check failed
+ */
+int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller);
+
/* This function should be called before schedule function */
void tfm_spm_init(void);
diff --git a/secure_fw/core/ipc/tfm_spm.c b/secure_fw/core/ipc/tfm_spm.c
index 56e05e98db..86e047e670 100644
--- a/secure_fw/core/ipc/tfm_spm.c
+++ b/secure_fw/core/ipc/tfm_spm.c
@@ -5,6 +5,7 @@
*
*/
#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -22,6 +23,7 @@
#include "tfm_spm.h"
#include "tfm_spm_signal_defs.h"
#include "tfm_thread.h"
+#include "region_defs.h"
#include "tfm_nspm.h"
/*
@@ -455,6 +457,86 @@ static uint32_t tfm_spm_partition_get_priority_ext(uint32_t partition_idx)
partition_priority;
}
+/* Macros to pick linker symbols and allow references to sections in all level*/
+#define REGION_DECLARE_EXT(a, b, c) extern uint32_t REGION_NAME(a, b, c)
+
+REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$Base);
+REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$Limit);
+REGION_DECLARE_EXT(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
+REGION_DECLARE_EXT(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
+REGION_DECLARE_EXT(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+REGION_DECLARE_EXT(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+/*
+ * \brief Check the memory whether in the given range.
+ *
+ * \param[in] buffer Pointer of memory reference
+ * \param[in] len Length of memory reference in bytes
+ * \param[in] base The base address
+ * \param[in] limit The limit address, the first byte of next
+ * area memory
+ *
+ * \retval IPC_SUCCESS Success
+ * \retval IPC_ERROR_MEMORY_CHECK Check failed
+ */
+static int32_t memory_check_range(const void *buffer, size_t len,
+ uintptr_t base, uintptr_t limit)
+{
+ if (((uintptr_t)buffer >= base) &&
+ ((uintptr_t)((uint8_t *)buffer + len - 1) < limit)) {
+ return IPC_SUCCESS;
+ }
+ return IPC_ERROR_MEMORY_CHECK;
+}
+
+/* FixMe: This is only valid for TFM LVL 1 now */
+int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller)
+{
+ uintptr_t base, limit;
+
+ /* If len is zero, this indicates an empty buffer and base is ignored */
+ if (len == 0) {
+ return IPC_SUCCESS;
+ }
+
+ if (!buffer) {
+ return IPC_ERROR_BAD_PARAMETERS;
+ }
+
+ if ((uintptr_t)buffer > (UINTPTR_MAX - len)) {
+ return IPC_ERROR_MEMORY_CHECK;
+ }
+
+ if (ns_caller) {
+ base = (uintptr_t)NS_DATA_START;
+ limit = (uintptr_t)(NS_DATA_START + NS_DATA_SIZE);
+ if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+ return IPC_SUCCESS;
+ }
+ } else {
+ base = (uintptr_t)&REGION_NAME(Image$$, ER_TFM_DATA, $$Base);
+ limit = (uintptr_t)&REGION_NAME(Image$$, ER_TFM_DATA, $$Limit);
+ if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+ return IPC_SUCCESS;
+ }
+
+ base = (uintptr_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
+ limit = (uintptr_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
+ if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+ return IPC_SUCCESS;
+ }
+
+ base = (uintptr_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+ limit = (uintptr_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH,
+ $$ZI$$Limit);
+ if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+ return IPC_SUCCESS;
+ }
+ }
+
+ return IPC_ERROR_MEMORY_CHECK;
+}
+
/********************** SPM functions for thread mode ************************/
void tfm_spm_init(void)