[RHEL7,COMMIT] ms/nbd: fix use after free on module unload

Submitted by Konstantin Khorenko on Nov. 5, 2019, 8:06 a.m.

Details

Message ID 201911050806.xA586EU3015874@finist-ce7.sw.ru
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko Nov. 5, 2019, 8:06 a.m.
The commit is pushed to "branch-rh7-3.10.0-1062.4.1.vz7.115.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1062.4.1.vz7.115.7
------>
commit 7fc5d99b5add7f1e67cd7a829a3e0a659e9cd113
Author: Josef Bacik <josef@toxicpanda.com>
Date:   Tue Nov 5 11:06:14 2019 +0300

    ms/nbd: fix use after free on module unload
    
    list_for_each_entry() isn't super safe if we're freeing the objects
    while we traverse the list.  Also don't bother taking the extra
    reference, the module refcounting stuff will save us from having anybody
    messing with the device while we're trying to unload.
    
    Reported-by: Ming Lei <ming.lei@redhat.com>
    Signed-off-by: Josef Bacik <jbacik@fb.com>
    Signed-off-by: Jens Axboe <axboe@fb.com>
    
    https://jira.sw.ru/browse/PSBM-99102
    (cherry picked from commit 60ae36ad0340b1ba88530d6a5e141455dd3afd81)
    Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 drivers/block/nbd.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 27fade554583..6713deae68cb 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -1426,7 +1426,6 @@  static int nbd_exit_cb(int id, void *ptr, void *data)
 	struct list_head *list = (struct list_head *)data;
 	struct nbd_device *nbd = ptr;
 
-	refcount_inc(&nbd->refs);
 	list_add_tail(&nbd->list, list);
 	return 0;
 }
@@ -1442,11 +1441,12 @@  static void __exit nbd_cleanup(void)
 	idr_for_each(&nbd_index_idr, &nbd_exit_cb, &del_list);
 	mutex_unlock(&nbd_index_mutex);
 
-	list_for_each_entry(nbd, &del_list, list) {
-		if (refcount_read(&nbd->refs) != 2)
+	while (!list_empty(&del_list)) {
+		nbd = list_first_entry(&del_list, struct nbd_device, list);
+		list_del_init(&nbd->list);
+		if (refcount_read(&nbd->refs) != 1)
 			printk(KERN_ERR "nbd: possibly leaking a device\n");
 		nbd_put(nbd);
-		nbd_put(nbd);
 	}
 
 	idr_destroy(&nbd_index_idr);