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 | |
| 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')
| -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 | ||
