net: Update MemReentrancyGuard for NIC
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> Acked-by: Alexander Bulekov <alxndr@bu.edu> Signed-off-by: Jason Wang <jasowang@redhat.com> (cherry picked from commit 9050f976e447444ea6ee2ba12c9f77e4b0dc54bc) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
This commit is contained in:
parent
cc5124d979
commit
88e79a2dfd
|
@ -124,6 +124,7 @@ typedef QTAILQ_HEAD(NetClientStateList, NetClientState) NetClientStateList;
|
||||||
typedef struct NICState {
|
typedef struct NICState {
|
||||||
NetClientState *ncs;
|
NetClientState *ncs;
|
||||||
NICConf *conf;
|
NICConf *conf;
|
||||||
|
MemReentrancyGuard *reentrancy_guard;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
bool peer_deleted;
|
bool peer_deleted;
|
||||||
} NICState;
|
} NICState;
|
||||||
|
|
14
net/net.c
14
net/net.c
|
@ -332,6 +332,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
|
||||||
nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
|
nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
|
||||||
nic->ncs = (void *)nic + info->size;
|
nic->ncs = (void *)nic + info->size;
|
||||||
nic->conf = conf;
|
nic->conf = conf;
|
||||||
|
nic->reentrancy_guard = reentrancy_guard,
|
||||||
nic->opaque = opaque;
|
nic->opaque = opaque;
|
||||||
|
|
||||||
for (i = 0; i < queues; i++) {
|
for (i = 0; i < queues; i++) {
|
||||||
|
@ -805,6 +806,7 @@ static ssize_t qemu_deliver_packet_iov(NetClientState *sender,
|
||||||
int iovcnt,
|
int iovcnt,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
|
MemReentrancyGuard *owned_reentrancy_guard;
|
||||||
NetClientState *nc = opaque;
|
NetClientState *nc = opaque;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -817,12 +819,24 @@ static ssize_t qemu_deliver_packet_iov(NetClientState *sender,
|
||||||
return 0;
|
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)) {
|
if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) {
|
||||||
ret = nc->info->receive_iov(nc, iov, iovcnt);
|
ret = nc->info->receive_iov(nc, iov, iovcnt);
|
||||||
} else {
|
} else {
|
||||||
ret = nc_sendv_compat(nc, iov, iovcnt, flags);
|
ret = nc_sendv_compat(nc, iov, iovcnt, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (owned_reentrancy_guard) {
|
||||||
|
owned_reentrancy_guard->engaged_in_io = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
nc->receive_disabled = 1;
|
nc->receive_disabled = 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue