Commit Graph

1336 Commits (6025f3540ffb43561ba5890ceee8c18cb4bd3650)

Author SHA1 Message Date
Daniele Lacamera f0e2c49150 F-13656: bound e_phentsize to the program-header struct size
An undersized e_phentsize made the last program-header loop iteration
read past the validated table (and past the image buffer when the
table ends at the image end). Reject such images with -3.

Verification: tools/unit-tests/unit-elf-phentsize fails pre-fix
(undersized ELF accepted, ret=0), passes post-fix (2/2); full
make -C tools/unit-tests run green.
2026-09-24 02:44:03 +02:00
Daniele Lacamera 1a8378ee58 F-14133: drop the dead entry_out_set guard in the ELF check 2026-09-24 02:33:47 +02:00
Daniele Lacamera b6f842ccbb F-14138: fix the DTCV base comment (2^13, not 2*13) 2026-09-24 02:33:47 +02:00
Daniele Lacamera a1bb7667d3 F-14149: compute the ARMORED witness triangular number in 64 bits 2026-09-24 02:33:47 +02:00
Daniele Lacamera 07301f972c F-12943: zeroize the policy session in seal/unseal blob cleanup
wolfBoot_seal_blob() and wolfBoot_unseal_blob() unload the
policy_session TPM handle on cleanup but leave the stack session object
(SRK-derived session key material) in the frame; ForceZero it in the
common cleanup of both.
2026-09-23 04:30:26 +02:00
Daniele Lacamera 525fd76398 F-7395: zeroize the stack auth blobs in the TPM seal/unseal and NV paths
wolfBoot_seal_auth()/wolfBoot_unseal_auth() copy the caller authValue
into a stack WOLFTPM2_KEYBLOB and the NV helpers copy it into a stack
WOLFTPM2_NV; none were cleared before return, inconsistent with the
existing TPM2_ForceZero(&unsealOut) in the same file. ForceZero each
stack object at the single exit.
2026-09-23 04:30:26 +02:00
Daniele Lacamera e1c7fb1f82 F-7393: zeroize the TPM session/SRK globals at deinit
wolfBoot_tpm2_deinit() unloads the session and SRK handles and cleans
up the device, but the file-scope wolftpm_session (HMAC/parameter-
encryption session key) and wolftpm_srk (SRK authValue) stayed in .bss
SRAM for the booted OS to read. ForceZero both after Cleanup.
2026-09-23 04:30:26 +02:00
Daniele Lacamera 60803ad3eb F-14156: mp_clear the ECDSA r/s scalars after verify
wolfBoot_verify_signature_ecc() imports the raw signature into mp_int
r/s and passes them to wc_ecc_verify_hash_ex() without clearing them;
mp_clear() scrubs the digit memory before the stack frame retires.
2026-09-23 03:29:49 +02:00
Daniele Lacamera 217dbe8f9e F-11039: zeroize XFREE'd slots in the static malloc pool
The small-stack crypto pool hands out workspace for hash blocks and
signature verification state; the slot was released back to the pool
still holding that data. Scrub it in XFREE before marking the slot
free (wc_ForceZero, same helper the rest of the crypto path uses).
2026-09-23 03:29:14 +02:00
Daniele Lacamera 6b505817ed F-13660: zeroize the nonce-derived IV copy in disk_crypto_set_iv
The CTR counter block built on the stack is a full copy of the secret
disk-encryption nonce plus counter; both in-tree sibling IV helpers
already scrub their stack copy, this was the only one that did not.
2026-09-23 03:26:31 +02:00
Daniele Lacamera 02f15efd0f F-7062: sdhci: check sdhci_set_clock results at all three call sites
A 0 return (no base clock / ICS never stabilized) proceeded with
an unconfigured card clock. Fail sdhci_init, emmc_card_full_init
and the UHS-I 50MHz step when the clock is not programmed.
2026-09-23 02:46:25 +02:00
Daniele Lacamera ab3b6f6f9d F-7386: sdcard_send_switch_function: fail when busy budget runs out
The do/while fell out with status==0 when the card stayed busy
until timeout, indistinguishable from supported, so the SWITCH
command went out for a function the card never cleared. Set
status=-1 when timeout reaches 0.
2026-09-23 02:46:25 +02:00
Daniele Lacamera 9b73957a85 F-7387: sdcard_send_switch_function: reject group 0
Groups are numbered 1..6; group 0 wrapped (group-1)*4 into a
0xFFFFFFFC shift count - undefined behaviour. Tighten the guard
to group_number < 1.
2026-09-23 02:46:25 +02:00
Daniele Lacamera 0f266e6407 F-7973: qspi test_ext_flash: return -1, not -i, on mismatch
A mismatch at index 0 evaluated to 0, which spi_flash_probe reads
as success. Use the fixed -1 like src/spi_flash.c does.
2026-09-23 02:46:16 +02:00
Daniele Lacamera c94453b083 F-7972: disk_open_mbr: return -1 when no usable partition
n_parts is unsigned, so the caller's < 0 guard was dead code and an
empty MBR reported success with zero partitions. Fail explicitly.
2026-09-23 02:46:16 +02:00
Daniele Lacamera 2f9a8ea15d F-7064: give the erase-completion ACK its long timeout
ERASE_TIMEOUT was defined but never used; the final erase ACK used
the plain short WAIT_CYCLES budget, so a slow remote flash made
ext_flash_erase() fail even when the erase succeeded. Factor
wait_ack_cycles() out of wait_ack() and use WAIT_CYCLES *
ERASE_TIMEOUT for the erase ACK, like uart_rx_timeout() does with
READ_TIMEOUT. Add unit tests for the success and timeout paths.
2026-09-23 01:48:54 +02:00
Aidan Garske c48a882cd9 Add a generic secure application handoff with a measured boot record 2026-09-22 15:35:42 +02:00
David Garske fae9e53653 hooks: add pre-boot hook, DTB accessor and FDT alias/reg helpers 2026-09-21 18:10:09 +02:00
David Garske 4093fa0e17 Add NXP i.MX 8QuadMax MEK port including BL33 support 2026-09-21 18:07:44 +02:00
David Garske e353b20504 va416x0: fix vector table alignment and length, FRAM defects and ML-DSA 2026-09-21 17:13:42 +02:00
Daniele Lacamera f80dde6d5d F-9753: accept the exact-fit update size in wolfBoot_update
The signer (sign.c) accepts total_img_sz == max_img_sz (the exact fit:
header + payload + trailer == partition size), but wolfBoot_update
rejected fw_size == MAX_UPDATE_SIZE via '> MAX_UPDATE_SIZE - 1', leaving
a 1-byte gap and an off-by-one between the two components. Drop the '- 1'
so the updater accepts the exact fit the signer produces. Rename
test_update_max_size_rejected to _accepted (version 2 now stages) and add
test_update_max_size_plus_one_rejected (MAX_UPDATE_SIZE + 1 still rejected).
2026-09-18 12:58:52 +02:00
Daniele Lacamera 928b9d9590 Guard security_command_passphrase against in-flight async DMA
Check ata_async_info.in_progress before preparing the slot or touching
the shared buffer, so a second security command cannot clobber the
passphrase still being DMA'd. With that guard an async call always
means in flight (exec_cmd_slot_ex sets in_progress and returns BUSY),
so the post-command scrub is unconditional for the async path.
2026-09-16 19:53:59 +02:00
Daniele Lacamera 5f231a890c Fix: keep wolfBoot API declarations visible to app builds
c3f9717f guarded the success/trigger/sector-flag declarations behind
WOLFBOOT_FIXED_PARTITIONS, but wolfboot.h includes target.h only under
__WOLFBOOT, so test-apps (compiled without __WOLFBOOT) never saw the
macro and failed with implicit-declaration errors on imx95_m7, mcxa,
mcxw and mcxw-tz. Unguard the header declarations; keep the definitions
guarded and move wolfBoot_success out of the fixed-partition guard
since it only uses the partition-state API.
2026-09-16 18:31:59 +02:00
Daniele Lacamera 7feb9cbf67 Mark wolfBoot_invalidate_hdr_cache RAMFUNCTION
Called from the RAM-resident update path (update_ram.c) under
EXT_FLASH; place the body in RAM so it runs after flash remap
instead of faulting.

