Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
20 changes: 18 additions & 2 deletions hal/cm4.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,11 @@ void* hal_get_boot_dts(void)
sz = fdt_size(&ctx);
/* SECURITY: the firmware DTB lives on the unsigned FAT partition (unless
* the RPi EEPROM secure-boot is enabled), so it is NOT covered by wolfBoot's
* signature. Only /chosen/bootargs is overwritten below; /memory,
* /reserved-memory, per-device reg windows and initrd remain firmware /
* signature. Only /chosen/bootargs is overwritten below, and the
* /chosen/linux,initrd-{start,end} pointers are zeroed: this path never
* loads an authenticated ramdisk, so a non-zero firmware value would
* direct the signed kernel to an unauthenticated initramfs in RAM.
* /memory, /reserved-memory and per-device reg windows remain firmware /
* attacker controlled.
* This is NOT effectively optional: CM4_FIRMWARE_DTB is enabled by default
* in both shipped Linux configurations (cm4_emmc_linux.config and
Expand Down Expand Up @@ -442,6 +445,19 @@ void* hal_get_boot_dts(void)
return NULL;
}
#endif
/* Zero the initrd pointers the firmware DTB may carry. This path never
* attaches an authenticated ramdisk (a FIT ramdisk subimage is only
* fixup'd into an FIT-embedded DTB, which bypasses this fallback), so
* any non-zero value here would point the signed kernel at an
* unauthenticated initramfs in RAM. The kernel loads no initrd from a
* zero range, and the properties are zeroed, not deleted, so the
* existing fdt_fixup_val64() covers both the present and absent case.
* Fail closed, like the bootargs fixup above. */
if (fdt_fixup_val64(&ctx, off, "chosen", "linux,initrd-start", 0) != 0 ||
fdt_fixup_val64(&ctx, off, "chosen", "linux,initrd-end", 0) != 0) {
wolfBoot_printf("cm4: DTB initrd fixup failed; refusing firmware DTB\n");
return NULL;
}
wolfBoot_printf("cm4: DTB relocated to %p, bootargs set\n", fdt);
return fdt;
#endif /* CM4_FIRMWARE_DTB */
Expand Down
26 changes: 12 additions & 14 deletions hal/stm32c0.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@
#define FLASH_SECR (*(volatile uint32_t *)(FLASH_BASE + 0x80)) /* RM0490 - 3.7.13 - FLASH_SECR */
#endif /* !WOLFBOOT_UNIT_TEST_FLASH_ERASE */

#define FLASHMEM_ADDRESS_SPACE (0x08000000)
#define FLASH_PAGE_SIZE (0x800) /* 2KB */
#define FLASH_PAGE_SIZE_SHIFT 11 /* (1 << FLASH_PAGE_SIZE_SHIFT) == FLASH_PAGE_SIZE*/

Expand Down Expand Up @@ -152,26 +151,25 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
flash_clear_errors();
if ((len - i >= 8) && ((((address + i) & 0x07) == 0) &&
((((uint32_t)data) + i) & 0x07) == 0)) {
src = (uint32_t *)data;
dst = (uint32_t *)(address + FLASHMEM_ADDRESS_SPACE);
src = (uint32_t *)(data + i);
dst = (uint32_t *)(address + i);
flash_wait_complete();
dst[i >> 2] = src[i >> 2];
dst[(i >> 2) + 1] = src[(i >> 2) + 1];
dst[0] = src[0];
dst[1] = src[1];
flash_wait_complete();
i+=8;
i += 8;
} else {
uint32_t unit_addr = (address + i) & (~0x07);
int off = (address + i) - unit_addr;
uint32_t val[2];
uint8_t *vbytes = (uint8_t *)(val);
int off = (address + i) - (((address + i) >> 3) << 3);
uint32_t base_addr = address & (~0x07); /* aligned to 64 bit */
int u32_idx = (i >> 2);
dst = (uint32_t *)(base_addr);
val[0] = dst[u32_idx];
val[1] = dst[u32_idx + 1];
dst = (uint32_t *)unit_addr;
val[0] = dst[0];
val[1] = dst[1];
while ((off < 8) && (i < len))
vbytes[off++] = data[i++];
dst[u32_idx] = val[0];
dst[u32_idx + 1] = val[1];
dst[0] = val[0];
dst[1] = val[1];
flash_wait_complete();
}
}
Expand Down
2 changes: 1 addition & 1 deletion hal/stm32f7.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ void fork_bootloader(void);
# define FLASH_SECTOR_8 0x8100000 /* 256 Kb */
# define FLASH_SECTOR_9 0x8140000 /* 256 Kb */
# define FLASH_SECTOR_10 0x8180000 /* 256 Kb */
# define FLASH_SECTOR_11 0x818C000 /* 256 Kb */
# define FLASH_SECTOR_11 0x81C0000 /* 256 Kb */
#endif
# define FLASH_TOP 0x8200000

