Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
21c82fa
F-12883: nRF5340 uart_write CRLF dropped multiline tail data
danielinux Sep 18, 2026
bad0fa3
F-13635: isolate each diag_read_header content gate
danielinux Sep 18, 2026
f1aa75a
F-13633: test encrypt_key_is_valid erased-key rejection
danielinux Sep 18, 2026
bdfddc5
Add gpt_parse_header hdr_size bounds test (F-6759)
danielinux Sep 18, 2026
ba74601
F-13646: test HDR_CMDLINE sign/decode roundtrip
danielinux Sep 18, 2026
ef4d73d
Add header_required_size cross-branch regression test (F-13644)
danielinux Sep 18, 2026
03ea0bb
F-13636: unit target for NSC update-partition bounds checks
danielinux Sep 18, 2026
dfe7150
F-13623: nRF5340 hal_flash_protect lock the full requested range
danielinux Sep 18, 2026
59c47a8
F-13624: guard keygen-emitted keystore accessors against negative id
danielinux Sep 18, 2026
c62b509
F-9752: test interrupted per-sector swap resumes from BACKUP
danielinux Sep 18, 2026
963bec3
F-6874: test whFlashH5 Erase/Verify/BlankCheck OOB bounds guards
danielinux Sep 18, 2026
cf56410
F-9752: guard swap-resume test out of EXT_ENCRYPTED targets
danielinux Sep 18, 2026
f80dde6
F-9753: accept the exact-fit update size in wolfBoot_update
danielinux Sep 18, 2026
6cc8437
F-13643: test swap round-trip restores the original boot image
danielinux Sep 18, 2026
b0db2b7
F-13622: guard partition overlap with the bootloader write-protect re…
danielinux Sep 18, 2026
a2f7d8b
Fix nrf5340 link error + cypsoc6 partition-overlap false positive
danielinux Sep 18, 2026
f0b2665
Fix nrf5340 test-app link error: add nrf5340_uart.o to APP_OBJS
danielinux Sep 18, 2026
d45f344
Address Copilot review comments
danielinux Sep 18, 2026
80af0bf
Fix CI: partition-guard extents, duplicate nrf5340 object, opt-out reach
danielinux Sep 18, 2026
ac519da
Address 3 Fenrir findings on PR 905
danielinux Sep 18, 2026
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
17 changes: 16 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,14 @@ list(APPEND WOLFBOOT_DEFS
WOLFBOOT_ORIGIN=${WOLFBOOT_ORIGIN}
BOOTLOADER_PARTITION_SIZE=${BOOTLOADER_PARTITION_SIZE})

# Opt-out for targets that deliberately place a partition inside the
# bootloader write-protect region (e.g. cypsoc6). Mirrors the GNU Make
# WOLFBOOT_ALLOW_PART_OVERLAP flag; without it the geometry guards in
# include/target.h fire on those layouts.
if(WOLFBOOT_ALLOW_PART_OVERLAP)
list(APPEND WOLFBOOT_DEFS WOLFBOOT_ALLOW_PART_OVERLAP=1)
endif()

if(${WOLFBOOT_TARGET} STREQUAL "x86_64_efi")
if(NOT DEFINED GNU_EFI_LIB_PATH)
set(GNU_EFI_LIB_PATH /usr/lib)
Expand Down Expand Up @@ -1156,8 +1164,15 @@ if(TZEN)
endif()
endif()

# nRF5340 debug-UART CRLF conversion (host-testable, no nrfx registers)
set(WOLFBOOT_NRF5340_UART_SRC "")
if(WOLFBOOT_TARGET MATCHES "^nrf5340")
set(WOLFBOOT_NRF5340_UART_SRC hal/nrf5340_uart.c)
endif()

target_sources(wolfboothal PRIVATE include/hal.h hal/hal.c hal/${WOLFBOOT_TARGET}.c ${WOLFBOOT_FLASH_SOURCES}
${PARTITION_SOURCE} ${WOLFBOOT_TZ_HAL_SOURCES})
${PARTITION_SOURCE} ${WOLFBOOT_TZ_HAL_SOURCES}
${WOLFBOOT_NRF5340_UART_SRC})


