mirror of https://gitee.com/openkylin/qemu.git
SD/MMC patches
Fix two heap-overflow reported by Alexander Bulekov while fuzzing: - https://bugs.launchpad.net/qemu/+bug/1892960 - https://bugs.launchpad.net/qemu/+bug/1895310 CI jobs results: . https://cirrus-ci.com/build/6399328187056128 . https://gitlab.com/philmd/qemu/-/pipelines/205701966 . https://travis-ci.org/github/philmd/qemu/builds/737708930 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAl+QcNQACgkQ4+MsLN6t wN5Bng/8C2xAFjxnXGbyDq3KKNX6+ag82pZc1+wI4PiYvjCNwQ3BL3FMU6Itu/xE 8bqI5UMlVQGJ0npS8YL4AYdU1wuyk5kb30oXubj+uKreMLd7gVgZSi6rM0C3xDu1 6atNYZK3BDbIdbKKoSx9cOAGnvsI0/gjei+OcmPRzyqQff7RLrOdIW0OaGqrKkjc ovvtV2gWxTo16HSe2pji4lfw6WkE4H8EshU1YA5ZgIhyQ6HvVz9qLd9QC3zyu9pl GfeHqEj9BQCnwGTpISewJVCAWdEQyygQxdbTpSEMYyN9A52WB3+Ne/AFESfoDYU4 dc3lefUEjim+EiddB2cGtMjXER8m0Xrl3Z9raRLj5Mrb9bVx+gso1/0L9utQLCy6 eVOGwSFZQ0Va64ng3z5w0tliLEB61B3nDNsIQSU2WLjQxGUVwli6YhHaGXbW9F39 hU0yuqch2cHpUtlvZREymsTkV1cTr1NXmyXN/fzIiDyi8GQZ54AP16eVW/jrj1Bn Rf1Q0ywe0zb/+bFK/oq6tN9zIoV1/DaJlKQSjmDFdIUBqaSxcUrj53yUHsno/slh U7cj2ItvlpOljpUrKgV4bVbP7UWsOPC9RX9j5YbkwpHevyWdk/XNlzxoEJAe8Zj1 3AdWsCtnxFdgLLEF3Y2tOENbVUI6Axo7If1oz83X0N782YZMbW8= =9A05 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/philmd-gitlab/tags/sd-next-20201021' into staging SD/MMC patches Fix two heap-overflow reported by Alexander Bulekov while fuzzing: - https://bugs.launchpad.net/qemu/+bug/1892960 - https://bugs.launchpad.net/qemu/+bug/1895310 CI jobs results: . https://cirrus-ci.com/build/6399328187056128 . https://gitlab.com/philmd/qemu/-/pipelines/205701966 . https://travis-ci.org/github/philmd/qemu/builds/737708930 # gpg: Signature made Wed 21 Oct 2020 18:33:08 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-gitlab/tags/sd-next-20201021: hw/sd/sdcard: Assert if accessing an illegal group hw/sd/sdcard: Do not attempt to erase out of range addresses hw/sd/sdcard: Reset both start/end addresses on error hw/sd/sdcard: Do not use legal address '0' for INVALID_ADDRESS hw/sd/sdcard: Introduce the INVALID_ADDRESS definition hw/sd/sdcard: Add trace event for ERASE command (CMD38) hw/sd/sdhci: Yield if interrupt delivered during multiple transfer hw/sd/sdhci: Let sdhci_update_irq() return if IRQ was delivered hw/sd/sdhci: Resume pending DMA transfers on MMIO accesses hw/sd/sdhci: Stop multiple transfers when block count is cleared hw/sd/sdhci: Fix DMA Transfer Block Size field hw/sd/sdhci: Document the datasheet used hw/sd/sdhci: Fix qemu_log_mask() format string Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
eec4682e99
30
hw/sd/sd.c
30
hw/sd/sd.c
|
@ -53,6 +53,8 @@
|
|||
|
||||
#define SDSC_MAX_CAPACITY (2 * GiB)
|
||||
|
||||
#define INVALID_ADDRESS UINT32_MAX
|
||||
|
||||
typedef enum {
|
||||
sd_r0 = 0, /* no response */
|
||||
sd_r1, /* normal response command */
|
||||
|
@ -575,8 +577,8 @@ static void sd_reset(DeviceState *dev)
|
|||
sd->wpgrps_size = sect;
|
||||
sd->wp_groups = bitmap_new(sd->wpgrps_size);
|
||||
memset(sd->function_group, 0, sizeof(sd->function_group));
|
||||
sd->erase_start = 0;
|
||||
sd->erase_end = 0;
|
||||
sd->erase_start = INVALID_ADDRESS;
|
||||
sd->erase_end = INVALID_ADDRESS;
|
||||
sd->size = size;
|
||||
sd->blk_len = 0x200;
|
||||
sd->pwd_len = 0;
|
||||
|
@ -664,8 +666,8 @@ static int sd_vmstate_pre_load(void *opaque)
|
|||
|
||||
static const VMStateDescription sd_vmstate = {
|
||||
.name = "sd-card",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.pre_load = sd_vmstate_pre_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(mode, SDState),
|
||||
|
@ -749,9 +751,12 @@ static void sd_erase(SDState *sd)
|
|||
uint64_t erase_start = sd->erase_start;
|
||||
uint64_t erase_end = sd->erase_end;
|
||||
|
||||
trace_sdcard_erase();
|
||||
if (!sd->erase_start || !sd->erase_end) {
|
||||
trace_sdcard_erase(sd->erase_start, sd->erase_end);
|
||||
if (sd->erase_start == INVALID_ADDRESS
|
||||
|| sd->erase_end == INVALID_ADDRESS) {
|
||||
sd->card_status |= ERASE_SEQ_ERROR;
|
||||
sd->erase_start = INVALID_ADDRESS;
|
||||
sd->erase_end = INVALID_ADDRESS;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -761,13 +766,21 @@ static void sd_erase(SDState *sd)
|
|||
erase_end *= 512;
|
||||
}
|
||||
|
||||
if (sd->erase_start > sd->size || sd->erase_end > sd->size) {
|
||||
sd->card_status |= OUT_OF_RANGE;
|
||||
sd->erase_start = INVALID_ADDRESS;
|
||||
sd->erase_end = INVALID_ADDRESS;
|
||||
return;
|
||||
}
|
||||
|
||||
erase_start = sd_addr_to_wpnum(erase_start);
|
||||
erase_end = sd_addr_to_wpnum(erase_end);
|
||||
sd->erase_start = 0;
|
||||
sd->erase_end = 0;
|
||||
sd->erase_start = INVALID_ADDRESS;
|
||||
sd->erase_end = INVALID_ADDRESS;
|
||||
sd->csd[14] |= 0x40;
|
||||
|
||||
for (i = erase_start; i <= erase_end; i++) {
|
||||
assert(i < sd->wpgrps_size);
|
||||
if (test_bit(i, sd->wp_groups)) {
|
||||
sd->card_status |= WP_ERASE_SKIP;
|
||||
}
|
||||
|
@ -782,6 +795,7 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
|
|||
wpnum = sd_addr_to_wpnum(addr);
|
||||
|
||||
for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) {
|
||||
assert(wpnum < sd->wpgrps_size);
|
||||
if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) {
|
||||
ret |= (1 << i);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/*
|
||||
* SD Association Host Standard Specification v2.0 controller emulation
|
||||
*
|
||||
* Datasheet: PartA2_SD_Host_Controller_Simplified_Specification_Ver2.00.pdf
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Mitsyanko Igor <i.mitsyanko@samsung.com>
|
||||
* Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
|
@ -216,9 +218,14 @@ static uint8_t sdhci_slotint(SDHCIState *s)
|
|||
((s->norintsts & SDHC_NIS_REMOVE) && (s->wakcon & SDHC_WKUP_ON_RMV));
|
||||
}
|
||||
|
||||
static inline void sdhci_update_irq(SDHCIState *s)
|
||||
/* Return true if IRQ was pending and delivered */
|
||||
static bool sdhci_update_irq(SDHCIState *s)
|
||||
{
|
||||
qemu_set_irq(s->irq, sdhci_slotint(s));
|
||||
bool pending = sdhci_slotint(s);
|
||||
|
||||
qemu_set_irq(s->irq, pending);
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
static void sdhci_raise_insertion_irq(void *opaque)
|
||||
|
@ -729,6 +736,12 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
ADMADescr dscr = {};
|
||||
int i;
|
||||
|
||||
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN && !s->blkcnt) {
|
||||
/* Stop Multiple Transfer */
|
||||
sdhci_end_transfer(s);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) {
|
||||
s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH;
|
||||
|
||||
|
@ -754,7 +767,6 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
|
||||
switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) {
|
||||
case SDHC_ADMA_ATTR_ACT_TRAN: /* data transfer */
|
||||
|
||||
if (s->trnmod & SDHC_TRNS_READ) {
|
||||
while (length) {
|
||||
if (s->data_count == 0) {
|
||||
|
@ -825,7 +837,10 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
s->norintsts |= SDHC_NIS_DMA;
|
||||
}
|
||||
|
||||
sdhci_update_irq(s);
|
||||
if (sdhci_update_irq(s) && !(dscr.attr & SDHC_ADMA_ATTR_END)) {
|
||||
/* IRQ delivered, reschedule current transfer */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ADMA transfer terminates if blkcnt == 0 or by END attribute */
|
||||
|
@ -941,11 +956,21 @@ sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void sdhci_resume_pending_transfer(SDHCIState *s)
|
||||
{
|
||||
timer_del(s->transfer_timer);
|
||||
sdhci_data_transfer(s);
|
||||
}
|
||||
|
||||
static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
SDHCIState *s = (SDHCIState *)opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (timer_pending(s->transfer_timer)) {
|
||||
sdhci_resume_pending_transfer(s);
|
||||
}
|
||||
|
||||
switch (offset & ~0x3) {
|
||||
case SDHC_SYSAD:
|
||||
ret = s->sdmasysad;
|
||||
|
@ -1089,6 +1114,10 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
|
|||
uint32_t value = val;
|
||||
value <<= shift;
|
||||
|
||||
if (timer_pending(s->transfer_timer)) {
|
||||
sdhci_resume_pending_transfer(s);
|
||||
}
|
||||
|
||||
switch (offset & ~0x3) {
|
||||
case SDHC_SYSAD:
|
||||
s->sdmasysad = (s->sdmasysad & mask) | value;
|
||||
|
@ -1105,14 +1134,14 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
|
|||
break;
|
||||
case SDHC_BLKSIZE:
|
||||
if (!TRANSFERRING_DATA(s->prnsts)) {
|
||||
MASKED_WRITE(s->blksize, mask, value);
|
||||
MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12));
|
||||
MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16);
|
||||
}
|
||||
|
||||
/* Limit block size to the maximum buffer size */
|
||||
if (extract32(s->blksize, 0, 12) > s->buf_maxsz) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than "
|
||||
"the maximum buffer 0x%x", __func__, s->blksize,
|
||||
"the maximum buffer 0x%x\n", __func__, s->blksize,
|
||||
s->buf_maxsz);
|
||||
|
||||
s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz);
|
||||
|
|
|
@ -46,7 +46,7 @@ sdcard_reset(void) ""
|
|||
sdcard_set_blocklen(uint16_t length) "0x%03x"
|
||||
sdcard_inserted(bool readonly) "read_only: %u"
|
||||
sdcard_ejected(void) ""
|
||||
sdcard_erase(void) ""
|
||||
sdcard_erase(uint32_t first, uint32_t last) "addr first 0x%" PRIx32" last 0x%" PRIx32
|
||||
sdcard_lock(void) ""
|
||||
sdcard_unlock(void) ""
|
||||
sdcard_read_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x"
|
||||
|
|
Loading…
Reference in New Issue