Expand Down
20 changes: 13 additions & 7 deletions hal/stm32l5.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,32 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)

while (i < len) {
int j;
uintptr_t cur_addr = (uintptr_t)dst + i;
uint32_t *unit = (uint32_t *)(cur_addr & (~0x07UL));
int off = (int)(cur_addr & 0x07UL);
int i_aligned = i - off;

/* Read-modify-write the whole 64-bit unit (as stm32h5.c):
* there is no 32-bit program mode, so both words must be
* stored inside one PG window or nothing is programmed. */
* stored inside one PG window or nothing is programmed. The
* unit is aligned down from the next byte, so an unaligned
* start keeps the bytes before the request. */
for (j = 0; j < 8; j++) {
if (i + j < len)
dword_bytes[j] = data[i + j];
if ((j >= off) && (i_aligned + j < len))
dword_bytes[j] = data[i_aligned + j];
else
dword_bytes[j] = ((const uint8_t *)dst)[i + j];
dword_bytes[j] = ((const uint8_t *)unit)[j];
}

*cr |= FLASH_CR_PG;
dst[i >> 2] = dword[0];
unit[0] = dword[0];
ISB();
dst[(i >> 2) + 1] = dword[1];
unit[1] = dword[1];
hal_flash_wait_complete(0);
if ((*sr & FLASH_SR_EOP) != 0)
*sr |= FLASH_SR_EOP;
*cr &= ~FLASH_CR_PG;
i += 8;
i = i_aligned + 8;
}
Comment thread
danielinux marked this conversation as resolved.
#if TZ_SECURE()
hal_tz_release_nonsecure_area();
Expand Down
18 changes: 12 additions & 6 deletions hal/stm32u5.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,27 +94,33 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)

while (i < len) {
int j;
uintptr_t cur_addr = (uintptr_t)dst + i;
uint32_t *unit = (uint32_t *)(cur_addr & (~0x0FUL));
int off = (int)(cur_addr & 0x0FUL);
int i_aligned = i - off;

/* Read-modify-write the whole 128-bit unit (as stm32h5.c):
* the program only starts on the 4th word, and a partial
* quad-word leaves FLASH_SR_WDW set, hanging the wait. */
* quad-word leaves FLASH_SR_WDW set, hanging the wait. The
* unit is aligned down from the next byte, so an unaligned
* start keeps the bytes before the request. */
for (j = 0; j < 16; j++) {
if (i + j < len)
qword_bytes[j] = data[i + j];
if ((j >= off) && (i_aligned + j < len))
qword_bytes[j] = data[i_aligned + j];
else
qword_bytes[j] = ((const uint8_t *)dst)[i + j];
qword_bytes[j] = ((const uint8_t *)unit)[j];
}

*cr |= FLASH_CR_PG;
for (j = 0; j < 4; j++) {
dst[(i >> 2) + j] = qword[j];
unit[j] = qword[j];
ISB();
}
hal_flash_wait_complete(0);
if ((*sr & FLASH_SR_EOP) != 0)
*sr |= FLASH_SR_EOP;
*cr &= ~FLASH_CR_PG;
i += 16;
i = i_aligned + 16;
}

