diff options
author | Brian Silverman <bsilver16384@gmail.com> | 2014-10-25 20:20:37 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2014-10-26 11:16:18 -0400 |
commit | 30a6b8031fe14031ab27c1fa3483cb9780e7f63c (patch) | |
tree | da56baddfc24fef71ca5b6f123c947e784527d87 /kernel/futex.c | |
parent | 993b2ff221999066fcff231590593d0b98f45d32 (diff) |
futex: Fix a race condition between REQUEUE_PI and task death
free_pi_state and exit_pi_state_list both clean up futex_pi_state's.
exit_pi_state_list takes the hb lock first, and most callers of
free_pi_state do too. requeue_pi doesn't, which means free_pi_state
can free the pi_state out from under exit_pi_state_list. For example:
task A | task B
exit_pi_state_list |
pi_state = |
curr->pi_state_list->next |
| futex_requeue(requeue_pi=1)
| // pi_state is the same as
| // the one in task A
| free_pi_state(pi_state)
| list_del_init(&pi_state->list)
| kfree(pi_state)
list_del_init(&pi_state->list) |
Move the free_pi_state calls in requeue_pi to before it drops the hb
locks which it's already holding.
[ tglx: Removed a pointless free_pi_state() call and the hb->lock held
debugging. The latter comes via a seperate patch ]
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Cc: austin.linux@gmail.com
Cc: darren@dvhart.com
Cc: peterz@infradead.org
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/1414282837-23092-1-git-send-email-bsilver16384@gmail.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index bbf071f325b8..63678b573d61 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -647,8 +647,14 @@ static struct futex_pi_state * alloc_pi_state(void) | |||
647 | return pi_state; | 647 | return pi_state; |
648 | } | 648 | } |
649 | 649 | ||
650 | /* | ||
651 | * Must be called with the hb lock held. | ||
652 | */ | ||
650 | static void free_pi_state(struct futex_pi_state *pi_state) | 653 | static void free_pi_state(struct futex_pi_state *pi_state) |
651 | { | 654 | { |
655 | if (!pi_state) | ||
656 | return; | ||
657 | |||
652 | if (!atomic_dec_and_test(&pi_state->refcount)) | 658 | if (!atomic_dec_and_test(&pi_state->refcount)) |
653 | return; | 659 | return; |
654 | 660 | ||
@@ -1527,15 +1533,6 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, | |||
1527 | } | 1533 | } |
1528 | 1534 | ||
1529 | retry: | 1535 | retry: |
1530 | if (pi_state != NULL) { | ||
1531 | /* | ||
1532 | * We will have to lookup the pi_state again, so free this one | ||
1533 | * to keep the accounting correct. | ||
1534 | */ | ||
1535 | free_pi_state(pi_state); | ||
1536 | pi_state = NULL; | ||
1537 | } | ||
1538 | |||
1539 | ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); | 1536 | ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); |
1540 | if (unlikely(ret != 0)) | 1537 | if (unlikely(ret != 0)) |
1541 | goto out; | 1538 | goto out; |
@@ -1625,6 +1622,8 @@ retry_private: | |||
1625 | case 0: | 1622 | case 0: |
1626 | break; | 1623 | break; |
1627 | case -EFAULT: | 1624 | case -EFAULT: |
1625 | free_pi_state(pi_state); | ||
1626 | pi_state = NULL; | ||
1628 | double_unlock_hb(hb1, hb2); | 1627 | double_unlock_hb(hb1, hb2); |
1629 | hb_waiters_dec(hb2); | 1628 | hb_waiters_dec(hb2); |
1630 | put_futex_key(&key2); | 1629 | put_futex_key(&key2); |
@@ -1640,6 +1639,8 @@ retry_private: | |||
1640 | * exit to complete. | 1639 | * exit to complete. |
1641 | * - The user space value changed. | 1640 | * - The user space value changed. |
1642 | */ | 1641 | */ |
1642 | free_pi_state(pi_state); | ||
1643 | pi_state = NULL; | ||
1643 | double_unlock_hb(hb1, hb2); | 1644 | double_unlock_hb(hb1, hb2); |
1644 | hb_waiters_dec(hb2); | 1645 | hb_waiters_dec(hb2); |
1645 | put_futex_key(&key2); | 1646 | put_futex_key(&key2); |
@@ -1716,6 +1717,7 @@ retry_private: | |||
1716 | } | 1717 | } |
1717 | 1718 | ||
1718 | out_unlock: | 1719 | out_unlock: |
1720 | free_pi_state(pi_state); | ||
1719 | double_unlock_hb(hb1, hb2); | 1721 | double_unlock_hb(hb1, hb2); |
1720 | hb_waiters_dec(hb2); | 1722 | hb_waiters_dec(hb2); |
1721 | 1723 | ||
@@ -1733,8 +1735,6 @@ out_put_keys: | |||
1733 | out_put_key1: | 1735 | out_put_key1: |
1734 | put_futex_key(&key1); | 1736 | put_futex_key(&key1); |
1735 | out: | 1737 | out: |
1736 | if (pi_state != NULL) | ||
1737 | free_pi_state(pi_state); | ||
1738 | return ret ? ret : task_count; | 1738 | return ret ? ret : task_count; |
1739 | } | 1739 | } |
1740 | 1740 | ||