#---------------------------------------------------------------------------------------------
Expand Down
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ override WOLFHSM_MICROCHIP_PIC32CZ := $(abspath $(WOLFHSM_MICROCHIP_PIC32CZ))
export WOLFHSM_MICROCHIP_PIC32CZ

CFLAGS:=-D"__WOLFBOOT"
ifeq ($(WOLFBOOT_ALLOW_PART_OVERLAP),1)
CFLAGS+=-DWOLFBOOT_ALLOW_PART_OVERLAP=1
endif
Comment thread
danielinux marked this conversation as resolved.
# gcc/clang warning flags; the TI cl2000 driver (ARCH=C2000) rejects them.
ifneq ($(ARCH),C2000)
CFLAGS+=-Werror -Wextra -Wno-array-bounds
Expand Down Expand Up @@ -75,6 +78,12 @@ ifneq ($(TARGET),library)
else
OBJS+=./hal/$(TARGET).o
endif
# nRF5340 debug-UART CRLF conversion (host-testable, no nrfx registers)
ifneq ($(filter nrf5340%, $(TARGET)),)
ifeq ($(DEBUG_UART),1)
OBJS+=./hal/nrf5340_uart.o
endif
endif
endif

# User-provided key configuration
Expand Down
8 changes: 8 additions & 0 deletions config/examples/cypsoc6.config
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,11 @@ WOLFBOOT_SECTOR_SIZE?=512
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x10080000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x10100000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x10010000

# cypsoc6 places the swap sector (0x10010000) inside the bootloader
# write-protect region [0x10000000, 0x10080000). This is a deliberate
# peculiarity of this target: hal_flash_protect() is the weak no-op
# (psoc6 does not override it), so the overlap is harmless at runtime.
# Allow the overlap so the partition-geometry #error guards in
# include/target.h.in do not fire for this config.
WOLFBOOT_ALLOW_PART_OVERLAP = 1
52 changes: 30 additions & 22 deletions hal/nrf5340.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,27 +282,14 @@ void uart_write_sz(const char* c, unsigned int sz)
}
}

/* CRLF conversion lives in nrf5340_uart.c so it can be unit-tested on the
* host without the nrfx register access the rest of this HAL needs. */
void nrf5340_uart_crlf(const char* buf, unsigned int sz,
void (*sink)(const char*, unsigned int));

void uart_write(const char* buf, unsigned int sz)
{
const char* line;
unsigned int lineSz;
do {
/* find `\n` */
line = memchr(buf, '\n', sz);
if (line == NULL) {
uart_write_sz(buf, sz);
break;
}
lineSz = line - buf;
if (lineSz > sz-1)
lineSz = sz-1;

uart_write_sz(buf, lineSz);
uart_write_sz("\r\n", 2); /* handle CRLF */

buf = line;
sz -= lineSz + 1; /* skip \n, already sent */
} while ((int)sz > 0);
nrf5340_uart_crlf(buf, sz, uart_write_sz);
}
#endif /* DEBUG_UART */

Expand Down Expand Up @@ -840,22 +827,43 @@ void hal_init(void)
}

