summaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-crypt.c
diff options
context:
space:
mode:
authorRabin Vincent <rabinv@axis.com>2016-09-21 10:22:29 -0400
committerMike Snitzer <snitzer@redhat.com>2016-09-22 11:15:06 -0400
commitf659b10087daaf4ce0087c3f6aec16746be9628f (patch)
treee3b361feeb5bf4b856b150fe3648fe60c5f13055 /drivers/md/dm-crypt.c
parentf177940a80917044f0ea6fd18ea1bfbdff012050 (diff)
dm crypt: fix crash on exit
As the documentation for kthread_stop() says, "if threadfn() may call do_exit() itself, the caller must ensure task_struct can't go away". dm-crypt does not ensure this and therefore crashes when crypt_dtr() calls kthread_stop(). The crash is trivially reproducible by adding a delay before the call to kthread_stop() and just opening and closing a dm-crypt device. general protection fault: 0000 [#1] PREEMPT SMP CPU: 0 PID: 533 Comm: cryptsetup Not tainted 4.8.0-rc7+ #7 task: ffff88003bd0df40 task.stack: ffff8800375b4000 RIP: 0010: kthread_stop+0x52/0x300 Call Trace: crypt_dtr+0x77/0x120 dm_table_destroy+0x6f/0x120 __dm_destroy+0x130/0x250 dm_destroy+0x13/0x20 dev_remove+0xe6/0x120 ? dev_suspend+0x250/0x250 ctl_ioctl+0x1fc/0x530 ? __lock_acquire+0x24f/0x1b10 dm_ctl_ioctl+0x13/0x20 do_vfs_ioctl+0x91/0x6a0 ? ____fput+0xe/0x10 ? entry_SYSCALL_64_fastpath+0x5/0xbd ? trace_hardirqs_on_caller+0x151/0x1e0 SyS_ioctl+0x41/0x70 entry_SYSCALL_64_fastpath+0x1f/0xbd This problem was introduced by bcbd94ff481e ("dm crypt: fix a possible hang due to race condition on exit"). Looking at the description of that patch (excerpted below), it seems like the problem it addresses can be solved by just using set_current_state instead of __set_current_state, since we obviously need the memory barrier. | dm crypt: fix a possible hang due to race condition on exit | | A kernel thread executes __set_current_state(TASK_INTERRUPTIBLE), | __add_wait_queue, spin_unlock_irq and then tests kthread_should_stop(). | It is possible that the processor reorders memory accesses so that | kthread_should_stop() is executed before __set_current_state(). If | such reordering happens, there is a possible race on thread | termination: [...] So this patch just reverts the aforementioned patch and changes the __set_current_state(TASK_INTERRUPTIBLE) to set_current_state(...). This fixes the crash and should also fix the potential hang. Fixes: bcbd94ff481e ("dm crypt: fix a possible hang due to race condition on exit") Cc: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org # v4.0+ Signed-off-by: Rabin Vincent <rabinv@axis.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md/dm-crypt.c')
-rw-r--r--drivers/md/dm-crypt.c24
1 files changed, 10 insertions, 14 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 9ba0f0724d28..bcba462a7d14 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -113,8 +113,7 @@ struct iv_tcw_private {
113 * and encrypts / decrypts at the same time. 113 * and encrypts / decrypts at the same time.
114 */ 114 */
115enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID, 115enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
116 DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD, 116 DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
117 DM_CRYPT_EXIT_THREAD};
118 117
119/* 118/*
120 * The fields in here must be read only after initialization. 119 * The fields in here must be read only after initialization.
@@ -1207,18 +1206,20 @@ continue_locked:
1207 if (!RB_EMPTY_ROOT(&cc->write_tree)) 1206 if (!RB_EMPTY_ROOT(&cc->write_tree))
1208 goto pop_from_list; 1207 goto pop_from_list;
1209 1208
1210 if (unlikely(test_bit(DM_CRYPT_EXIT_THREAD, &cc->flags))) { 1209 set_current_state(TASK_INTERRUPTIBLE);
1211 spin_unlock_irq(&cc->write_thread_wait.lock);
1212 break;
1213 }
1214
1215 __set_current_state(TASK_INTERRUPTIBLE);
1216 __add_wait_queue(&cc->write_thread_wait, &wait); 1210 __add_wait_queue(&cc->write_thread_wait, &wait);
1217 1211
1218 spin_unlock_irq(&cc->write_thread_wait.lock); 1212 spin_unlock_irq(&cc->write_thread_wait.lock);
1219 1213
1214 if (unlikely(kthread_should_stop())) {
1215 set_task_state(current, TASK_RUNNING);
1216 remove_wait_queue(&cc->write_thread_wait, &wait);
1217 break;
1218 }
1219
1220 schedule(); 1220 schedule();
1221 1221
1222 set_task_state(current, TASK_RUNNING);
1222 spin_lock_irq(&cc->write_thread_wait.lock); 1223 spin_lock_irq(&cc->write_thread_wait.lock);
1223 __remove_wait_queue(&cc->write_thread_wait, &wait); 1224 __remove_wait_queue(&cc->write_thread_wait, &wait);
1224 goto continue_locked; 1225 goto continue_locked;
@@ -1533,13 +1534,8 @@ static void crypt_dtr(struct dm_target *ti)
1533 if (!cc) 1534 if (!cc)
1534 return; 1535 return;
1535 1536
1536 if (cc->write_thread) { 1537 if (cc->write_thread)
1537 spin_lock_irq(&cc->write_thread_wait.lock);
1538 set_bit(DM_CRYPT_EXIT_THREAD, &cc->flags);
1539 wake_up_locked(&cc->write_thread_wait);
1540 spin_unlock_irq(&cc->write_thread_wait.lock);
1541 kthread_stop(cc->write_thread); 1538 kthread_stop(cc->write_thread);
1542 }
1543 1539
1544 if (cc->io_queue) 1540 if (cc->io_queue)
1545 destroy_workqueue(cc->io_queue); 1541 destroy_workqueue(cc->io_queue);