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>
This commit is contained in:
		
							parent
							
								
									7d0fefdf81
								
							
						
					
					
						commit
						9050f976e4
					
				@ -126,6 +126,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++) {
 | 
				
			||||||
@ -814,6 +815,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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -826,12 +828,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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user