BL2: Validate target access address in flash_map.c
Before accessing the target access address in flash_area_xxx
operation in flash_map.c, check whether the address is within
the size of the area.
Change-Id: I8a9a5f72b6a0a54b8f100d342c6868d7a8817733
Signed-off-by: Sherry Zhang <sherry.zhang2@arm.com>
diff --git a/bl2/src/flash_map.c b/bl2/src/flash_map.c
index 4286f86..ffb04ee 100644
--- a/bl2/src/flash_map.c
+++ b/bl2/src/flash_map.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -9,6 +9,7 @@
#include "target.h"
#include "flash_map/flash_map.h"
#include "flash_map_backend/flash_map_backend.h"
+#include "bootutil_priv.h"
#include "bootutil/bootutil_log.h"
#include "Driver_Flash.h"
@@ -94,6 +95,30 @@
static const int flash_map_entry_num = ARRAY_SIZE(flash_map);
/*
+ * Check the target address in the flash_area_xxx operation.
+ */
+static bool is_range_valid(const struct flash_area *area,
+ uint32_t off,
+ uint32_t len)
+{
+ uint32_t size;
+
+ if (!area) {
+ return false;
+ }
+
+ if (!boot_u32_safe_add(&size, off, len)) {
+ return false;
+ }
+
+ if (area->fa_size < size) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
* `open` a flash area. The `area` in this case is not the individual
* sectors, but describes the particular flash area in question.
*/
@@ -125,6 +150,11 @@
uint32_t len)
{
BOOT_LOG_DBG("read area=%d, off=%#x, len=%#x", area->fa_id, off, len);
+
+ if (!is_range_valid(area, off, len)) {
+ return -1;
+ }
+
return DRV_FLASH_AREA(area)->ReadData(area->fa_off + off, dst, len);
}
@@ -132,6 +162,11 @@
const void *src, uint32_t len)
{
BOOT_LOG_DBG("write area=%d, off=%#x, len=%#x", area->fa_id, off, len);
+
+ if (!is_range_valid(area, off, len)) {
+ return -1;
+ }
+
return DRV_FLASH_AREA(area)->ProgramData(area->fa_off + off, src, len);
}
@@ -142,6 +177,11 @@
int32_t rc = 0;
BOOT_LOG_DBG("erase area=%d, off=%#x, len=%#x", area->fa_id, off, len);
+
+ if (!is_range_valid(area, off, len)) {
+ return -1;
+ }
+
flash_info = DRV_FLASH_AREA(area)->GetInfo();
if (flash_info->sector_info == NULL) {