u-boot corruption from EFI CAAM RNG request

Anthony Pighin (Nokia) anthony.pighin at nokia.com
Mon Jul 14 14:53:46 CEST 2025


> u-boot is being corrupted following a Linux EFI callback to get_rng(). One of
> the many footprints is a corruption of the EFI protocols linked list.
> 
> Turns out that a request for >16 bytes of random data is broken into smaller
> requests.
> Those requests are fed in a loop to the CAAM RNG, which uses a job queue
> ring for interaction.
> 
> The problem is that in u-boot, the job queue descriptor is created only at
> probe time, but then u-boot needs to endian swap the descriptor fed to the
> CAAM RNG. So this corrupts the descriptor for the next iteration, since it will
> be blindly endian swapped yet again.
> 
> Two issues arise. The number of words to endian swap is taken from the
> input descriptor itself.
> So on the second iteration, the length has been corrupted. This results in a
> corruption past the end of the descriptor: whatever is after in memory is
> corrupted. Second, some of the entries in the descriptors are DMA addresses.
> So if the descriptor is still valid after swapping, the data at the corrupted DMA
> address is now corrupted.
> 
> Linux properly initializes the descriptor for each iterations.
> 
> Example:
> Iteration 1:
> desc[0]: 0xB0800005
> desc[1]: 0x82500002
> desc[2]: 0x60340010
> desc[3]: 0x00000000
> desc[4]: 0xFBC17380
> jr_enqueue: Start swap.
> 0xb0800005 -> 0x050080b0
> 0x82500002 -> 0x02005082
> 0x60340010 -> 0x10003460
> 0x00000000 -> 0x00000000
> 0xfbc17380 -> 0x8073c1fb
> 
> Iteration 2:
> desc[0]: 0x050080B0
> desc[1]: 0x02005082
> desc[2]: 0x10003460
> desc[3]: 0x00000000
> desc[4]: 0x8073C1FB
> jr_enqueue: Start swap.
> 0x050080b0 -> 0xb0800005
> 0x02005082 -> 0x82500002
> 0x10003460 -> 0x60340010
> 0x00000000 -> 0x00000000
> 0x8073c1fb -> 0xfbc17380
> 0x00000000 -> 0x00000000
> 0x00000000 -> 0x00000000
> 0x00000000 -> 0x00000000
> 0x00000000 -> 0x00000000
> 0x00000000 -> 0x00000000
> 0x00000000 -> 0x00000000
> 0x00000000 -> 0x00000000
> ...
> 
> Anthony
> 

Here is a proposed fix. The caam_rng_probe() init might not even be needed, but I left it there just in case.

diff --git a/drivers/crypto/fsl/rng.c b/drivers/crypto/fsl/rng.c
index 786a710f5fb..85544f931cb 100644
--- a/drivers/crypto/fsl/rng.c
+++ b/drivers/crypto/fsl/rng.c
@@ -23,11 +23,24 @@ struct caam_rng_priv {
        u8 data[CAAM_RNG_MAX_FIFO_STORE_SIZE] __aligned(ARCH_DMA_MINALIGN);
 };

+static int caam_init_desc(struct caam_rng_priv *priv)
+{
+       ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN);
+
+       inline_cnstr_jobdesc_rng(priv->desc, priv->data,
+                                CAAM_RNG_MAX_FIFO_STORE_SIZE);
+       flush_dcache_range((unsigned long)priv->desc,
+                          (unsigned long)priv->desc + size);
+
+       return 0;
+}
+
 static int caam_rng_read_one(struct caam_rng_priv *priv)
 {
        int size = ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE, ARCH_DMA_MINALIGN);
        int ret;

+       caam_init_desc(priv);
        ret = run_descriptor_jr(priv->desc);
        if (ret < 0)
                return -EIO;
@@ -63,12 +76,8 @@ static int caam_rng_read(struct udevice *dev, void *data, size_t len)
 static int caam_rng_probe(struct udevice *dev)
 {
        struct caam_rng_priv *priv = dev_get_priv(dev);
-       ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN);

-       inline_cnstr_jobdesc_rng(priv->desc, priv->data,
-                                CAAM_RNG_MAX_FIFO_STORE_SIZE);
-       flush_dcache_range((unsigned long)priv->desc,
-                          (unsigned long)priv->desc + size);
+       caam_init_desc(priv);

        return 0;
 }



More information about the U-Boot mailing list