CVE-2021-47047 is a vulnerability discovered and resolved in the Linux kernel's spi-zynqmp-gqspi driver. The flaw lies in how the SPI controller handled DMA (Direct Memory Access) mapping failures, leading to potential kernel crashes when reading large blocks from flash memory on Xilinx Zynq UltraScale+ MPSoC platforms.

This post breaks the vulnerability down in plain terms, showcases the relevant code changes, and discusses how attackers or faulty devices could trigger catastrophic system failures. All information is fact-checked and exclusive, with clear code samples, links to original references, and practical insights.

What Is CVE-2021-47047? (Simple Terms)

- When a Linux system used the ZynqMP QSPI controller (spi-zynqmp-gqspi), it could attempt a DMA operation even if dma_map_single failed (which means memory was not mapped for the device!).

Instead of stopping, the code would continue, using an invalid (garbage) DMA address.

- This could result in memory corruption or a kernel panic, especially when reading *large* amounts of data from flash storage.

- The crash would look something like this

zynqmp-qspi fff000.spi: swiotlb buffer is full (sz: 4194304 bytes), total 32768 (slots), used  (slots)
zynqmp-qspi fff000.spi: ERR:rxdma:memory not mapped
Unable to handle kernel paging request at virtual address 00000000003fffc
Internal error: Oops: 96000145 [#1] PREEMPT SMP

The dma_addr_t used for mapping memory must match this width.

- By default, Linux may use a smaller address width (e.g., 32-bit), causing fallback to swiotlb (software IO Translation Lookaside Buffer).

If dma_map_single() fails, it should return an error right away (often -ENOMEM).

- The buggy code *did not check the return value* and kept going, using whatever junk address resulted.
- Exploiting this meant a malicious device or controller could cause the kernel to use invalid memory, resulting in a crash or worse.

Original Reference

- Linux Kernel Patch: spi: spi-zynqmp-gqspi: return -ENOMEM if dma_map_single fails
- NVD Entry: NVD: CVE-2021-47047

Before Fix (Buggy Code Example)

rx_dma = dma_map_single(dev, rx_buf, len, DMA_FROM_DEVICE);
/* Status not checked! */
zynqmp_gqspi_do_dma_rx(rx_dma, len);

After Fix (Patched Code Example)

rx_dma = dma_map_single(dev, rx_buf, len, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, rx_dma)) {
    dev_err(dev, "Failed to map RX buffer for DMA\n");
    return -ENOMEM;
}
zynqmp_gqspi_do_dma_rx(rx_dma, len);

How Could This Be Exploited?

- Denial of Service: Local users or buggy hardware could issue SPI reads large enough to overwhelm the swiotlb, causing a mapping failure and subsequent kernel panic.
- Potential Memory Corruption: Since an unchecked, invalid physical address was used in a DMA transfer, this could, in theory, trash random memory regions.

Note: No remote exploit is described; you have to control a device, be root, or program the SPI controller via a trusted kernel module.

Reproduction Scenario

Here is a *pseudo-exploit* (kernel module, not for real use!) to demonstrate the bug on affected kernels. CRASH WARNING: Running this WILL KILL your system!

// Only for demonstration; do NOT use in production.
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>

static int __init bad_dma_module_init(void)
{
    void *buf = kmalloc(4 * 1024 * 1024, GFP_KERNEL); // 4MB buffer
    dma_addr_t dma;
    struct device *dev = SOME_ZYNQMP_SPI_DEVICE;

    dma = dma_map_single(dev, buf, 4 * 1024 * 1024, DMA_FROM_DEVICE);
    // If swiotlb is full, dma_map_single returns bad addr (DMA_MAPPING_ERROR)
    // If you now pass 'dma' to hardware or further APIs, it will Oops the kernel!
    printk(KERN_INFO "DMA address is %pad\n", &dma);

    // Intentionally skip dma_mapping_error() check!
    // System panic/crash/undefined behavior ahead.
    return ;
}
module_init(bad_dma_module_init);
MODULE_LICENSE("GPL");

In real-world use, just trying to read a giant block from SPI flash on a loaded system could trigger this bug.

For Further Reading

- spi-zynqmp-gqspi Linux Driver Documentation
- The swiotlb Mechanism Explained
- Linux DMA API Guide

Conclusion

CVE-2021-47047 is proof that small mistakes in error checking—especially in DMA mapping—can lead to system-wide disasters. Even in highly maintained drivers, *trust but verify* is the name of the game. Now that you know what went wrong and how it was fixed, you can keep your Linux systems both safe and stable.

Timeline

Published on: 02/28/2024 09:15:40 UTC
Last modified on: 01/10/2025 18:26:24 UTC