Skip to content

Commit 7c07725

Browse files
KAGA-KOKOGerrit - the friendly Code Review server
authored and
Gerrit - the friendly Code Review server
committedAug 17, 2021
futex: Handle faults correctly for PI futexes
commit 34b1a1ce1458f50ef27c54e28eb9b1947012907a upstream fixup_pi_state_owner() tries to ensure that the state of the rtmutex, pi_state and the user space value related to the PI futex are consistent before returning to user space. In case that the user space value update faults and the fault cannot be resolved by faulting the page in via fault_in_user_writeable() the function returns with -EFAULT and leaves the rtmutex and pi_state owner state inconsistent. A subsequent futex_unlock_pi() operates on the inconsistent pi_state and releases the rtmutex despite not owning it which can corrupt the RB tree of the rtmutex and cause a subsequent kernel stack use after free. It was suggested to loop forever in fixup_pi_state_owner() if the fault cannot be resolved, but that results in runaway tasks which is especially undesired when the problem happens due to a programming error and not due to malice. As the user space value cannot be fixed up, the proper solution is to make the rtmutex and the pi_state consistent so both have the same owner. This leaves the user space value out of sync. Any subsequent operation on the futex will fail because the 10th rule of PI futexes (pi_state owner and user space value are consistent) has been violated. As a consequence this removes the inept attempts of 'fixing' the situation in case that the current task owns the rtmutex when returning with an unresolvable fault by unlocking the rtmutex which left pi_state::owner and rtmutex::owner out of sync in a different and only slightly less dangerous way. Change-Id: Ic19f2e16d6de16db63594706eae5f547e38ea852 Fixes: 1b7558e ("futexes: fix fault handling in futex_lock_pi") Reported-by: [email protected] Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Cc: [email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]> Git-commit: 6e7bfa046de83596c2a50f72e8ced1ee327db654 Git-repo: https://android.googlesource.com/kernel/msm Signed-off-by: PavanKumar S.R. <[email protected]>

File tree

1 file changed

+20
-36
lines changed

1 file changed

+20
-36
lines changed
 

‎kernel/futex.c

+20-36
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,8 @@ void exit_pi_state_list(struct task_struct *curr)
10321032
* FUTEX_OWNER_DIED bit. See [4]
10331033
*
10341034
* [10] There is no transient state which leaves owner and user space
1035-
* TID out of sync.
1035+
* TID out of sync. Except one error case where the kernel is denied
1036+
* write access to the user address, see fixup_pi_state_owner().
10361037
*
10371038
*
10381039
* Serialization and lifetime rules:
@@ -2524,6 +2525,24 @@ static int __fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
25242525
if (!err)
25252526
goto retry;
25262527

2528+
/*
2529+
* fault_in_user_writeable() failed so user state is immutable. At
2530+
* best we can make the kernel state consistent but user state will
2531+
* be most likely hosed and any subsequent unlock operation will be
2532+
* rejected due to PI futex rule [10].
2533+
*
2534+
* Ensure that the rtmutex owner is also the pi_state owner despite
2535+
* the user space value claiming something different. There is no
2536+
* point in unlocking the rtmutex if current is the owner as it
2537+
* would need to wait until the next waiter has taken the rtmutex
2538+
* to guarantee consistent state. Keep it simple. Userspace asked
2539+
* for this wreckaged state.
2540+
*
2541+
* The rtmutex has an owner - either current or some other
2542+
* task. See the EAGAIN loop above.
2543+
*/
2544+
pi_state_update_owner(pi_state, rt_mutex_owner(&pi_state->pi_mutex));
2545+
25272546
return err;
25282547
}
25292548

@@ -2813,7 +2832,6 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
28132832
ktime_t *time, int trylock)
28142833
{
28152834
struct hrtimer_sleeper timeout, *to = NULL;
2816-
struct futex_pi_state *pi_state = NULL;
28172835
struct rt_mutex_waiter rt_waiter;
28182836
struct futex_hash_bucket *hb;
28192837
struct futex_q q = futex_q_init;
@@ -2947,23 +2965,9 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
29472965
if (res)
29482966
ret = (res < 0) ? res : 0;
29492967

2950-
/*
2951-
* If fixup_owner() faulted and was unable to handle the fault, unlock
2952-
* it and return the fault to userspace.
2953-
*/
2954-
if (ret && (rt_mutex_owner(&q.pi_state->pi_mutex) == current)) {
2955-
pi_state = q.pi_state;
2956-
get_pi_state(pi_state);
2957-
}
2958-
29592968
/* Unqueue and drop the lock */
29602969
unqueue_me_pi(&q);
29612970

2962-
if (pi_state) {
2963-
rt_mutex_futex_unlock(&pi_state->pi_mutex);
2964-
put_pi_state(pi_state);
2965-
}
2966-
29672971
goto out_put_key;
29682972

29692973
out_unlock_put_key:
@@ -3229,7 +3233,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
32293233
u32 __user *uaddr2)
32303234
{
32313235
struct hrtimer_sleeper timeout, *to = NULL;
3232-
struct futex_pi_state *pi_state = NULL;
32333236
struct rt_mutex_waiter rt_waiter;
32343237
struct futex_hash_bucket *hb;
32353238
union futex_key key2 = FUTEX_KEY_INIT;
@@ -3314,10 +3317,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
33143317
if (q.pi_state && (q.pi_state->owner != current)) {
33153318
spin_lock(q.lock_ptr);
33163319
ret = fixup_pi_state_owner(uaddr2, &q, current);
3317-
if (ret < 0 && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
3318-
pi_state = q.pi_state;
3319-
get_pi_state(pi_state);
3320-
}
33213320
/*
33223321
* Drop the reference to the pi state which
33233322
* the requeue_pi() code acquired for us.
@@ -3359,25 +3358,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
33593358
if (res)
33603359
ret = (res < 0) ? res : 0;
33613360

3362-
/*
3363-
* If fixup_pi_state_owner() faulted and was unable to handle
3364-
* the fault, unlock the rt_mutex and return the fault to
3365-
* userspace.
3366-
*/
3367-
if (ret && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
3368-
pi_state = q.pi_state;
3369-
get_pi_state(pi_state);
3370-
}
3371-
33723361
/* Unqueue and drop the lock. */
33733362
unqueue_me_pi(&q);
33743363
}
33753364

3376-
if (pi_state) {
3377-
rt_mutex_futex_unlock(&pi_state->pi_mutex);
3378-
put_pi_state(pi_state);
3379-
}
3380-
33813365
if (ret == -EINTR) {
33823366
/*
33833367
* We've already been requeued, but cannot restart by calling

0 commit comments

Comments
 (0)
Please sign in to comment.