This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 2330e39546f arch/arm/rp23xx: harden the TRNG against health-test 
failures
2330e39546f is described below

commit 2330e39546fed122a2fc12cf49ae18923b47dac4
Author: Ricard Rosson <[email protected]>
AuthorDate: Mon Jul 27 14:31:27 2026 +0100

    arch/arm/rp23xx: harden the TRNG against health-test failures
    
    The TRNG driver waited for EHR_VALID and copied the block out without
    checking the CryptoCell health-test result, so a sample that failed the
    on-chip von-Neumann, CRNGT or autocorrelation test was served as entropy.
    
    Check RNG_ISR before consuming a block: on a health-test error, discard
    the block and re-arm the source; only a block that passed is returned.
    Add a small startup self-test that draws a few conditioned blocks and, if
    the source is stuck (identical blocks), latches /dev/random and /dev/urandom
    to fail with -EIO rather than emit predictable output that would silently
    weaken every derived key.
    
    Builds on the driver added in 52e84e0c0a.
    
    Signed-off-by: Ricard Rosson <[email protected]>
    Assisted-by: Claude (Anthropic Claude Code)
    Signed-off-by: Ricard Rosson <[email protected]>
---
 arch/arm/src/rp23xx/rp23xx_rng.c | 141 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 123 insertions(+), 18 deletions(-)

diff --git a/arch/arm/src/rp23xx/rp23xx_rng.c b/arch/arm/src/rp23xx/rp23xx_rng.c
index e2c7bca54f0..ccd5bdce857 100644
--- a/arch/arm/src/rp23xx/rp23xx_rng.c
+++ b/arch/arm/src/rp23xx/rp23xx_rng.c
@@ -28,6 +28,7 @@
 
 #include <sys/types.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -54,6 +55,20 @@
 
 #define RP23XX_TRNG_EHR_VALID  (1 << 0)
 
