From 4decc1699a18cc81f4b72837626fa32a1059b9fd Mon Sep 17 00:00:00 2001 From: Neil Berkman Date: Tue, 17 Mar 2026 15:39:02 -0700 Subject: [PATCH] boot/nxboot: add flush barriers and CRC-validate primary before boot Two hardening fixes for nxboot power-loss resilience: 1. Add flash_partition_flush() calls between critical partition operations in perform_update(). Without explicit flush barriers, writes may remain buffered in RAM (e.g. via FTL rwbuffer) when nxboot proceeds to the next phase. A power loss between phases can leave the recovery image uncommitted while the staging partition has already been consumed. Flush points added: - After copy_partition(primary, recovery) completes - After copy_partition(update, primary) completes, before erasing the staging first sector 2. Replace validate_image_header() with validate_image() in the final primary validation path of nxboot_perform_update(). The header-only check validates magic and platform identifier but does not CRC-check the image body. After an interrupted update, a corrupt primary with an intact header would pass this check and be booted, resulting in a persistent boot failure. Signed-off-by: Neil Berkman --- boot/nxboot/loader/boot.c | 6 ++++-- boot/nxboot/loader/flash.c | 20 ++++++++++++++++++++ boot/nxboot/loader/flash.h | 16 ++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/boot/nxboot/loader/boot.c b/boot/nxboot/loader/boot.c index 6de9659ac..8bcd24cef 100644 --- a/boot/nxboot/loader/boot.c +++ b/boot/nxboot/loader/boot.c @@ -417,6 +417,7 @@ static int perform_update(struct nxboot_state *state, bool check_only) syslog(LOG_INFO, "Creating recovery image.\n"); nxboot_progress(nxboot_progress_start, recovery_create); copy_partition(primary, recovery, state, false); + flash_partition_flush(recovery); nxboot_progress(nxboot_progress_end); nxboot_progress(nxboot_progress_start, validate_recovery); successful = validate_image(recovery); @@ -444,6 +445,8 @@ static int perform_update(struct nxboot_state *state, bool check_only) nxboot_progress(nxboot_progress_start, update_from_update); if (copy_partition(update, primary, state, true) >= 0) { + flash_partition_flush(primary); + /* Erase the first sector of update partition. This marks the * partition as updated so we don't end up in an update loop. * The sector is written back again during the image @@ -919,8 +922,7 @@ int nxboot_perform_update(bool check_only) return ERROR; } - get_image_header(primary, &header); - if (!validate_image_header(&header)) + if (!validate_image(primary)) { ret = ERROR; } diff --git a/boot/nxboot/loader/flash.c b/boot/nxboot/loader/flash.c index f1a359573..ab6a24320 100644 --- a/boot/nxboot/loader/flash.c +++ b/boot/nxboot/loader/flash.c @@ -76,6 +76,26 @@ int flash_partition_open(const char *path) return fd; } +/**************************************************************************** + * Name: flash_partition_flush + * + * Description: + * Flushes any buffered writes to the underlying storage. This ensures + * data is physically committed to flash before the caller proceeds. + * + * Input parameters: + * fd: Valid file descriptor. + * + * Returned Value: + * 0 on success, -1 on failure. + * + ****************************************************************************/ + +int flash_partition_flush(int fd) +{ + return fsync(fd); +} + /**************************************************************************** * Name: flash_partition_close * diff --git a/boot/nxboot/loader/flash.h b/boot/nxboot/loader/flash.h index ef1dee09d..69906490d 100644 --- a/boot/nxboot/loader/flash.h +++ b/boot/nxboot/loader/flash.h @@ -79,6 +79,22 @@ int flash_partition_open(const char *path); int flash_partition_close(int fd); +/**************************************************************************** + * Name: flash_partition_flush + * + * Description: + * Flushes any buffered writes to the underlying storage. + * + * Input parameters: + * fd: Valid file descriptor. + * + * Returned Value: + * 0 on success, -1 on failure. + * + ****************************************************************************/ + +int flash_partition_flush(int fd); + /**************************************************************************** * Name: flash_partition_write *