#ifdef __WOLFBOOT
/* enable write protection for the region of flash specified */
/* Enable write protection for the region of flash specified.
*
* Contract: protects [start, start+len). A zero len protects nothing and
* succeeds; a negative len is rejected. Protection is granted in whole
* SPU_FLASH_BLOCK_SIZE blocks, so a partial block at either end is locked
* whole - the locked range may be wider than requested, never narrower.
*/
int RAMFUNCTION hal_flash_protect(haladdr_t start, int len)
{
/* only application core supports SPU */
#ifdef TARGET_nrf5340_app
uint32_t region, n, i;
uint32_t tail;

/* limit check */
if (start > FLASH_SIZE)
return -1;
if (len < 0)
return -1;
/* An empty range protects nothing. Return before the region math below:
* `tail` carries the start offset, so an unaligned start would round up
* to one block and lock 16 KiB the caller never asked to protect. */
if (len == 0)
return 0;
/* truncate if exceeds flash size */
if (start + len > FLASH_SIZE)
if (start + (uint32_t)len > FLASH_SIZE)
len = FLASH_SIZE - start;

region = (start / SPU_FLASH_BLOCK_SIZE);
n = (len / SPU_FLASH_BLOCK_SIZE);
/* SPU regions are SPU_FLASH_BLOCK_SIZE-aligned. Round the block count up
* so the locked range covers [start, start+len) whole: start may sit
* mid-block and len may not be a whole number of blocks, so the partial
* blocks at both ends are locked whole (safe: it only ever widens
* protection). The old `len / SPU_FLASH_BLOCK_SIZE` truncated, leaving
* the tail block writable while still returning success. */
tail = (start % SPU_FLASH_BLOCK_SIZE) + (uint32_t)len;
Comment thread
danielinux marked this conversation as resolved.
n = (tail + SPU_FLASH_BLOCK_SIZE - 1) / SPU_FLASH_BLOCK_SIZE;

for (i = 0; i < n; i++) {
/* do not allow write to this region and lock till next reset */
Expand Down
56 changes: 56 additions & 0 deletions hal/nrf5340_uart.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* nrf5340_uart.c
*
* CRLF line conversion for the nRF5340 debug UART, split out of
* hal/nrf5340.c so the newline handling can be unit-tested on the host
* without the nrfx register access the rest of that HAL needs.
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with wolfBoot; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1335, USA
*/

#ifdef DEBUG_UART

#include <string.h>

/* Emit buf[0..sz) via "sink" with every '\n' rendered as CRLF. */
void nrf5340_uart_crlf(const char* buf, unsigned int sz,
void (*sink)(const char*, unsigned int))
{
const char* line;
unsigned int lineSz;
do {
/* find '\n' */
line = memchr(buf, '\n', sz);
if (line == NULL) {
sink(buf, sz);
break;
}
lineSz = (unsigned int)(line - buf);
if (lineSz > sz - 1)
lineSz = sz - 1;

sink(buf, lineSz);
sink("\r\n", 2); /* handle CRLF */

buf = line + 1; /* advance past the emitted newline */
sz -= lineSz + 1;
} while ((int)sz > 0);
}

#endif /* DEBUG_UART */
41 changes: 41 additions & 0 deletions include/target.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,47 @@
(WOLFBOOT_PARTITION_SWAP_ADDRESS + 0 + WOLFBOOT_SECTOR_SIZE))
#error "Update and swap partitions overlap"
#endif

/*
* The bootloader write-protect region [WOLFBOOT_ORIGIN,
* WOLFBOOT_ORIGIN + BOOTLOADER_PARTITION_SIZE) must not overlap any
* partition: an undersized value leaves the bootloader tail writable,
* an over-sized one write-protects the head of the partition.
* WOLFBOOT_ALLOW_PART_OVERLAP disables these checks for targets that
* deliberately place a partition inside the region (e.g. cypsoc6,
* where hal_flash_protect() is a no-op).
*/
#if !defined(WOLFBOOT_ALLOW_PART_OVERLAP)
#if defined(WOLFBOOT_ORIGIN) && \
Comment thread
danielinux marked this conversation as resolved.
!defined(PART_BOOT_EXT) && \
((WOLFBOOT_PARTITION_BOOT_ADDRESS + 0) != 0) && \
((WOLFBOOT_ORIGIN + 0) < \
(WOLFBOOT_PARTITION_BOOT_ADDRESS + 0 + WOLFBOOT_PARTITION_SIZE + 0)) && \
((WOLFBOOT_PARTITION_BOOT_ADDRESS + 0) < \
(WOLFBOOT_ORIGIN + 0 + BOOTLOADER_PARTITION_SIZE + 0))
#error "Boot partition overlaps the bootloader region"
#endif

#if defined(WOLFBOOT_ORIGIN) && \
!defined(PART_UPDATE_EXT) && \
((WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0) != 0) && \
((WOLFBOOT_ORIGIN + 0) < \
(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0 + WOLFBOOT_PARTITION_UPDATE_SIZE + 0)) && \
((WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0) < \
(WOLFBOOT_ORIGIN + 0 + BOOTLOADER_PARTITION_SIZE + 0))
#error "Update partition overlaps the bootloader region"
#endif

#if defined(WOLFBOOT_ORIGIN) && \
!defined(PART_SWAP_EXT) && \
((WOLFBOOT_PARTITION_SWAP_ADDRESS + 0) != 0) && \
((WOLFBOOT_ORIGIN + 0) < \
(WOLFBOOT_PARTITION_SWAP_ADDRESS + 0 + WOLFBOOT_SECTOR_SIZE)) && \
((WOLFBOOT_PARTITION_SWAP_ADDRESS + 0) < \
(WOLFBOOT_ORIGIN + 0 + BOOTLOADER_PARTITION_SIZE + 0))
#error "Swap partition overlaps the bootloader region"
#endif
#endif /* !WOLFBOOT_ALLOW_PART_OVERLAP */
#endif

#ifdef WOLFBOOT_PERSIST_FAILURE_STATUS
Expand Down
2 changes: 1 addition & 1 deletion src/update_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,7 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
update_type, HDR_IMG_TYPE_AUTH);
return -1;
}
if (update.fw_size > MAX_UPDATE_SIZE - 1) {
if (update.fw_size > MAX_UPDATE_SIZE) {
wolfBoot_printf("Invalid update size %u\n", update.fw_size);
return -1;
}
Expand Down
11 changes: 11 additions & 0 deletions test-app/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ ifeq ($(TZEN),1)
CFLAGS:=-I./wcs $(CFLAGS)
endif
CFLAGS+=-I. -I..
# Same opt-out as the bootloader build: target.h is shared, so the
# partition-vs-bootloader-region guards must be suppressed here too.
ifeq ($(WOLFBOOT_ALLOW_PART_OVERLAP),1)
CFLAGS+=-DWOLFBOOT_ALLOW_PART_OVERLAP=1
endif
DEBUG?=1
DELTA_DATA_SIZE?=2000
USE_CLANG?=0
Expand Down Expand Up @@ -118,6 +123,12 @@ else
else
APP_OBJS:=app_$(TARGET).o led.o system.o timer.o ../test-app/libwolfboot.o
endif
# nRF5340 debug-UART CRLF conversion (host-testable, no nrfx registers)
ifneq ($(filter nrf5340%, $(TARGET)),)
ifeq ($(DEBUG_UART),1)
APP_OBJS+=../hal/nrf5340_uart.o
endif
endif
endif

# Disable Thumb2 ASM for MAX32666 before arch.mk: hardware TPU handles AES
Expand Down
2 changes: 2 additions & 0 deletions tools/config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ ifeq ($(ARCH),)
WOLFBOOT_TPM_MFG_AUTH_DERIVE?=0
WOLFBOOT_ATTESTATION_IAK?=0
WOLFBOOT_ATTESTATION_TEST?=0
WOLFBOOT_ALLOW_PART_OVERLAP?=0
WOLFBOOT_UNIVERSAL_KEYSTORE?=0
WOLFBOOT_UDS_UID_FALLBACK_FORTEST?=0
WOLFBOOT_UDS_OBKEYS?=0
Expand Down Expand Up @@ -110,6 +111,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
WOLFTPM WOLFBOOT_TPM_VERIFY MEASURED_BOOT WOLFBOOT_TPM_SEAL WOLFBOOT_TPM_KEYSTORE \
WOLFBOOT_TPM_MFG_AUTH_DERIVE \
WOLFBOOT_ATTESTATION_IAK \
WOLFBOOT_ALLOW_PART_OVERLAP \
WOLFBOOT_ATTESTATION_TEST \
WOLFBOOT_UDS_UID_FALLBACK_FORTEST \
WOLFBOOT_UDS_OBKEYS \
Expand Down
8 changes: 5 additions & 3 deletions tools/keytools/keygen.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ const char Keystore_API[] =
" return (uint8_t*)RENESAS_RSIP_INSTALLEDKEY_RAM_ADDR;\n"
"#else\n"
#endif
" if (id >= keystore_num_pubkeys())\n"
" if (id < 0 || id >= keystore_num_pubkeys())\n"
Comment thread
danielinux marked this conversation as resolved.
" return (uint8_t *)0;\n"
" return (uint8_t *)PubKeys[id].pubkey;\n"
#ifdef RENESAS_KEY
Expand All @@ -241,7 +241,7 @@ const char Keystore_API[] =
" return (int)sizeof(rsa_public_t);\n"
"#else\n"
#endif
" if (id >= keystore_num_pubkeys())\n"
" if (id < 0 || id >= keystore_num_pubkeys())\n"
" return -1;\n"
" return (int)PubKeys[id].pubkey_size;\n"
#ifdef RENESAS_KEY
Expand All @@ -251,13 +251,15 @@ const char Keystore_API[] =
"\n"
"uint32_t keystore_get_mask(int id)\n"
"{\n"
" if (id >= keystore_num_pubkeys())\n"
" if (id < 0 || id >= keystore_num_pubkeys())\n"
" return 0;\n"
" return PubKeys[id].part_id_mask;\n"
"}\n"
"\n"
"uint32_t keystore_get_key_type(int id)\n"
"{\n"
" if (id < 0 || id >= keystore_num_pubkeys())\n"
" return (uint32_t)-1;\n"
" return PubKeys[id].key_type;\n"
"}\n"
"\n"
Expand Down
22 changes: 22 additions & 0 deletions tools/keytools/sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,11 @@ static int dts_hash_file(const char *file, int hash_algo, uint8_t *out,
return ret;
}

/* Test hook: the content header_idx from the last successful make_header_ex()
* (recorded before the 0xFF padding), so unit tests can compare the writer
* against header_required_size() without the auto-grow exit(1) path. */
static uint32_t test_last_header_idx;

static uint32_t header_required_size(int is_diff, uint32_t cert_chain_sz,
uint32_t secondary_key_sz)
{
Expand Down Expand Up @@ -1766,6 +1771,21 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
/* Add custom TLVs */
if (CMD.custom_tlvs > 0) {
uint32_t i;
/* A custom TLV reusing a built-in tag is serialized before the
* generated TLV and shadows it: wolfBoot_find_header() walks from the
* start and returns the first match. The device-tree digest (0x35) is
* the reserved tag reachable from --custom-tlv (tags >= 0x30); a
* custom 0x35 ahead of the --dts digest would make DTB verification
* use the operator-supplied value. Reject the collision. */
for (i = 0; i < CMD.custom_tlvs; i++) {
if (CMD.dts_file != NULL &&
CMD.custom_tlv[i].tag == HDR_DEVICE_TREE_DIGEST) {
fprintf(stderr,
"Error: custom TLV tag 0x%04x is reserved for --dts\n",
(unsigned)HDR_DEVICE_TREE_DIGEST);
goto failure;
}
}
for (i = 0; i < CMD.custom_tlvs; i++) {
/* require 8-byte alignment */
/* The offset '4' takes into account 2B Tag + 2B Len, so that the
Expand Down Expand Up @@ -2316,6 +2336,8 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
}
} /* end if(sign != NO_SIGN) */

test_last_header_idx = header_idx;

/* Add padded header at end */
while (header_idx < CMD.header_sz) {
header[header_idx++] = 0xFF;
Expand Down
Loading
Loading