+/* RNG_ISR health-test error bits: a sample that failed the on-chip
+ * von-Neumann, CRNGT or autocorrelation test must be discarded.
+ */
+
+#define RP23XX_TRNG_ISR_ERRORS (RP23XX_TRNG_RNG_ISR_VN_ERR |     \
+                                RP23XX_TRNG_RNG_ISR_CRNGT_ERR |  \
+                                RP23XX_TRNG_RNG_ISR_AUTOCORR_ERR)
+
+/* Startup self-test: draw this many blocks and reject an obviously broken
+ * source (stuck or all-constant) before the RNG is trusted.
+ */
+
+#define RP23XX_TRNG_SELFTEST_BLOCKS  4
+
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
@@ -66,6 +81,8 @@ static ssize_t rp23xx_rng_read(struct file *filep, char 
*buffer,
  ****************************************************************************/
 
 static mutex_t g_rng_lock = NXMUTEX_INITIALIZER;
+static bool    g_rng_healthy;   /* startup self-test passed */
+static bool    g_rng_inited;
 
 static const struct file_operations g_rngops =
 {
@@ -81,13 +98,90 @@ static const struct file_operations g_rngops =
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: rp23xx_rng_collect
+ *
+ * Description:
+ *   Wait for one fresh 192-bit block into 'ehr', discarding any block the
+ *   on-chip health tests rejected (re-arming the source each time).  The
+ *   entropy source must already be enabled.
+ *
+ ****************************************************************************/
+
+static void rp23xx_rng_collect(uint32_t ehr[RP23XX_TRNG_EHR_WORDS])
+{
+  int i;
+
+  for (; ; )
+    {
+      uint32_t isr = getreg32(RP23XX_TRNG_RNG_ISR);
+
+      if ((isr & RP23XX_TRNG_ISR_ERRORS) != 0)
+        {
+          /* Health test failed: drop the block and restart the source. */
+
+          putreg32(0xffffffff, RP23XX_TRNG_RNG_ICR);
+          putreg32(0, RP23XX_TRNG_RND_SOURCE_ENABLE);
+          putreg32(1, RP23XX_TRNG_RND_SOURCE_ENABLE);
+          continue;
+        }
+
+      if ((isr & RP23XX_TRNG_RNG_ISR_EHR_VALID) != 0)
+        {
+          break;
+        }
+    }
+
+  for (i = 0; i < RP23XX_TRNG_EHR_WORDS; i++)
+    {
+      ehr[i] = getreg32(RP23XX_TRNG_EHR_DATA(i));
+    }
+
+  putreg32(0xffffffff, RP23XX_TRNG_RNG_ICR);
+}
+
+/****************************************************************************
+ * Name: rp23xx_rng_selftest
+ *
+ * Description:
+ *   Draw a few conditioned blocks at startup and reject an obviously broken
+ *   source (a stuck source emitting identical blocks).  The on-chip tests
+ *   cover statistical quality; this only catches a dead source before any
+ *   key is derived from it.  Returns true if the source looks healthy.
+ *
+ ****************************************************************************/
+
+static bool rp23xx_rng_selftest(void)
+{
+  uint32_t block[RP23XX_TRNG_SELFTEST_BLOCKS][RP23XX_TRNG_EHR_WORDS];
+  bool ok = true;
+  int i;
+
+  putreg32(1, RP23XX_TRNG_RND_SOURCE_ENABLE);
+
+  for (i = 0; i < RP23XX_TRNG_SELFTEST_BLOCKS; i++)
+    {
+      rp23xx_rng_collect(block[i]);
+
+      if (i > 0 && memcmp(block[i], block[i - 1],
+                          RP23XX_TRNG_EHR_BYTES) == 0)
+        {
+          ok = false;
+          break;
+        }
+    }
+
+  putreg32(0, RP23XX_TRNG_RND_SOURCE_ENABLE);
+  return ok;
+}
+
 /****************************************************************************
  * Name: rp23xx_rng_read
  *
  * Description:
- *   Fill 'buffer' with 'buflen' bytes of hardware entropy.  Enables the ring
- *   -oscillator source, then repeatedly waits for a valid 192-bit EHR and
- *   copies it out until the request is satisfied.
+ *   Fill 'buffer' with 'buflen' bytes of hardware entropy, discarding any
+ *   block the on-chip health tests reject.  Fails with -EIO if the startup
+ *   self-test found the source broken.
  *
  ****************************************************************************/
 
@@ -103,6 +197,12 @@ static ssize_t rp23xx_rng_read(struct file *filep, char 
*buffer,
       return ret;
     }
 
+  if (!g_rng_healthy)
+    {
+      nxmutex_unlock(&g_rng_lock);
+      return -EIO;
+    }
+
   /* Enable the entropy source. */
 
   putreg32(1, RP23XX_TRNG_RND_SOURCE_ENABLE);
@@ -111,22 +211,8 @@ static ssize_t rp23xx_rng_read(struct file *filep, char 
*buffer,
     {
       uint32_t ehr[RP23XX_TRNG_EHR_WORDS];
       size_t chunk;
-      int i;
-
-      /* Wait for the next 192-bit sample to become valid. */
-
-      while ((getreg32(RP23XX_TRNG_TRNG_VALID) & RP23XX_TRNG_EHR_VALID) == 0)
-        {
-        }
-
-      for (i = 0; i < RP23XX_TRNG_EHR_WORDS; i++)
-        {
-          ehr[i] = getreg32(RP23XX_TRNG_EHR_DATA(i));
-        }
 
-      /* Acknowledge the sample so the engine collects the next one. */
-
-      putreg32(0xffffffff, RP23XX_TRNG_RNG_ICR);
+      rp23xx_rng_collect(ehr);
 
       chunk = buflen - nread;
       if (chunk > RP23XX_TRNG_EHR_BYTES)
@@ -146,6 +232,23 @@ static ssize_t rp23xx_rng_read(struct file *filep, char 
*buffer,
   return (ssize_t)nread;
 }
 
+/****************************************************************************
+ * Name: rp23xx_rng_init
+ *
+ * Description:
+ *   Run the startup self-test once and latch the result.  Idempotent.
+ *
+ ****************************************************************************/
+
+static void rp23xx_rng_init(void)
+{
+  if (!g_rng_inited)
+    {
+      g_rng_healthy = rp23xx_rng_selftest();
+      g_rng_inited  = true;
+    }
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -162,6 +265,7 @@ static ssize_t rp23xx_rng_read(struct file *filep, char 
*buffer,
 #ifdef CONFIG_DEV_RANDOM
 void devrandom_register(void)
 {
+  rp23xx_rng_init();
   register_driver("/dev/random", &g_rngops, 0444, NULL);
 }
 #endif
@@ -178,6 +282,7 @@ void devrandom_register(void)
 #ifdef CONFIG_DEV_URANDOM_ARCH
 void devurandom_register(void)
 {
+  rp23xx_rng_init();
   register_driver("/dev/urandom", &g_rngops, 0444, NULL);
 }
 #endif

Reply via email to