diff mbox series

[v2,2/2] net: Update MemReentrancyGuard for NIC

Message ID 20230601031859.7115-3-akihiko.odaki@daynix.com (mailing list archive)
State New, archived
Headers show
Series net: Update MemReentrancyGuard for NIC | expand

Commit Message

Akihiko Odaki June 1, 2023, 3:18 a.m. UTC
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(+)

Comments

Alexander Bulekov June 5, 2023, 8:04 a.m. UTC | #1
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 mbox series

Patch

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;
     }