]> git.baikalelectronics.ru Git - kernel.git/commitdiff
nbd: fix use after free on module unload
authorJosef Bacik <josef@toxicpanda.com>
Fri, 28 Apr 2017 13:49:19 +0000 (09:49 -0400)
committerJens Axboe <axboe@fb.com>
Fri, 28 Apr 2017 14:04:01 +0000 (08:04 -0600)
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>
drivers/block/nbd.c

index 5583dc4ff9415a68f36e58066b26d3ca451a3265..ac376b9b852d69677f292eba1afb15df419fe769 100644 (file)
@@ -2090,7 +2090,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;
 }
@@ -2106,11 +2105,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);