Verification: built unit-custom-trailer-nopart (EXT_FLASH) - compiles
clean; imx95_m7 (EXT_FLASH, CI repro) - compiles clean.
2026-09-16 18:17:48 +02:00
Daniele Lacamera c3f9717fb5 PR 892: address 3 Fenrir review findings
- libwolfboot.c: keep the partition state APIs (set/get_partition_state)
  available to CUSTOM_PARTITION_TRAILER / WOLFBOOT_NO_PARTITIONS builds;
  guard the fixed-partition APIs (sector flags, erase, trigger, success)
  behind WOLFBOOT_FIXED_PARTITIONS. Add the unit-custom-trailer-nopart
  compile target to lock in that configuration.
- unit-p1021-fcm-bytes.c: add program tests for status 0x81 (fail) and
  0x00 (write-protected), asserting no later page is programmed.
- unit-p1021-erase-advance.c: add an erase test for status 0x00
  (write-protected), asserting failure before advancing to the next block.
2026-09-16 17:19:16 +02:00
Daniele Lacamera 6814b503ef PR 892: address 6 Fenrir review findings
- hal/nxp_p1021.c: fix ONFI status polarity (bit 0 set = fail, bit 7
  clear = protected; was checking bits 0+1 set = success)
- src/libwolfboot.c: move partition state APIs under HAVE_PARTITION_TRAILERS
  so CUSTOM_PARTITION_TRAILER without WOLFBOOT_FIXED_PARTITIONS links
