From 8ed4b62dc0d65bcfbd8c2b61238c1babe7eed237 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 3 Mar 2020 13:52:50 -0800 Subject: [PATCH] syscalls: arm: Fix possible overflow in is_in_region function This function is widely used by functions that validate memory buffers. Macros used to check permissions, like Z_SYSCALL_MEMORY_READ and Z_SYSCALL_MEMORY_WRITE, use these functions to check that a pointers passed by user threads in a syscall. Signed-off-by: Flavio Ceolin --- .../core/aarch32/cortex_m/mpu/arm_mpu_v7_internal.h | 10 +++++++++- arch/arm/core/aarch32/cortex_m/mpu/nxp_mpu.c | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/arm/core/aarch32/cortex_m/mpu/arm_mpu_v7_internal.h b/arch/arm/core/aarch32/cortex_m/mpu/arm_mpu_v7_internal.h index cd82e8a0fda..08d903808c5 100644 --- a/arch/arm/core/aarch32/cortex_m/mpu/arm_mpu_v7_internal.h +++ b/arch/arm/core/aarch32/cortex_m/mpu/arm_mpu_v7_internal.h @@ -9,6 +9,8 @@ #define ZEPHYR_ARCH_ARM_CORE_AARCH32_CORTEX_M_MPU_ARM_MPU_V7_INTERNAL_H_ +#include + #define LOG_LEVEL CONFIG_MPU_LOG_LEVEL #include @@ -200,6 +202,7 @@ static inline int is_in_region(u32_t r_index, u32_t start, u32_t size) u32_t r_addr_start; u32_t r_size_lshift; u32_t r_addr_end; + u32_t end; /* Lock IRQs to ensure RNR value is correct when reading RBAR, RASR. */ unsigned int key; @@ -216,7 +219,12 @@ static inline int is_in_region(u32_t r_index, u32_t start, u32_t size) MPU_RASR_SIZE_Pos) + 1; r_addr_end = r_addr_start + (1UL << r_size_lshift) - 1; - if (start >= r_addr_start && (start + size - 1) <= r_addr_end) { + size = size == 0 ? 0 : size - 1; + if (u32_add_overflow(start, size, &end)) { + return 0; + } + + if ((start >= r_addr_start) && (end <= r_addr_end)) { return 1; } diff --git a/arch/arm/core/aarch32/cortex_m/mpu/nxp_mpu.c b/arch/arm/core/aarch32/cortex_m/mpu/nxp_mpu.c index 3dcec2909c5..6451591e2a5 100644 --- a/arch/arm/core/aarch32/cortex_m/mpu/nxp_mpu.c +++ b/arch/arm/core/aarch32/cortex_m/mpu/nxp_mpu.c @@ -10,6 +10,7 @@ #include #include "arm_core_mpu_dev.h" #include +#include #include #define LOG_LEVEL CONFIG_MPU_LOG_LEVEL @@ -428,11 +429,17 @@ static inline int is_in_region(u32_t r_index, u32_t start, u32_t size) { u32_t r_addr_start; u32_t r_addr_end; + u32_t end; r_addr_start = SYSMPU->WORD[r_index][0]; r_addr_end = SYSMPU->WORD[r_index][1]; - if (start >= r_addr_start && (start + size - 1) <= r_addr_end) { + size = size == 0 ? 0 : size - 1; + if (u32_add_overflow(start, size, &end)) { + return 0; + } + + if ((start >= r_addr_start) && (end <= r_addr_end)) { return 1; }