dm: fix use after free crash due to incorrect cleanup sequence
authorMikulas Patocka <mpatocka@redhat.com>
Fri, 10 Jul 2015 21:21:43 +0000 (17:21 -0400)
committerMike Snitzer <snitzer@redhat.com>
Mon, 13 Jul 2015 13:14:11 +0000 (09:14 -0400)
Linux 4.2-rc1 Commit 0f20972f7bf6 ("dm: factor out a common
cleanup_mapped_device()") moved a common cleanup code to a separate
function.  Unfortunately, that commit incorrectly changed the order of
cleanup, so that it destroys the mapped_device's srcu structure
'io_barrier' before destroying its workqueue.

The function that is executed on the workqueue (dm_wq_work) uses the srcu
structure, thus it may use it after being freed.  That results in a
crash in the LVM test suite's mirror-vgreduce-removemissing.sh test.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Fixes: 0f20972f7bf6 ("dm: factor out a common cleanup_mapped_device()")
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm.c

index de703778d39fddd6377dfc33da4819db43566470..ab37ae114e943c20c161f88b8c2a739206bfafab 100644 (file)
@@ -2277,8 +2277,6 @@ static void dm_init_old_md_queue(struct mapped_device *md)
 
 static void cleanup_mapped_device(struct mapped_device *md)
 {
-       cleanup_srcu_struct(&md->io_barrier);
-
        if (md->wq)
                destroy_workqueue(md->wq);
        if (md->kworker_task)
@@ -2290,6 +2288,8 @@ static void cleanup_mapped_device(struct mapped_device *md)
        if (md->bs)
                bioset_free(md->bs);
 
+       cleanup_srcu_struct(&md->io_barrier);
+
        if (md->disk) {
                spin_lock(&_minor_lock);
                md->disk->private_data = NULL;