return 0;
Expand Down
11 changes: 10 additions & 1 deletion hal/stm32wb.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ PKA_HandleTypeDef hpka = { };
#define RCC_CFGR_SW_MSI 0x0
#define RCC_CFGR_SW_PLL 0x3
#define RCC_CFGR_SW_MASK 0x3
/* SWS (bits 3:2, read-only) mirrors the SW encoding (RM0434 6.4.3): */
#define RCC_CFGR_SWS_MSI 0x0
#define RCC_CFGR_SWS_MASK 0x3

#define RCC_CFGR_HPRE_MASK 0x0F
#define RCC_CFGR_PPRE1_MASK 0x07
Expand Down Expand Up @@ -254,11 +257,17 @@ static void clock_pll_off(void)
/* Enable internal high-speed oscillator. */
RCC_CR |= RCC_CR_MSION;
DMB();
while ((RCC_CFGR & RCC_CR_MSIRDY) == 0) {};
/* Wait for MSI to be ready. */
while ((RCC_CR & RCC_CR_MSIRDY) == 0)
;
/* Select MSI as SYSCLK source. */
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_SW_MASK);
RCC_CFGR = reg32;
DMB();
/* Wait for the switch to be confirmed (SWS, bits 3:2). */
while (((RCC_CFGR >> 2) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_MSI)
;
Comment thread
danielinux marked this conversation as resolved.
/* Turn off PLL */
RCC_CR &= ~RCC_CR_PLLON;
DMB();
Expand Down
3 changes: 3 additions & 0 deletions src/pkcs11_store.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,9 @@ int wolfPKCS11_Store_Remove(int type, CK_ULONG id1, CK_ULONG id2)
if (buf == NULL)
return NOT_AVAILABLE_E;

/* Erase the payload before invalidating the metadata, so key
* material does not remain recoverable in flash after removal. */
erase_object_payload(buf);
delete_object((int32_t)type, (uint32_t)id1, (uint32_t)id2);
return 0;
}
Expand Down
3 changes: 3 additions & 0 deletions src/psa_store.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,9 @@ int wolfPSA_Store_Remove(int type, unsigned long id1, unsigned long id2)
if (buf == NULL)
return NOT_AVAILABLE_E;