- src/x86/ata.c: do not zeroize DMA buffer when another async op is
  in progress (buffer still owned by first command's transfer)
- unit-p1021-fcm-bytes/erase-advance: update mocks to ONFI status bytes
- unit-update-ram-custom-trailer: add BOOT selection assertion via
  mock_max_read_addr, PID-suffixed temp files, unlink in cleanup
- unit-update-ram-nofixed-noramboot: unlink PID-specific temp files
2026-09-16 16:18:49 +02:00
Daniele Lacamera d316af6567 PR 892: TFES PxCI check + unique test temp files
- src/x86/ata.c: verify PxCI is clear in the TFES path before scrubbing
  the DMA buffer (symmetric with the success path; prevents scrubbing
  while the HBA may still reference the buffer)
- unit-update-ram-nofixed-noramboot.c: append PID to /tmp filenames to
  avoid collisions under parallel make -j or shared runners
2026-09-16 14:40:50 +02:00
Daniele Lacamera cc7fec1ea2 PR 892: anti-rollback for CUSTOM_PARTITION_TRAILER targets
Add HAVE_PARTITION_TRAILERS macro (set when WOLFBOOT_FIXED_PARTITIONS or
CUSTOM_PARTITION_TRAILER is defined) and use it to gate the TESTING state
transition in update_ram.c. Previously the gate was WOLFBOOT_FIXED_PARTITIONS
only, so targets using custom partition trailers never transitioned from
UPDATING to TESTING, allowing rollback to older versions.

Add unit-update-ram-custom-trailer test covering the CUSTOM_PARTITION_TRAILER
path with mocked get/set_trailer_at callbacks.
2026-09-16 14:30:26 +02:00
Daniele Lacamera b7857b99f9 F-12077: wolfBoot_ram_decrypt is not AES-only
Decryption is ChaCha20, AES-CTR, or PKCS#11 per build config; the doc
implied AES only.
2026-09-16 12:15:37 +02:00
Daniele Lacamera 44908c3e5d F-12076: ext_flash_decrypt_read is not AES-only
Decryption is ChaCha20, AES-CTR, or PKCS#11 per build config; the doc
implied AES only.
2026-09-16 12:15:31 +02:00
Daniele Lacamera 17d6cc2604 F-12892: wolfBoot_update_trigger acts on the update partition
The function sets the update partition state to IMG_STATE_UPDATING and
erases the update partition last sector; the doc said boot partition.
2026-09-16 12:15:23 +02:00
Daniele Lacamera 180647eb1c F-12893: drop invented @return from set_update_sector_flags doc
set_update_sector_flags is void; the doc claimed a 0/-1 status return.
2026-09-16 12:15:15 +02:00
Daniele Lacamera bed6df776d F-9255: fix eMMC ready-bit polarity in comment
The code treats OCR bit 31 set as ready (response & MMC_OCR_BUSY_BIT);
the comment said busy bit cleared equals ready.
2026-09-16 12:15:08 +02:00
Daniele Lacamera c8b799bda9 F-11013: SDHCI no-base-clock path returns 0 as an error
The no-base-clock path disables the clock and returns 0 (error),
unlike the already-set path above which returns last_clock_khz.
The old NOTE claimed callers could not tell the two apart.
2026-09-16 12:15:00 +02:00
Daniele Lacamera e32ea8a659 F-12891: wolfBoot_tpm2_extend PCR range is 0-23
PCR 24 is not a valid extend target; the doc said 0-24.
2026-09-16 12:14:13 +02:00
Daniele Lacamera 43a0e59f37 F-12890: change_stack_and_invoke has no callback arg
The function takes (new_stack, other_func) only; the doc described a
nonexistent 'ptr' parameter.
2026-09-16 12:14:13 +02:00
Daniele Lacamera c58a6905f0 F-9723: non-MMU handoff clears r0-r3, not all GPRs
The code clears only r0-r3 for the handoff; the comment said all
GPRs cleared.
2026-09-16 12:14:13 +02:00
Daniele Lacamera 36c57846f5 F-9256: rejected ELF does not rewrite the entry point
The rationale that a rejected ELF leaves load_address rewritten no
longer matches the code. The skip flag is set on each stage's
success path.
2026-09-16 12:14:13 +02:00
Daniele Lacamera a2e6238183 F-9254: XMSS import error comment named LMS params
The failing call is wc_XmssKey_ImportPubRaw; the error comment
referenced LMS parameters.
2026-09-16 12:14:13 +02:00
Daniele Lacamera 09f0c9a5a3 F-9253: disk_open accepts GPT or MBR, not GPT-only
The @return contract said 'no valid GPT partition table' but
disk_open falls back to parsing an MBR when no protective-MBR GPT
is present.
2026-09-16 12:14:13 +02:00
Daniele Lacamera 9f456bf864 F-9252: fix MPU system-control range end address
Comment said 0xE0000000:0xEFFFFFF (255M) but the system-control
region is 256M, ending at 0xEFFFFFFF.
2026-09-16 12:14:13 +02:00
Daniele Lacamera 5f6eb05552 F-6764: scrub passphrase buffer when async ATA command completes
security_command_passphrase() only wiped the static DMA buffer on the
synchronous path; in async mode (ata_security_erase_unit) the
passphrase stayed resident in the file-static buffer for the rest of
the boot, since ata_cmd_complete_async() never scrubbed it.

Add a scrub_buffer flag to the async state, set it when the command
goes in flight (or wipe immediately if it never started), and scrub in
ata_cmd_complete_async() on both the success and task-file-error exits,
once the HBA has retired the command.

Covered by two new unit tests: scrub after async completion and after
an async port error; the in-flight state is asserted unscrubbed.

Reported by Fenrir.
2026-09-15 15:43:11 +02:00
Daniele Lacamera 19d8a42303 F-6765: scrub previous value before overwriting PSA storage
ARM_TEE_PS_SET on an existing object XMEMCPY'd the new value over the
old one without clearing the buffer first, so a SET that stores less
data (or zero data) left the tail of the previous object readable
through ARM_TEE_PS_GET.

Zero the full data area with wc_ForceZero after every validation check
passes and before the copy, matching the DELETE path.

Reported by Fenrir.
2026-09-15 15:35:10 +02:00
Daniele Lacamera bad522f654 F-12942: pkcs11: wipe PIN on terminal init failure
pkcs11_crypto_init() tore down the session on failure but left the
pre-populated pkcs11_pin credential in retained bootloader memory
after the handoff. Wipe it in the failure path, same as the deinit
path (F-12114). Regression test in unit-pkcs11-pin-zeroize: login
rejected -> init fails -> every pin byte is zero.
2026-09-15 13:24:14 +02:00
Daniele Lacamera 63f1ce7872 F-12922: do not block fallback to a valid image in wolfBoot_start
The version gate in the retry loop panicked whenever the selected
candidate failed verification and the fallback partition carried a
lower version, even though that image is valid and signed. A single
corrupted higher-version image bricked the device instead of falling
back. The gate only ever fired on the failure path (candidate
selection already prefers the higher version), so remove it; the
TESTING-state anti-rollback check in wolfBoot_dualboot_candidate()
still guards the confirmed-update path.
2026-09-15 08:24:11 +02:00
Daniele Lacamera f0ad5692d2 F-13604: Reset image state on each retry in update_ram fallback
wolfBoot_start() zeroed os_image once, before the retry loop, so the
fallback iteration kept the stale img->hdr of the failed partition and
wolfBoot_open_image_address() (which only adopts load_address when
hdr is NULL) re-verified the wrong image. The external header cache
had the same problem: it kept the first image opened.

memset the struct and invalidate the EXT_FLASH header cache at the
top of each loop iteration, per the documented precondition of
wolfBoot_open_image_address().

Add unit-update-ram-nofixed-noramboot: the non-fixed-partition,
non-RAMBOOT (XIP) layout where load_address varies per retry, with
fallback tests both directions plus candidate-selection checks.
2026-09-15 02:58:57 +02:00
David Garske b0fe251747 Add Nuvoton NuMaker M2354 Cortex-M23 target with TrustZone 2026-09-14 18:08:40 +02:00
Daniele Lacamera 9b06b907f8 hal: always define hal_cache_invalidate(), implement it on F4 and G4
The weak no-op sat inside NVM_FLASH_WRITEONCE, so pkcs11_store.c failed to
link on the nrf5340/nrf54l TrustZone configs. STM32F4 and STM32G4 enable the
flash instruction/data caches and never reset them, so give them a real one.
2026-09-10 18:42:54 +02:00
Daniele Lacamera 42e6dba558 pkcs11 store: invalidate the flash read cache after every commit
The store commits sectors with hal_flash_erase()/hal_flash_write() and
then reads them back through the memory map - sector_ptr(),
cache_get_sector()'s refill, and the raw magic reads in check_vault().
On a part that caches flash reads (STM32 ICACHE) those reads can return
pre-erase bytes. check_vault() is the worst case: a stale magic there
does not merely read wrong, it triggers restore_backup() or a full vault
re-initialisation, losing the token.
2026-09-10 10:45:55 +02:00
Daniele Lacamera 1d3b576f03 pkcs11 store: pin the Open-time durability rule with a power-fail test
Adds power-fail injection to the flash mock and a test that cuts power at
every flash operation of a rewrite window, asserting the object always reads
back as the whole old payload, the whole new payload, or empty. Fails at
op 3 without this fix, passes with it.

unit-pkcs11_store 10/10; full unit-tests suite green.
2026-09-10 09:40:17 +02:00