You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by mi...@apache.org on 2026/03/18 12:06:13 UTC
(nuttx-apps) 01/03: boot/nxboot: add flush barriers and CRC-validate primary before boot
This is an automated email from the ASF dual-hosted git repository.
michallenc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit 4decc1699a18cc81f4b72837626fa32a1059b9fd
Author: Neil Berkman <ne...@xuku.com>
AuthorDate: Tue Mar 17 15:39:02 2026 -0700
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 <ne...@xuku.com>
---
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
*