/* Erase the payload before invalidating the metadata, so key
* material does not remain recoverable in flash after removal. */
erase_object_payload(buf);
delete_object((int32_t)type, (uint32_t)id1, (uint32_t)id2);
return 0;
}
Expand Down
17 changes: 12 additions & 5 deletions src/riscv_sbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,13 +536,16 @@ static void sbi_post_ipi(unsigned long mask, unsigned long base,
* the targets increment ipi_done after executing the fences, so this
* completes only when every target has finished its fence. The SBI
* remote-fence calls are synchronous; the bound guards against a wedged
* target turning into a wedged caller. */
static void sbi_wait_ipi_done(unsigned long mask, unsigned long base,
* target turning into a wedged caller. Returns SBI_SUCCESS when every
* target completed, SBI_ERR_FAILED when any target did not complete
* within the bound. */
static long sbi_wait_ipi_done(unsigned long mask, unsigned long base,
unsigned long self)
{
unsigned long i;
unsigned long h;
uint32_t spin;
long err = SBI_SUCCESS;
/* SBI v0.2: hart_mask_base == -1 selects all harts (see sbi_post_ipi). */
if (base == (unsigned long)-1) {
base = 0;
Expand All @@ -561,7 +564,11 @@ static void sbi_wait_ipi_done(unsigned long mask, unsigned long base,
while (sbi_ipi_done[h] <= sbi_ipi_wait_gen[h] && spin > 0U) {
spin--;
}
if (sbi_ipi_done[h] <= sbi_ipi_wait_gen[h]) {
err = SBI_ERR_FAILED;
}
}
return err;
}

/* Returns the (possibly advanced) PC to resume at. For ecall we skip the
Expand Down Expand Up @@ -658,7 +665,7 @@ unsigned long sbi_handle_ecall(unsigned long *regs, unsigned long epc)
break;
}
sbi_post_ipi(regs[A0], regs[A1], op, hartid);
sbi_wait_ipi_done(regs[A0], regs[A1], hartid);
err = sbi_wait_ipi_done(regs[A0], regs[A1], hartid);
break;
}

Expand Down Expand Up @@ -786,9 +793,9 @@ unsigned long sbi_handle_ecall(unsigned long *regs, unsigned long epc)
sbi_post_ipi(fmask, 0,
(eid == SBI_EXT_0_1_REMOTE_FENCE_I) ?
SBI_IPI_OP_FENCE_I : SBI_IPI_OP_SFENCE, hartid);
sbi_wait_ipi_done(fmask, 0, hartid);
err = sbi_wait_ipi_done(fmask, 0, hartid);
}
regs[A0] = 0;
regs[A0] = (unsigned long)err;
return epc + 4;
case SBI_EXT_0_1_SHUTDOWN:
wolfBoot_printf("[SBI] legacy SHUTDOWN requested\n");
Expand Down
21 changes: 13 additions & 8 deletions src/update_disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -547,11 +547,15 @@ void RAMFUNCTION wolfBoot_start(void)
* The header sits ahead of the payload in the same file, hence the
* IMAGE_HEADER_SIZE. */
#if defined(WOLFBOOT_FSP)
/* Fail closed on an inverted tolum: the subtraction would otherwise wrap
* to a near-2^64 bound, which is the opposite of a cap. */
if ((uintptr_t)(stage2_params->tolum) > (uintptr_t)load_address) {
slot_max = (uint64_t)(uintptr_t)(stage2_params->tolum) -
(uint64_t)(uintptr_t)load_address;
/* Fail closed on an inverted tolum: with tolum at or below the load
* address there is no low-memory window, so the cap is zero. Both
* are low-memory addresses, so compare them in their 32-bit form.
* The subtraction would otherwise wrap into a near-2^32 bound, which
* is the opposite of a cap. */
if ((uint32_t)(uintptr_t)(stage2_params->tolum) >
(uint32_t)(uintptr_t)load_address) {
slot_max = (uint64_t)(uint32_t)(uintptr_t)(stage2_params->tolum) -
(uint64_t)(uint32_t)(uintptr_t)load_address;
}
else {
slot_max = 0;
Expand Down Expand Up @@ -697,9 +701,10 @@ void RAMFUNCTION wolfBoot_start(void)
#endif

#ifdef WOLFBOOT_FSP
/* Verify image size fits in low memory */
if (os_image.fw_size > ((uint32_t)(stage2_params->tolum) -
(uint32_t)(uintptr_t)load_address)) {
/* Verify image size fits in low memory. Reuse the validated
* slot_max: it is zero when tolum is inverted, where the raw
* subtraction would wrap into a near-2^32 limit. */
if (os_image.fw_size > slot_max) {
wolfBoot_printf("Image size %u doesn't fit in low memory\r\n",
os_image.fw_size);
selected ^= 1;
Expand Down
36 changes: 27 additions & 9 deletions tools/unit-tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ TESTS+=unit-stm32l4-write
TESTS+=unit-stm32wb-write
TESTS+=unit-stm32l5-write
TESTS+=unit-stm32u5-write
TESTS+=unit-stm32c0-write
TESTS+=unit-nvm-cache-scrub
TESTS+=unit-update-trigger-scrub
TESTS+=unit-sdhci-uhs-recover
Expand Down Expand Up @@ -1254,6 +1255,20 @@ stm32wb_write_extract.h: ../../hal/stm32wb.c
unit-stm32wb-write: unit-stm32wb-write.c stm32wb_write_extract.h
gcc -o $@ unit-stm32wb-write.c $(CFLAGS) $(LDFLAGS)

# unit-stm32c0-write runs the real hal_flash_write() from hal/stm32c0.c
# (the double-word fast path added the flash base to an already
# absolute address, targeting an address space past the flash, and the
# read-modify-write path located its unit from the request base instead
# of from the destination). Same harness as the STM32L4/STM32WB twins;
# the c0 helpers are static and un-prefixed.
stm32c0_write_extract.h: ../../hal/stm32c0.c
sed -n '/^static RAMFUNCTION void flash_wait_complete/,/^}/p' $< > $@
sed -n '/^static void RAMFUNCTION flash_clear_errors/,/^}/p' $< >> $@
sed -n '/^int RAMFUNCTION hal_flash_write/,/^}/p' $< >> $@

unit-stm32c0-write: unit-stm32c0-write.c stm32c0_write_extract.h
gcc -o $@ unit-stm32c0-write.c $(CFLAGS) $(LDFLAGS)

# unit-t10xx-flash-status runs the real hal_flash_write()/hal_flash_erase()
# and hal_flash_status_wait() from hal/nxp_t10xx.c against a mock QPI
# status model (F-11033: a timed-out program/erase used to report
Expand Down Expand Up @@ -1425,20 +1440,23 @@ unit-ecc-raw-der: unit-ecc-raw-der.c
# destination flash is a pre-filled host array, so the over-read is
# observable through a canary after the source buffer.
stm32l5_write_extract.h: ../../hal/stm32l5.c
sed -n '/^void RAMFUNCTION hal_flash_wait_complete/,/^}/p' $< > $@
sed -n '/^void RAMFUNCTION hal_flash_clear_errors/,/^}/p' $< >> $@
# hal_flash_wait_complete is mocked in the test (program-window
# check), so only the real clear_errors + write are extracted.
sed -n '/^void RAMFUNCTION hal_flash_clear_errors/,/^}/p' $< > $@
sed -n '/^int RAMFUNCTION hal_flash_write/,/^}/p' $< >> $@

unit-stm32l5-write: unit-stm32l5-write.c stm32l5_write_extract.h
gcc -o $@ unit-stm32l5-write.c $(CFLAGS) $(LDFLAGS)

# unit-stm32u5-write is the 16-byte-unit twin of the STM32L5 test:
# the real hal_flash_write() and its wait/clear helpers from
# hal/stm32u5.c, FLASH_NS_SR/CR on a host register file, destination
# flash at a 32-bit host address, canary after the source buffer.
# the real hal_flash_write() and clear_errors from hal/stm32u5.c
# (hal_flash_wait_complete is mocked in the test for the
# program-window check), FLASH_NS_SR/CR on a host register file,
# destination flash at a 32-bit host address, canary after the source.
stm32u5_write_extract.h: ../../hal/stm32u5.c
sed -n '/^void RAMFUNCTION hal_flash_wait_complete/,/^}/p' $< > $@
sed -n '/^void RAMFUNCTION hal_flash_clear_errors/,/^}/p' $< >> $@
# hal_flash_wait_complete is mocked in the test (program-window
# check), so only the real clear_errors + write are extracted.
sed -n '/^void RAMFUNCTION hal_flash_clear_errors/,/^}/p' $< > $@
sed -n '/^int RAMFUNCTION hal_flash_write/,/^}/p' $< >> $@

unit-stm32u5-write: unit-stm32u5-write.c stm32u5_write_extract.h
Expand Down Expand Up @@ -1621,8 +1639,8 @@ GENERATED_SRC:=aurix_erased_extract.h \
kontron_spi_extract.h kontron_spi_fn_extract.h \
rp2350_flash_write_extract.h \
sdhci_host.c \
stm32g4_write_extract.h stm32l4_write_extract.h stm32l5_write_extract.h \
stm32u5_write_extract.h stm32wb_write_extract.h \
stm32c0_write_extract.h stm32g4_write_extract.h stm32l4_write_extract.h \
stm32l5_write_extract.h stm32u5_write_extract.h stm32wb_write_extract.h \
t10xx_flash_status_extract.h t10xx_qe_firmware_extract.h \
t2080_fman_extract.h \
ti_hercules_write_extract.h versal_ext_write_extract.h versal_host.c \
Expand Down
Loading
Loading