hw/sd/sdcard: Do not switch to ReceivingData if address is invalid
Only move the state machine to ReceivingData if there is no pending error. This avoids later OOB access while processing commands queued. "SD Specifications Part 1 Physical Layer Simplified Spec. v3.01" 4.3.3 Data Read Read command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR occurred and no data transfer is performed. 4.3.4 Data Write Write command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR occurred and no data transfer is performed. WP_VIOLATION errors are not modified: the error bit is set, we stay in receive-data state, wait for a stop command. All further data transfer is ignored. See the check on sd->card_status at the beginning of sd_read_data() and sd_write_data(). Fixes: CVE-2020-13253 Cc: qemu-stable@nongnu.org Reported-by: Alexander Bulekov <alxndr@bu.edu> Buglink: https://bugs.launchpad.net/qemu/+bug/1880822 Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-Id: <20200630133912.9428-6-f4bug@amsat.org>
This commit is contained in:
parent
794d68de2f
commit
790762e548
38
hw/sd/sd.c
38
hw/sd/sd.c
@ -1171,13 +1171,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
|
||||
case 17: /* CMD17: READ_SINGLE_BLOCK */
|
||||
switch (sd->state) {
|
||||
case sd_transfer_state:
|
||||
|
||||
if (addr + sd->blk_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
return sd_r1;
|
||||
}
|
||||
|
||||
sd->state = sd_sendingdata_state;
|
||||
sd->data_start = addr;
|
||||
sd->data_offset = 0;
|
||||
|
||||
if (sd->data_start + sd->blk_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
}
|
||||
return sd_r1;
|
||||
|
||||
default:
|
||||
@ -1188,13 +1190,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
|
||||
case 18: /* CMD18: READ_MULTIPLE_BLOCK */
|
||||
switch (sd->state) {
|
||||
case sd_transfer_state:
|
||||
|
||||
if (addr + sd->blk_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
return sd_r1;
|
||||
}
|
||||
|
||||
sd->state = sd_sendingdata_state;
|
||||
sd->data_start = addr;
|
||||
sd->data_offset = 0;
|
||||
|
||||
if (sd->data_start + sd->blk_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
}
|
||||
return sd_r1;
|
||||
|
||||
default:
|
||||
@ -1234,14 +1238,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
|
||||
/* Writing in SPI mode not implemented. */
|
||||
if (sd->spi)
|
||||
break;
|
||||
|
||||
if (addr + sd->blk_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
return sd_r1;
|
||||
}
|
||||
|
||||
sd->state = sd_receivingdata_state;
|
||||
sd->data_start = addr;
|
||||
sd->data_offset = 0;
|
||||
sd->blk_written = 0;
|
||||
|
||||
if (sd->data_start + sd->blk_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
}
|
||||
if (sd_wp_addr(sd, sd->data_start)) {
|
||||
sd->card_status |= WP_VIOLATION;
|
||||
}
|
||||
@ -1261,14 +1268,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
|
||||
/* Writing in SPI mode not implemented. */
|
||||
if (sd->spi)
|
||||
break;
|
||||
|
||||
if (addr + sd->blk_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
return sd_r1;
|
||||
}
|
||||
|
||||
sd->state = sd_receivingdata_state;
|
||||
sd->data_start = addr;
|
||||
sd->data_offset = 0;
|
||||
sd->blk_written = 0;
|
||||
|
||||
if (sd->data_start + sd->blk_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
}
|
||||
if (sd_wp_addr(sd, sd->data_start)) {
|
||||
sd->card_status |= WP_VIOLATION;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user