diff options
author | Summer Qin <summer.qin@arm.com> | 2018-09-26 17:10:41 +0800 |
---|---|---|
committer | Edison Ai <edison.ai@arm.com> | 2019-01-26 10:31:44 +0800 |
commit | 2bfd2a0e786217c9043b703f0eb773c0ab240d7d (patch) | |
tree | 712004835c8d75f34b3ec5fc0d919faf9f9ad885 | |
parent | c74f11c251c9b69db22694c45320158fc176717b (diff) | |
download | trusted-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.h | 1 | ||||
-rw-r--r-- | secure_fw/core/ipc/include/tfm_spm.h | 13 | ||||
-rw-r--r-- | secure_fw/core/ipc/tfm_spm.c | 82 |
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)®ION_NAME(Image$$, ER_TFM_DATA, $$Base); + limit = (uintptr_t)®ION_NAME(Image$$, ER_TFM_DATA, $$Limit); + if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) { + return IPC_SUCCESS; + } + + base = (uintptr_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base); + limit = (uintptr_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit); + if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) { + return IPC_SUCCESS; + } + + base = (uintptr_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base); + limit = (uintptr_t)®ION_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) |