aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2024-04-10 14:43:11 +0100
committerPeter Maydell <peter.maydell@linaro.org>2024-04-10 14:43:11 +0100
commitf243175727903a0d2b52422e7baef86c1838a895 (patch)
tree0053806f66e324d5dfe37a9c8c1ffb61079f6694
parentfee571c7afced9bf4b01b864ea6e85f00fb50e30 (diff)
parentdcb0a1ac03d6b5ba6c7fcbe467f0215738006113 (diff)
Merge tag 'hw-misc-20240410' of https://github.com/philmd/qemu into staging
Misc HW patch queue - Fix CXL Fixed Memory Window interleave-granularity typo - Fix for DMA re-entrancy abuse with VirtIO devices (CVE-2024-3446) - Fix out-of-bound access in NAND block buffer - Fix memory leak in AppleSMC reset() handler - Avoid VirtIO crypto backends abort o invalid session ID - Fix overflow in LAN9118 MIL TX FIFO - Fix overflow when abusing SDHCI TRNMOD register (CVE-2024-3447) - Fix overrun in short fragmented packet SCTP checksum (CVE-2024-3567) - Remove unused assignment in virtio-snd model (Coverity 1542933 & 1542934) # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmYWV94ACgkQ4+MsLN6t # wN4+ew/+PqDmL4S8xXGQPi6Q8fxAogbwo1mPptDO2y8ChEjtc9LI5HOLu90EYz7A # s62SPDsh3gx8vOthrJVEk0LqCbw4N3s5dFdmHNrnjXCsKQFifgucQ+yZy8ipy34N # wWHSJ9nipBQLvkK23iCxkbl3cTyr44Rlweae/TZR4/FjFCEe3N555LQU0fruEqRo # AHW1RjYhGvOfL9knLWzIQqW2QjcCnKky3bJhwHh3crfWE69nvVJTkbSF6oUxWSG0 # RzSToK3nN5tmvUlyvbTBE9u0K9JkOcbtMQiAgj39nR9xpsaUZZa0zSWOmliYIuBC # kWuUY0/nAQk6gxHBKyu8q09ACBbzeCp+lVPOYXdxax8QMeURSa9fB1qY7JmI5QAZ # bg0ypD2pvbxhidU5TWpw7araAYyBOJrEYjnOkhXB4oa01ZWu2d0uNhGWo83h3Wjy # ahKrNDoVIQIdh8QkYy/ZqDwhCMoNM+pQcfUzsYxkqZC/JiiM/qxm87pTHQ/x2yQA # l0MLzljGv90/dklokrqeg4REwMqfwzc74PUbKdCk43saemmatslK3ktu3xAzUlQW # 2xmZQTnKwXDf+U3YnYryDddow2LsU7qlu8dlDGNd0WIrE5LRCCXzhv8la66O0jVE # qMOHpBPkwMlACBwiXuxV6ucelk4vy+XvabeQUsizm0m+PR7TwJY= # =9phd # -----END PGP SIGNATURE----- # gpg: Signature made Wed 10 Apr 2024 10:11:58 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 * tag 'hw-misc-20240410' of https://github.com/philmd/qemu: hw/audio/virtio-snd: Remove unused assignment hw/net/net_tx_pkt: Fix overrun in update_sctp_checksum() hw/sd/sdhci: Do not update TRNMOD when Command Inhibit (DAT) is set hw/net/lan9118: Fix overflow in MIL TX FIFO hw/net/lan9118: Replace magic '2048' value by MIL_TXFIFO_SIZE definition backends/cryptodev: Do not abort for invalid session ID hw/misc/applesmc: Fix memory leak in reset() handler hw/misc/applesmc: Do not call DeviceReset from DeviceRealize hw/block/nand: Fix out-of-bound access in NAND block buffer hw/block/nand: Have blk_load() take unsigned offset and return boolean hw/block/nand: Factor nand_load_iolen() method out qemu-options: Fix CXL Fixed Memory Window interleave-granularity typo hw/virtio/virtio-crypto: Protect from DMA re-entrancy bugs hw/char/virtio-serial-bus: Protect from DMA re-entrancy bugs hw/display/virtio-gpu: Protect from DMA re-entrancy bugs hw/virtio: Introduce virtio_bh_new_guarded() helper Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--backends/cryptodev-builtin.c4
-rw-r--r--hw/audio/virtio-snd.c8
-rw-r--r--hw/block/nand.c55
-rw-r--r--hw/char/virtio-serial-bus.c3
-rw-r--r--hw/display/virtio-gpu.c6
-rw-r--r--hw/misc/applesmc.c2
-rw-r--r--hw/net/lan9118.c28
-rw-r--r--hw/net/net_tx_pkt.c4
-rw-r--r--hw/sd/sdhci.c8
-rw-r--r--hw/virtio/virtio-crypto.c4
-rw-r--r--hw/virtio/virtio.c10
-rw-r--r--include/hw/virtio/virtio.h7
-rw-r--r--qemu-options.hx6
13 files changed, 109 insertions, 36 deletions
diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index 39d0455280..a514bbb310 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -427,7 +427,9 @@ static int cryptodev_builtin_close_session(
CRYPTODEV_BACKEND_BUILTIN(backend);
CryptoDevBackendBuiltinSession *session;
- assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]);
+ if (session_id >= MAX_NUM_SESSIONS || !builtin->sessions[session_id]) {
+ return -VIRTIO_CRYPTO_INVSESS;
+ }
session = builtin->sessions[session_id];
if (session->cipher) {
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 90d9a2796e..c80b58bf5d 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -885,7 +885,9 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
}
trace_virtio_snd_handle_tx_xfer();
- for (VirtIOSoundPCMStream *stream = NULL;; stream = NULL) {
+ for (;;) {
+ VirtIOSoundPCMStream *stream;
+
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
@@ -964,7 +966,9 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
}
trace_virtio_snd_handle_rx_xfer();
- for (VirtIOSoundPCMStream *stream = NULL;; stream = NULL) {
+ for (;;) {
+ VirtIOSoundPCMStream *stream;
+
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
diff --git a/hw/block/nand.c b/hw/block/nand.c
index d1435f2207..e2433c25bd 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -84,7 +84,11 @@ struct NANDFlashState {
void (*blk_write)(NANDFlashState *s);
void (*blk_erase)(NANDFlashState *s);
- void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
+ /*
+ * Returns %true when block containing (@addr + @offset) is
+ * successfully loaded, otherwise %false.
+ */
+ bool (*blk_load)(NANDFlashState *s, uint64_t addr, unsigned offset);
uint32_t ioaddr_vmstate;
};
@@ -243,9 +247,30 @@ static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
}
}
+/*
+ * nand_load_block: Load block containing (s->addr + @offset).
+ * Returns length of data available at @offset in this block.
+ */
+static unsigned nand_load_block(NANDFlashState *s, unsigned offset)
+{
+ unsigned iolen;
+
+ if (!s->blk_load(s, s->addr, offset)) {
+ return 0;
+ }
+
+ iolen = (1 << s->page_shift);
+ if (s->gnd) {
+ iolen += 1 << s->oob_shift;
+ }
+ assert(offset <= iolen);
+ iolen -= offset;
+
+ return iolen;
+}
+
static void nand_command(NANDFlashState *s)
{
- unsigned int offset;
switch (s->cmd) {
case NAND_CMD_READ0:
s->iolen = 0;
@@ -271,12 +296,7 @@ static void nand_command(NANDFlashState *s)
case NAND_CMD_NOSERIALREAD2:
if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
break;
- offset = s->addr & ((1 << s->addr_shift) - 1);
- s->blk_load(s, s->addr, offset);
- if (s->gnd)
- s->iolen = (1 << s->page_shift) - offset;
- else
- s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+ s->iolen = nand_load_block(s, s->addr & ((1 << s->addr_shift) - 1));
break;
case NAND_CMD_RESET:
@@ -597,12 +617,7 @@ uint32_t nand_getio(DeviceState *dev)
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
s->offset = 0;
-
- s->blk_load(s, s->addr, offset);
- if (s->gnd)
- s->iolen = (1 << s->page_shift) - offset;
- else
- s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+ s->iolen = nand_load_block(s, offset);
}
if (s->ce || s->iolen <= 0) {
@@ -763,11 +778,15 @@ static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s)
}
}
-static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
- uint64_t addr, int offset)
+static bool glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
+ uint64_t addr, unsigned offset)
{
if (PAGE(addr) >= s->pages) {
- return;
+ return false;
+ }
+
+ if (offset > NAND_PAGE_SIZE + OOB_SIZE) {
+ return false;
}
if (s->blk) {
@@ -795,6 +814,8 @@ static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
offset, NAND_PAGE_SIZE + OOB_SIZE - offset);
s->ioaddr = s->io;
}
+
+ return true;
}
static void glue(nand_init_, NAND_PAGE_SIZE)(NANDFlashState *s)
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 016aba6374..2094d213cd 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -985,8 +985,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
return;
}
- port->bh = qemu_bh_new_guarded(flush_queued_data_bh, port,
- &dev->mem_reentrancy_guard);
+ port->bh = virtio_bh_new_guarded(dev, flush_queued_data_bh, port);
port->elem = NULL;
}
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 78d5a4f164..ae831b6b3e 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1492,10 +1492,8 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
g->ctrl_vq = virtio_get_queue(vdev, 0);
g->cursor_vq = virtio_get_queue(vdev, 1);
- g->ctrl_bh = qemu_bh_new_guarded(virtio_gpu_ctrl_bh, g,
- &qdev->mem_reentrancy_guard);
- g->cursor_bh = qemu_bh_new_guarded(virtio_gpu_cursor_bh, g,
- &qdev->mem_reentrancy_guard);
+ g->ctrl_bh = virtio_bh_new_guarded(qdev, virtio_gpu_ctrl_bh, g);
+ g->cursor_bh = virtio_bh_new_guarded(qdev, virtio_gpu_cursor_bh, g);
g->reset_bh = qemu_bh_new(virtio_gpu_reset_bh, g);
qemu_cond_init(&g->reset_cond);
QTAILQ_INIT(&g->reslist);
diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
index 72300d0cbc..14e3ef667d 100644
--- a/hw/misc/applesmc.c
+++ b/hw/misc/applesmc.c
@@ -274,6 +274,7 @@ static void qdev_applesmc_isa_reset(DeviceState *dev)
/* Remove existing entries */
QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
QLIST_REMOVE(d, node);
+ g_free(d);
}
s->status = 0x00;
s->status_1e = 0x00;
@@ -342,7 +343,6 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp)
}
QLIST_INIT(&s->data_def);
- qdev_applesmc_isa_reset(dev);
}
static Property applesmc_isa_properties[] = {
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index 47ff25b441..91d81b410b 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -150,6 +150,12 @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
#define GPT_TIMER_EN 0x20000000
+/*
+ * The MAC Interface Layer (MIL), within the MAC, contains a 2K Byte transmit
+ * and a 128 Byte receive FIFO which is separate from the TX and RX FIFOs.
+ */
+#define MIL_TXFIFO_SIZE 2048
+
enum tx_state {
TX_IDLE,
TX_B,
@@ -166,7 +172,7 @@ typedef struct {
int32_t pad;
int32_t fifo_used;
int32_t len;
- uint8_t data[2048];
+ uint8_t data[MIL_TXFIFO_SIZE];
} LAN9118Packet;
static const VMStateDescription vmstate_lan9118_packet = {
@@ -182,7 +188,7 @@ static const VMStateDescription vmstate_lan9118_packet = {
VMSTATE_INT32(pad, LAN9118Packet),
VMSTATE_INT32(fifo_used, LAN9118Packet),
VMSTATE_INT32(len, LAN9118Packet),
- VMSTATE_UINT8_ARRAY(data, LAN9118Packet, 2048),
+ VMSTATE_UINT8_ARRAY(data, LAN9118Packet, MIL_TXFIFO_SIZE),
VMSTATE_END_OF_LIST()
}
};
@@ -544,7 +550,7 @@ static ssize_t lan9118_receive(NetClientState *nc, const uint8_t *buf,
return -1;
}
- if (size >= 2048 || size < 14) {
+ if (size >= MIL_TXFIFO_SIZE || size < 14) {
return -1;
}
@@ -793,8 +799,22 @@ static void tx_fifo_push(lan9118_state *s, uint32_t val)
/* Documentation is somewhat unclear on the ordering of bytes
in FIFO words. Empirical results show it to be little-endian.
*/
- /* TODO: FIFO overflow checking. */
while (n--) {
+ if (s->txp->len == MIL_TXFIFO_SIZE) {
+ /*
+ * No more space in the FIFO. The datasheet is not
+ * precise about this case. We choose what is easiest
+ * to model: the packet is truncated, and TXE is raised.
+ *
+ * Note, it could be a fragmented packet, but we currently
+ * do not handle that (see earlier TX_B case).
+ */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "MIL TX FIFO overrun, discarding %u byte%s\n",
+ n, n > 1 ? "s" : "");
+ s->int_sts |= TXE_INT;
+ break;
+ }
s->txp->data[s->txp->len] = val & 0xff;
s->txp->len++;
val >>= 8;
diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index 2134a18c4c..b7b1de816d 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -141,6 +141,10 @@ bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt)
uint32_t csum = 0;
struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG;
+ if (iov_size(pl_start_frag, pkt->payload_frags) < 8 + sizeof(csum)) {
+ return false;
+ }
+
if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) {
return false;
}
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index c5e0bc018b..27673e1c70 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);
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index fe1313f2ad..bbe8aa4b99 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -1080,8 +1080,8 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
vcrypto->vqs[i].dataq =
virtio_add_queue(vdev, 1024, virtio_crypto_handle_dataq_bh);
vcrypto->vqs[i].dataq_bh =
- qemu_bh_new_guarded(virtio_crypto_dataq_bh, &vcrypto->vqs[i],
- &dev->mem_reentrancy_guard);
+ virtio_bh_new_guarded(dev, virtio_crypto_dataq_bh,
+ &vcrypto->vqs[i]);
vcrypto->vqs[i].vcrypto = vcrypto;
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index c5bedca848..871674f9be 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -4145,3 +4145,13 @@ static void virtio_register_types(void)
}
type_init(virtio_register_types)
+
+QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
+ QEMUBHFunc *cb, void *opaque,
+ const char *name)
+{
+ DeviceState *transport = qdev_get_parent_bus(dev)->parent;
+
+ return qemu_bh_new_full(cb, opaque, name,
+ &transport->mem_reentrancy_guard);
+}
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index c8f72850bc..7d5ffdc145 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -22,6 +22,7 @@
#include "standard-headers/linux/virtio_config.h"
#include "standard-headers/linux/virtio_ring.h"
#include "qom/object.h"
+#include "block/aio.h"
/*
* A guest should never accept this. It implies negotiation is broken
@@ -508,4 +509,10 @@ static inline bool virtio_device_disabled(VirtIODevice *vdev)
bool virtio_legacy_allowed(VirtIODevice *vdev);
bool virtio_legacy_check_disabled(VirtIODevice *vdev);
+QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
+ QEMUBHFunc *cb, void *opaque,
+ const char *name);
+#define virtio_bh_new_guarded(dev, cb, opaque) \
+ virtio_bh_new_guarded_full((dev), (cb), (opaque), (stringify(cb)))
+
#endif
diff --git a/qemu-options.hx b/qemu-options.hx
index 7fd1713fa8..8ce85d4559 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -151,14 +151,14 @@ SRST
platform and configuration dependent.
``interleave-granularity=granularity`` sets the granularity of
- interleave. Default 256KiB. Only 256KiB, 512KiB, 1024KiB, 2048KiB
- 4096KiB, 8192KiB and 16384KiB granularities supported.
+ interleave. Default 256 (bytes). Only 256, 512, 1k, 2k,
+ 4k, 8k and 16k granularities supported.
Example:
::
- -machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512k
+ -machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512
ERST
DEF("M", HAS_ARG, QEMU_OPTION_M,