[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 2/2] net: Update MemReentrancyGuard for NIC
From: |
Akihiko Odaki |
Subject: |
[PATCH v2 2/2] net: Update MemReentrancyGuard for NIC |
Date: |
Thu, 1 Jun 2023 12:18:59 +0900 |
Recently MemReentrancyGuard was added to DeviceState to record that the
device is engaging in I/O. The network device backend needs to update it
when delivering a packet to a device.
This implementation follows what bottom half does, but it does not add
a tracepoint for the case that the network device backend started
delivering a packet to a device which is already engaging in I/O. This
is because such reentrancy frequently happens for
qemu_flush_queued_packets() and is insignificant.
Fixes: CVE-2023-3019
Reported-by: Alexander Bulekov <alxndr@bu.edu>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
include/net/net.h | 1 +
net/net.c | 14 ++++++++++++++
2 files changed, 15 insertions(+)
diff --git a/include/net/net.h b/include/net/net.h
index a7d8deaccb..685ec58318 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -124,6 +124,7 @@ typedef QTAILQ_HEAD(NetClientStateList, NetClientState)
NetClientStateList;
typedef struct NICState {
NetClientState *ncs;
NICConf *conf;
+ MemReentrancyGuard *reentrancy_guard;
void *opaque;
bool peer_deleted;
} NICState;
diff --git a/net/net.c b/net/net.c
index 982df2479f..3523cceafc 100644
--- a/net/net.c
+++ b/net/net.c
@@ -332,6 +332,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
nic->ncs = (void *)nic + info->size;
nic->conf = conf;
+ nic->reentrancy_guard = reentrancy_guard,
nic->opaque = opaque;
for (i = 0; i < queues; i++) {
@@ -805,6 +806,7 @@ static ssize_t qemu_deliver_packet_iov(NetClientState
*sender,
int iovcnt,
void *opaque)
{
+ MemReentrancyGuard *owned_reentrancy_guard;
NetClientState *nc = opaque;
int ret;
@@ -817,12 +819,24 @@ static ssize_t qemu_deliver_packet_iov(NetClientState
*sender,
return 0;
}
+ if (nc->info->type != NET_CLIENT_DRIVER_NIC ||
+ qemu_get_nic(nc)->reentrancy_guard->engaged_in_io) {
+ owned_reentrancy_guard = NULL;
+ } else {
+ owned_reentrancy_guard = qemu_get_nic(nc)->reentrancy_guard;
+ owned_reentrancy_guard->engaged_in_io = true;
+ }
+
if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) {
ret = nc->info->receive_iov(nc, iov, iovcnt);
} else {
ret = nc_sendv_compat(nc, iov, iovcnt, flags);
}
+ if (owned_reentrancy_guard) {
+ owned_reentrancy_guard->engaged_in_io = false;
+ }
+
if (ret == 0) {
nc->receive_disabled = 1;
}
--
2.40.1