SD/MMC patches queue

- sdcard: Check for valid address range in SEND_WRITE_PROT (CMD30)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmDsGT0ACgkQ4+MsLN6t
 wN7RWA//ZaQAu2yUa5usg51tZ7/xHEfMtjceC+sXnPmWz7nyJAN3TMZCg6UPjYhx
 fg4shiyRTbK8wTVeHzDpo0bbej+VdDQBAeb0QOdVhQUZVUnnrvL2Z+bjWpssI7o+
 3SaF5GOo+YkrliJggeqQCuPc/imW3qcX4SfiJGVXlmO2TxX4gppfp9nHr0o4DTGD
 joTvCv0snubANel2v4laR9wc5+DlbLB9yfGyt065DgVv0a0NxZr+k2npdE95FxZP
 iEoMOqL8NYx1WOO1C5hmUqLUcOhCtVGh1GeLpRJb/czJ7W7M20lLyaXJ0xwVUdA6
 058u4yf4xZTrslZSw1tTdfAkIkYKT5RCIs4utwhFSFmGS5N3kTwGrOIkvOIeT6QB
 wqaArLJK8vBVWOmgfgIEE19C28dWiL4lSCxJDyS8f2Y/JO1eBCFckTo5EHge0zRZ
 MdyWu6wIW8zGzkxW89XhChXeF93qSXBqRrrBYcCHQUhrEeX2/TX2SzMddOwt/Pv3
 mtvBV8cW8Od1pm7ZV/oR+Z6w80jDUHLFvyAQMGcU6uL6EzUAhSuDs0ukkgwUuUfM
 FZ9RZJDsu0H50NHQJ1WJN/46ixW8aI6H/AafctRK/pEZ1oU9n8eB91SoWTvdptAm
 yORq/snigg+R9p/VWnbZs2cZmdzOxmHkTgwdLRIoktir74Vxozs=
 =9vFl
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/philmd/tags/sdmmc-20210712' into staging

SD/MMC patches queue

- sdcard: Check for valid address range in SEND_WRITE_PROT (CMD30)

# gpg: Signature made Mon 12 Jul 2021 11:28:13 BST
# gpg:                using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD  6BB2 E3E3 2C2C DEAD C0DE

* remotes/philmd/tags/sdmmc-20210712:
  hw/sd/sdcard: Check for valid address range in SEND_WRITE_PROT (CMD30)
  hw/sd/sdcard: Extract address_in_range() helper, log invalid accesses
  hw/sd/sdcard: When card is in wrong state, log which state it is

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-07-12 21:22:27 +01:00
commit eca7371335
4 changed files with 97 additions and 14 deletions

View File

@ -1823,7 +1823,8 @@ F: include/hw/sd/sd*
F: hw/sd/core.c F: hw/sd/core.c
F: hw/sd/sd* F: hw/sd/sd*
F: hw/sd/ssi-sd.c F: hw/sd/ssi-sd.c
F: tests/qtest/sd* F: tests/qtest/fuzz-sdcard-test.c
F: tests/qtest/sdhci-test.c
USB USB
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>

View File

