Message ID | 20230601031859.7115-3-akihiko.odaki@daynix.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | net: Update MemReentrancyGuard for NIC | expand |
On 230601 1218, Akihiko Odaki wrote: > 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> > --- > 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 >
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; }
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(+)