Patch "virtio-net: fix the race between refill work and close" has been added to the 5.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    virtio-net: fix the race between refill work and close

to the 5.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     virtio-net-fix-the-race-between-refill-work-and-clos.patch
and it can be found in the queue-5.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 107584d36a876b373e733c893b58dd447c8b9e48
Author: Jason Wang <jasowang@xxxxxxxxxx>
Date:   Mon Jul 25 15:21:59 2022 +0800

    virtio-net: fix the race between refill work and close
    
    [ Upstream commit 5a159128faff151b7fe5f4eb0f310b1e0a2d56bf ]
    
    We try using cancel_delayed_work_sync() to prevent the work from
    enabling NAPI. This is insufficient since we don't disable the source
    of the refill work scheduling. This means an NAPI poll callback after
    cancel_delayed_work_sync() can schedule the refill work then can
    re-enable the NAPI that leads to use-after-free [1].
    
    Since the work can enable NAPI, we can't simply disable NAPI before
    calling cancel_delayed_work_sync(). So fix this by introducing a
    dedicated boolean to control whether or not the work could be
    scheduled from NAPI.
    
    [1]
    ==================================================================
    BUG: KASAN: use-after-free in refill_work+0x43/0xd4
    Read of size 2 at addr ffff88810562c92e by task kworker/2:1/42
    
    CPU: 2 PID: 42 Comm: kworker/2:1 Not tainted 5.19.0-rc1+ #480
    Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014
    Workqueue: events refill_work
    Call Trace:
     <TASK>
     dump_stack_lvl+0x34/0x44
     print_report.cold+0xbb/0x6ac
     ? _printk+0xad/0xde
     ? refill_work+0x43/0xd4
     kasan_report+0xa8/0x130
     ? refill_work+0x43/0xd4
     refill_work+0x43/0xd4
     process_one_work+0x43d/0x780
     worker_thread+0x2a0/0x6f0
     ? process_one_work+0x780/0x780
     kthread+0x167/0x1a0
     ? kthread_exit+0x50/0x50
     ret_from_fork+0x22/0x30
     </TASK>
    ...
    
    Fixes: b2baed69e605c ("virtio_net: set/cancel work on ndo_open/ndo_stop")
    Signed-off-by: Jason Wang <jasowang@xxxxxxxxxx>
    Acked-by: Michael S. Tsirkin <mst@xxxxxxxxxx>
    Reviewed-by: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx>
    Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index e14842fbe3d6..579df7c5411d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -213,9 +213,15 @@ struct virtnet_info {
 	/* Packet virtio header size */
 	u8 hdr_len;
 
-	/* Work struct for refilling if we run low on memory. */
+	/* Work struct for delayed refilling if we run low on memory. */
 	struct delayed_work refill;
 
+	/* Is delayed refill enabled? */
+	bool refill_enabled;
+
+	/* The lock to synchronize the access to refill_enabled */
+	spinlock_t refill_lock;
+
 	/* Work struct for config space updates */
 	struct work_struct config_work;
 
@@ -319,6 +325,20 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
 	return p;
 }
 
+static void enable_delayed_refill(struct virtnet_info *vi)
+{
+	spin_lock_bh(&vi->refill_lock);
+	vi->refill_enabled = true;
+	spin_unlock_bh(&vi->refill_lock);
+}
+
+static void disable_delayed_refill(struct virtnet_info *vi)
+{
+	spin_lock_bh(&vi->refill_lock);
+	vi->refill_enabled = false;
+	spin_unlock_bh(&vi->refill_lock);
+}
+
 static void virtqueue_napi_schedule(struct napi_struct *napi,
 				    struct virtqueue *vq)
 {
@@ -1388,8 +1408,12 @@ static int virtnet_receive(struct receive_queue *rq, int budget,
 	}
 
 	if (rq->vq->num_free > min((unsigned int)budget, virtqueue_get_vring_size(rq->vq)) / 2) {
-		if (!try_fill_recv(vi, rq, GFP_ATOMIC))
-			schedule_delayed_work(&vi->refill, 0);
+		if (!try_fill_recv(vi, rq, GFP_ATOMIC)) {
+			spin_lock(&vi->refill_lock);
+			if (vi->refill_enabled)
+				schedule_delayed_work(&vi->refill, 0);
+			spin_unlock(&vi->refill_lock);
+		}
 	}
 
 	u64_stats_update_begin(&rq->stats.syncp);
@@ -1508,6 +1532,8 @@ static int virtnet_open(struct net_device *dev)
 	struct virtnet_info *vi = netdev_priv(dev);
 	int i, err;
 
+	enable_delayed_refill(vi);
+
 	for (i = 0; i < vi->max_queue_pairs; i++) {
 		if (i < vi->curr_queue_pairs)
 			/* Make sure we have some buffers: if oom use wq. */
@@ -1878,6 +1904,8 @@ static int virtnet_close(struct net_device *dev)
 	struct virtnet_info *vi = netdev_priv(dev);
 	int i;
 
+	/* Make sure NAPI doesn't schedule refill work */
+	disable_delayed_refill(vi);
 	/* Make sure refill_work doesn't re-enable napi! */
 	cancel_delayed_work_sync(&vi->refill);
 
@@ -2417,6 +2445,8 @@ static int virtnet_restore_up(struct virtio_device *vdev)
 
 	virtio_device_ready(vdev);
 
+	enable_delayed_refill(vi);
+
 	if (netif_running(vi->dev)) {
 		err = virtnet_open(vi->dev);
 		if (err)
@@ -3140,6 +3170,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 	vdev->priv = vi;
 
 	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
+	spin_lock_init(&vi->refill_lock);
 
 	/* If we can receive ANY GSO packets, we must allocate large ones. */
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux