Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ set(MBR_HEX ${SOFTDEVICE_DIR}/mbr/hex/mbr_nrf52_2.4.1_mbr.hex)
set(TINYUSB_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/tinyusb/src)
set(TCRYPT_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/tinycrypt/lib)

option(SKIP_FLASH_PROT "Skip enabling MBR/BL FLASH overwrite protection from user application" OFF)
option(DEFAULT_TO_OTA_DFU "Default to OTA DFU instead of Serial DFU" OFF)
option(SIGNED_FW "Enable signed firmware verification" OFF)
option(DUALBANK_FW "Enable dual bank DFU support" OFF)
Expand Down Expand Up @@ -201,6 +202,10 @@ if (DEFAULT_TO_OTA_DFU)
target_compile_definitions(bootloader PUBLIC DEFAULT_TO_OTA_DFU)
endif ()

if (SKIP_FLASH_PROT)
target_compile_definitions(bootloader PUBLIC SKIP_FLASH_PROT)
endif ()

if (TRACE_ETM STREQUAL "1")
# ENABLE_TRACE will cause system_nrf5x.c to set up ETM trace
target_compile_definitions(bootloader PUBLIC ENABLE_TRACE)
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# - DUALBANK_FW : If bootloader will implement a dual bank feature to allow autorecover from failed
# - FORCE_UF2 : if SIGNED_FW is 1, will force to include UF2 support (UNSECURE, UF2 does NOT validate signature!)
# - DEFAULT_TO_OTA_DFU : if entering DFU, by default enter OTA DFU instead of Serial DFU
# - SKIP_FLASH_PROT : Skip enabling protection against user application writing to FLASH MBR/Bootloader
#------------------------------------------------------------------------------

PYTHON = python
Expand Down Expand Up @@ -376,6 +377,10 @@ ifeq ($(DEFAULT_TO_OTA_DFU), 1)
CFLAGS += -DDEFAULT_TO_OTA_DFU
endif

ifeq ($(SKIP_FLASH_PROT), 1)
CFLAGS += -DSKIP_FLASH_PROT
endif

_VER = $(subst ., ,$(word 1, $(subst -, ,$(GIT_VERSION))))
CFLAGS += -DMK_BOOTLOADER_VERSION='($(word 1,$(_VER)) << 16) + ($(word 2,$(_VER)) << 8) + $(word 3,$(_VER))'

Expand Down
89 changes: 88 additions & 1 deletion lib/sdk11/components/libraries/bootloader_dfu/bootloader_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
*/

#include "bootloader_util.h"
#include "dfu_types.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>


/**
* @brief Function for aborting current application/bootloader jump to to other app/bootloader.
*
Expand Down Expand Up @@ -164,8 +165,94 @@ static inline void bootloader_util_reset(uint32_t start_addr)
#error Compiler not supported.
#endif

#ifndef SKIP_FLASH_PROT
uint32_t bootloader_util_flash_protect(uint32_t address, uint32_t size, bool read_protect)
{
if ((size & (CODE_PAGE_SIZE - 1)) || (address > BOOTLOADER_SETTINGS_ADDRESS))
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter validation logic has issues. First, it doesn't check if size is zero, which would cause incorrect behavior. Second, the address validation (address > BOOTLOADER_SETTINGS_ADDRESS) doesn't make sense for protecting the MBR at address 0. Consider validating that size > 0 and checking that address + size doesn't overflow or exceed valid flash memory bounds.

Suggested change
if ((size & (CODE_PAGE_SIZE - 1)) || (address > BOOTLOADER_SETTINGS_ADDRESS))
uint32_t end_addr = address + size;
if ((size == 0) ||
(size & (CODE_PAGE_SIZE - 1)) ||
(end_addr < address) ||
(address > BOOTLOADER_SETTINGS_ADDRESS))

Copilot uses AI. Check for mistakes.
{
return NRF_ERROR_INVALID_PARAM;
}

#if defined(ACL_PRESENT)

// Protect using ACL.
static uint32_t acl_instance = 0;

uint32_t const wmask = (ACL_ACL_PERM_WRITE_Disable << ACL_ACL_PERM_WRITE_Pos);
uint32_t const rwmask = wmask | (ACL_ACL_PERM_READ_Disable << ACL_ACL_PERM_READ_Pos);
uint32_t const mask = read_protect ? rwmask: wmask;

do
{
if (acl_instance >= ACL_REGIONS_COUNT)
{
return NRF_ERROR_NO_MEM;
}

NRF_ACL->ACL[acl_instance].ADDR = address;
NRF_ACL->ACL[acl_instance].SIZE = size;
NRF_ACL->ACL[acl_instance].PERM = mask;

acl_instance++;

} while (NRF_ACL->ACL[acl_instance - 1].ADDR != address
|| NRF_ACL->ACL[acl_instance - 1].SIZE != size
|| NRF_ACL->ACL[acl_instance - 1].PERM != mask); // Check whether the acl_instance has been used before.

#elif defined (BPROT_PRESENT)

// Protect using BPROT. BPROT does not support read protection.
uint32_t pagenum_start = address / CODE_PAGE_SIZE;
uint32_t pagenum_end = pagenum_start + ((size - 1) / CODE_PAGE_SIZE);

for (uint32_t i = pagenum_start; i <= pagenum_end; i++)
{
uint32_t config_index = i / 32;
uint32_t mask = (1 << (i - config_index * 32));

switch (config_index)
{
case 0:
NRF_BPROT->CONFIG0 = mask;
break;
case 1:
NRF_BPROT->CONFIG1 = mask;
break;
#if BPROT_REGIONS_NUM > 64
case 2:
NRF_BPROT->CONFIG2 = mask;
break;
case 3:
NRF_BPROT->CONFIG3 = mask;
break;
#endif
}
}

#endif

return NRF_SUCCESS;
}
#endif

void bootloader_util_app_start(uint32_t start_addr)
{

#ifndef SKIP_FLASH_PROT
uint32_t area_size;

// Protect MBR against user writes
bootloader_util_flash_protect(0, MBR_SIZE, false);

// Size of the bootloader flash area to protect (Bootloader + MBR params + Bootloader settings)
area_size = BOOTLOADER_SETTINGS_ADDRESS + CODE_PAGE_SIZE - BOOTLOADER_REGION_START;

// Protect bootloader code and params pages against user writes
bootloader_util_flash_protect(BOOTLOADER_REGION_START,
area_size,
false);
#endif

// Jump to user application
bootloader_util_reset(start_addr);
}