Skip to content

Commit 790762e

Browse files
committed
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: [email protected] Reported-by: Alexander Bulekov <[email protected]> Buglink: https://bugs.launchpad.net/qemu/+bug/1880822 Reviewed-by: Peter Maydell <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]> Reviewed-by: Alistair Francis <[email protected]> Message-Id: <[email protected]>
1 parent 794d68d commit 790762e

File tree

1 file changed

+24
-14
lines changed

1 file changed

+24
-14
lines changed

hw/sd/sd.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,13 +1171,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
11711171
case 17: /* CMD17: READ_SINGLE_BLOCK */
11721172
switch (sd->state) {
11731173
case sd_transfer_state:
1174-
sd->state = sd_sendingdata_state;
1175-
sd->data_start = addr;
1176-
sd->data_offset = 0;
11771174

1178-
if (sd->data_start + sd->blk_len > sd->size) {
1175+
if (addr + sd->blk_len > sd->size) {
11791176
sd->card_status |= ADDRESS_ERROR;
1177+
return sd_r1;
11801178
}
1179+
1180+
sd->state = sd_sendingdata_state;
1181+
sd->data_start = addr;
1182+
sd->data_offset = 0;
11811183
return sd_r1;
11821184

11831185
default:
@@ -1188,13 +1190,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
11881190
case 18: /* CMD18: READ_MULTIPLE_BLOCK */
11891191
switch (sd->state) {
11901192
case sd_transfer_state:
1191-
sd->state = sd_sendingdata_state;
1192-
sd->data_start = addr;
1193-
sd->data_offset = 0;
11941193

1195-
if (sd->data_start + sd->blk_len > sd->size) {
1194+
if (addr + sd->blk_len > sd->size) {
11961195
sd->card_status |= ADDRESS_ERROR;
1196+
return sd_r1;
11971197
}
1198+
1199+
sd->state = sd_sendingdata_state;
1200+
sd->data_start = addr;
1201+
sd->data_offset = 0;
11981202
return sd_r1;
11991203

12001204
default:
@@ -1234,14 +1238,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
12341238
/* Writing in SPI mode not implemented. */
12351239
if (sd->spi)
12361240
break;
1241+
1242+
if (addr + sd->blk_len > sd->size) {
1243+
sd->card_status |= ADDRESS_ERROR;
1244+
return sd_r1;
1245+
}
1246+
12371247
sd->state = sd_receivingdata_state;
12381248
sd->data_start = addr;
12391249
sd->data_offset = 0;
12401250
sd->blk_written = 0;
12411251

1242-
if (sd->data_start + sd->blk_len > sd->size) {
1243-
sd->card_status |= ADDRESS_ERROR;
1244-
}
12451252
if (sd_wp_addr(sd, sd->data_start)) {
12461253
sd->card_status |= WP_VIOLATION;
12471254
}
@@ -1261,14 +1268,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
12611268
/* Writing in SPI mode not implemented. */
12621269
if (sd->spi)
12631270
break;
1271+
1272+
if (addr + sd->blk_len > sd->size) {
1273+
sd->card_status |= ADDRESS_ERROR;
1274+
return sd_r1;
1275+
}
1276+
12641277
sd->state = sd_receivingdata_state;
12651278
sd->data_start = addr;
12661279
sd->data_offset = 0;
12671280
sd->blk_written = 0;
12681281

1269-
if (sd->data_start + sd->blk_len > sd->size) {
1270-
sd->card_status |= ADDRESS_ERROR;
1271-
}
12721282
if (sd_wp_addr(sd, sd->data_start)) {
12731283
sd->card_status |= WP_VIOLATION;
12741284
}

0 commit comments

Comments
 (0)