@ -937,6 +937,19 @@ static void sd_lock_command(SDState *sd)
sd->card_status &= ~CARD_IS_LOCKED; sd->card_status &= ~CARD_IS_LOCKED;
} }
static bool address_in_range(SDState *sd, const char *desc,
uint64_t addr, uint32_t length)
{
if (addr + length > sd->size) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s offset %"PRIu64" > card %"PRIu64" [%%%u]\n",
desc, addr, sd->size, length);
sd->card_status |= ADDRESS_ERROR;
return false;
}
return true;
}
static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
{ {
uint32_t rca = 0x0000; uint32_t rca = 0x0000;
@ -1218,8 +1231,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
switch (sd->state) { switch (sd->state) {
case sd_transfer_state: case sd_transfer_state:
if (addr + sd->blk_len > sd->size) { if (!address_in_range(sd, "READ_BLOCK", addr, sd->blk_len)) {
sd->card_status |= ADDRESS_ERROR;
return sd_r1; return sd_r1;
} }
@ -1264,8 +1276,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
switch (sd->state) { switch (sd->state) {
case sd_transfer_state: case sd_transfer_state:
if (addr + sd->blk_len > sd->size) { if (!address_in_range(sd, "WRITE_BLOCK", addr, sd->blk_len)) {
sd->card_status |= ADDRESS_ERROR;
return sd_r1; return sd_r1;
} }
@ -1325,8 +1336,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
switch (sd->state) { switch (sd->state) {
case sd_transfer_state: case sd_transfer_state:
if (addr >= sd->size) { if (!address_in_range(sd, "SET_WRITE_PROT", addr, 1)) {
sd->card_status |= ADDRESS_ERROR;
return sd_r1b; return sd_r1b;
} }
@ -1348,8 +1358,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
switch (sd->state) { switch (sd->state) {
case sd_transfer_state: case sd_transfer_state:
if (addr >= sd->size) { if (!address_in_range(sd, "CLR_WRITE_PROT", addr, 1)) {
sd->card_status |= ADDRESS_ERROR;
return sd_r1b; return sd_r1b;
} }
@ -1371,6 +1380,11 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
switch (sd->state) { switch (sd->state) {
case sd_transfer_state: case sd_transfer_state:
if (!address_in_range(sd, "SEND_WRITE_PROT",
req.arg, sd->blk_len)) {
return sd_r1;
}
sd->state = sd_sendingdata_state; sd->state = sd_sendingdata_state;
*(uint32_t *) sd->data = sd_wpbits(sd, req.arg); *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
sd->data_start = addr; sd->data_start = addr;
@ -1504,7 +1518,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
return sd_illegal; return sd_illegal;
} }
qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state\n", req.cmd); qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state: %s\n",
req.cmd, sd_state_name(sd->state));
return sd_illegal; return sd_illegal;
} }
@ -1825,8 +1840,8 @@ void sd_write_byte(SDState *sd, uint8_t value)
case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
if (sd->data_offset == 0) { if (sd->data_offset == 0) {
/* Start of the block - let's check the address is valid */ /* Start of the block - let's check the address is valid */
if (sd->data_start + sd->blk_len > sd->size) { if (!address_in_range(sd, "WRITE_MULTIPLE_BLOCK",
sd->card_status |= ADDRESS_ERROR; sd->data_start, sd->blk_len)) {
break; break;
} }
if (sd->size <= SDSC_MAX_CAPACITY) { if (sd->size <= SDSC_MAX_CAPACITY) {
@ -1998,8 +2013,8 @@ uint8_t sd_read_byte(SDState *sd)
case 18: /* CMD18: READ_MULTIPLE_BLOCK */ case 18: /* CMD18: READ_MULTIPLE_BLOCK */
if (sd->data_offset == 0) { if (sd->data_offset == 0) {
if (sd->data_start + io_len > sd->size) { if (!address_in_range(sd, "READ_MULTIPLE_BLOCK",
sd->card_status |= ADDRESS_ERROR; sd->data_start, io_len)) {
return 0x00; return 0x00;
} }
BLK_READ_BLOCK(sd->data_start, io_len); BLK_READ_BLOCK(sd->data_start, io_len);

View File

@ -0,0 +1,66 @@
/*
* QTest fuzzer-generated testcase for sdcard device
*
* Copyright (c) 2021 Philippe Mathieu-Daudé <f4bug@amsat.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "libqos/libqtest.h"
/*
* https://gitlab.com/qemu-project/qemu/-/issues/450
* Used to trigger:
* Assertion `wpnum < sd->wpgrps_size' failed.
*/
static void oss_fuzz_29225(void)
{
QTestState *s;
s = qtest_init(" -display none -m 512m -nodefaults -nographic"
" -device sdhci-pci,sd-spec-version=3"
" -device sd-card,drive=d0"
" -drive if=none,index=0,file=null-co://,format=raw,id=d0");
qtest_outl(s, 0xcf8, 0x80001010);
qtest_outl(s, 0xcfc, 0xd0690);
qtest_outl(s, 0xcf8, 0x80001003);
qtest_outl(s, 0xcf8, 0x80001013);
qtest_outl(s, 0xcfc, 0xffffffff);
qtest_outl(s, 0xcf8, 0x80001003);
qtest_outl(s, 0xcfc, 0x3effe00);
qtest_bufwrite(s, 0xff0d062c, "\xff", 0x1);
qtest_bufwrite(s, 0xff0d060f, "\xb7", 0x1);
qtest_bufwrite(s, 0xff0d060a, "\xc9", 0x1);
qtest_bufwrite(s, 0xff0d060f, "\x29", 0x1);
qtest_bufwrite(s, 0xff0d060f, "\xc2", 0x1);
qtest_bufwrite(s, 0xff0d0628, "\xf7", 0x1);
qtest_bufwrite(s, 0x0, "\xe3", 0x1);
qtest_bufwrite(s, 0x7, "\x13", 0x1);
qtest_bufwrite(s, 0x8, "\xe3", 0x1);
qtest_bufwrite(s, 0xf, "\xe3", 0x1);
qtest_bufwrite(s, 0xff0d060f, "\x03", 0x1);
qtest_bufwrite(s, 0xff0d0605, "\x01", 0x1);
qtest_bufwrite(s, 0xff0d060b, "\xff", 0x1);
qtest_bufwrite(s, 0xff0d060c, "\xff", 0x1);
qtest_bufwrite(s, 0xff0d060e, "\xff", 0x1);
qtest_bufwrite(s, 0xff0d060f, "\x06", 0x1);
qtest_bufwrite(s, 0xff0d060f, "\x9e", 0x1);
qtest_quit(s);
}
int main(int argc, char **argv)
{
const char *arch = qtest_get_arch();
g_test_init(&argc, &argv, NULL);
if (strcmp(arch, "i386") == 0) {
qtest_add_func("fuzz/sdcard/oss_fuzz_29225", oss_fuzz_29225);
}
return g_test_run();
}

View File

@ -21,6 +21,7 @@ qtests_generic = \
(config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \ (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
(config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \
[ [
'cdrom-test', 'cdrom-test',
'device-introspect-test', 'device-introspect-test',