136 lines
5.6 KiB
Diff
136 lines
5.6 KiB
Diff
|
|
From b628859b936c6d6348d2af9e6b6d2887c697b9b7 Mon Sep 17 00:00:00 2001
|
||
|
|
From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@linaro.org>
|
||
|
|
Date: Tue, 9 Apr 2024 16:19:27 +0200
|
||
|
|
Subject: [PATCH] hw/sd/sdhci: Do not update TRNMOD when Command Inhibit (DAT)
|
||
|
|
is set(CVE-2024-3447)
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
Per "SD Host Controller Standard Specification Version 3.00":
|
||
|
|
|
||
|
|
* 2.2.5 Transfer Mode Register (Offset 00Ch)
|
||
|
|
|
||
|
|
Writes to this register shall be ignored when the Command
|
||
|
|
Inhibit (DAT) in the Present State register is 1.
|
||
|
|
|
||
|
|
Do not update the TRNMOD register when Command Inhibit (DAT)
|
||
|
|
bit is set to avoid the present-status register going out of
|
||
|
|
sync, leading to malicious guest using DMA mode and overflowing
|
||
|
|
the FIFO buffer:
|
||
|
|
|
||
|
|
$ cat << EOF | qemu-system-i386 \
|
||
|
|
-display none -nographic -nodefaults \
|
||
|
|
-machine accel=qtest -m 512M \
|
||
|
|
-device sdhci-pci,sd-spec-version=3 \
|
||
|
|
-device sd-card,drive=mydrive \
|
||
|
|
-drive if=none,index=0,file=null-co://,format=raw,id=mydrive \
|
||
|
|
-qtest stdio
|
||
|
|
outl 0xcf8 0x80001013
|
||
|
|
outl 0xcfc 0x91
|
||
|
|
outl 0xcf8 0x80001001
|
||
|
|
outl 0xcfc 0x06000000
|
||
|
|
write 0x9100002c 0x1 0x05
|
||
|
|
write 0x91000058 0x1 0x16
|
||
|
|
write 0x91000005 0x1 0x04
|
||
|
|
write 0x91000028 0x1 0x08
|
||
|
|
write 0x16 0x1 0x21
|
||
|
|
write 0x19 0x1 0x20
|
||
|
|
write 0x9100000c 0x1 0x01
|
||
|
|
write 0x9100000e 0x1 0x20
|
||
|
|
write 0x9100000f 0x1 0x00
|
||
|
|
write 0x9100000c 0x1 0x00
|
||
|
|
write 0x91000020 0x1 0x00
|
||
|
|
EOF
|
||
|
|
|
||
|
|
Stack trace (part):
|
||
|
|
=================================================================
|
||
|
|
==89993==ERROR: AddressSanitizer: heap-buffer-overflow on address
|
||
|
|
0x615000029900 at pc 0x55d5f885700d bp 0x7ffc1e1e9470 sp 0x7ffc1e1e9468
|
||
|
|
WRITE of size 1 at 0x615000029900 thread T0
|
||
|
|
#0 0x55d5f885700c in sdhci_write_dataport hw/sd/sdhci.c:564:39
|
||
|
|
#1 0x55d5f8849150 in sdhci_write hw/sd/sdhci.c:1223:13
|
||
|
|
#2 0x55d5fa01db63 in memory_region_write_accessor system/memory.c:497:5
|
||
|
|
#3 0x55d5fa01d245 in access_with_adjusted_size system/memory.c:573:18
|
||
|
|
#4 0x55d5fa01b1a9 in memory_region_dispatch_write system/memory.c:1521:16
|
||
|
|
#5 0x55d5fa09f5c9 in flatview_write_continue system/physmem.c:2711:23
|
||
|
|
#6 0x55d5fa08f78b in flatview_write system/physmem.c:2753:12
|
||
|
|
#7 0x55d5fa08f258 in address_space_write system/physmem.c:2860:18
|
||
|
|
...
|
||
|
|
0x615000029900 is located 0 bytes to the right of 512-byte region
|
||
|
|
[0x615000029700,0x615000029900) allocated by thread T0 here:
|
||
|
|
#0 0x55d5f7237b27 in __interceptor_calloc
|
||
|
|
#1 0x7f9e36dd4c50 in g_malloc0
|
||
|
|
#2 0x55d5f88672f7 in sdhci_pci_realize hw/sd/sdhci-pci.c:36:5
|
||
|
|
#3 0x55d5f844b582 in pci_qdev_realize hw/pci/pci.c:2092:9
|
||
|
|
#4 0x55d5fa2ee74b in device_set_realized hw/core/qdev.c:510:13
|
||
|
|
#5 0x55d5fa325bfb in property_set_bool qom/object.c:2358:5
|
||
|
|
#6 0x55d5fa31ea45 in object_property_set qom/object.c:1472:5
|
||
|
|
#7 0x55d5fa332509 in object_property_set_qobject om/qom-qobject.c:28:10
|
||
|
|
#8 0x55d5fa31f6ed in object_property_set_bool qom/object.c:1541:15
|
||
|
|
#9 0x55d5fa2e2948 in qdev_realize hw/core/qdev.c:292:12
|
||
|
|
#10 0x55d5f8eed3f1 in qdev_device_add_from_qdict system/qdev-monitor.c:719:10
|
||
|
|
#11 0x55d5f8eef7ff in qdev_device_add system/qdev-monitor.c:738:11
|
||
|
|
#12 0x55d5f8f211f0 in device_init_func system/vl.c:1200:11
|
||
|
|
#13 0x55d5fad0877d in qemu_opts_foreach util/qemu-option.c:1135:14
|
||
|
|
#14 0x55d5f8f0df9c in qemu_create_cli_devices system/vl.c:2638:5
|
||
|
|
#15 0x55d5f8f0db24 in qmp_x_exit_preconfig system/vl.c:2706:5
|
||
|
|
#16 0x55d5f8f14dc0 in qemu_init system/vl.c:3737:9
|
||
|
|
...
|
||
|
|
SUMMARY: AddressSanitizer: heap-buffer-overflow hw/sd/sdhci.c:564:39
|
||
|
|
in sdhci_write_dataport
|
||
|
|
|
||
|
|
Add assertions to ensure the fifo_buffer[] is not overflowed by
|
||
|
|
malicious accesses to the Buffer Data Port register.
|
||
|
|
|
||
|
|
Fixes: CVE-2024-3447
|
||
|
|
Cc: qemu-stable@nongnu.org
|
||
|
|
Fixes: d7dfca0807 ("hw/sdhci: introduce standard SD host controller")
|
||
|
|
Buglink: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=58813
|
||
|
|
Reported-by: Alexander Bulekov <alxndr@bu.edu>
|
||
|
|
Reported-by: Chuhong Yuan <hslester96@gmail.com>
|
||
|
|
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||
|
|
Message-Id: <CAFEAcA9iLiv1XGTGKeopgMa8Y9+8kvptvsb8z2OBeuy+5=NUfg@mail.gmail.com>
|
||
|
|
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||
|
|
Message-Id: <20240409145524.27913-1-philmd@linaro.org>
|
||
|
|
---
|
||
|
|
hw/sd/sdhci.c | 8 ++++++++
|
||
|
|
1 file changed, 8 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
|
||
|
|
index 40473b0db0..e95ea34895 100644
|
||
|
|
--- a/hw/sd/sdhci.c
|
||
|
|
+++ b/hw/sd/sdhci.c
|
||
|
|
@@ -473,6 +473,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < size; i++) {
|
||
|
|
+ assert(s->data_count < s->buf_maxsz);
|
||
|
|
value |= s->fifo_buffer[s->data_count] << i * 8;
|
||
|
|
s->data_count++;
|
||
|
|
/* check if we've read all valid data (blksize bytes) from buffer */
|
||
|
|
@@ -561,6 +562,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < size; i++) {
|
||
|
|
+ assert(s->data_count < s->buf_maxsz);
|
||
|
|
s->fifo_buffer[s->data_count] = value & 0xFF;
|
||
|
|
s->data_count++;
|
||
|
|
value >>= 8;
|
||
|
|
@@ -1208,6 +1210,12 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
|
||
|
|
if (!(s->capareg & R_SDHC_CAPAB_SDMA_MASK)) {
|
||
|
|
value &= ~SDHC_TRNS_DMA;
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+ /* TRNMOD writes are inhibited while Command Inhibit (DAT) is true */
|
||
|
|
+ if (s->prnsts & SDHC_DATA_INHIBIT) {
|
||
|
|
+ mask |= 0xffff;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
MASKED_WRITE(s->trnmod, mask, value & SDHC_TRNMOD_MASK);
|
||
|
|
MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16);
|
||
|
|
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|