Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5f13082 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking fixes from Thomas Gleixner:
 "Three fixes related to locking:

   - fix a SIGKILL issue for RWSEM_GENERIC_SPINLOCK which has been fixed
     for the XCHGADD variant already

   - plug a potential use after free in the futex code

   - prevent leaking a held spinlock in an futex error handling code
     path"

* 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  locking/rwsem: Fix down_write_killable() for CONFIG_RWSEM_GENERIC_SPINLOCK=y
  futex: Add missing error handling to FUTEX_REQUEUE_PI
  futex: Fix potential use-after-free in FUTEX_REQUEUE_PI
parents 18f48c9f 17fcbd59
Loading
Loading
Loading
Loading
+13 −9
Original line number Diff line number Diff line
@@ -2815,7 +2815,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
{
	struct hrtimer_sleeper timeout, *to = NULL;
	struct rt_mutex_waiter rt_waiter;
	struct rt_mutex *pi_mutex = NULL;
	struct futex_hash_bucket *hb;
	union futex_key key2 = FUTEX_KEY_INIT;
	struct futex_q q = futex_q_init;
@@ -2899,6 +2898,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
		if (q.pi_state && (q.pi_state->owner != current)) {
			spin_lock(q.lock_ptr);
			ret = fixup_pi_state_owner(uaddr2, &q, current);
			if (ret && rt_mutex_owner(&q.pi_state->pi_mutex) == current)
				rt_mutex_unlock(&q.pi_state->pi_mutex);
			/*
			 * Drop the reference to the pi state which
			 * the requeue_pi() code acquired for us.
@@ -2907,6 +2908,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
			spin_unlock(q.lock_ptr);
		}
	} else {
		struct rt_mutex *pi_mutex;

		/*
		 * We have been woken up by futex_unlock_pi(), a timeout, or a
		 * signal.  futex_unlock_pi() will not destroy the lock_ptr nor
@@ -2930,18 +2933,19 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
		if (res)
			ret = (res < 0) ? res : 0;

		/*
		 * If fixup_pi_state_owner() faulted and was unable to handle
		 * the fault, unlock the rt_mutex and return the fault to
		 * userspace.
		 */
		if (ret && rt_mutex_owner(pi_mutex) == current)
			rt_mutex_unlock(pi_mutex);

		/* Unqueue and drop the lock. */
		unqueue_me_pi(&q);
	}

	/*
	 * If fixup_pi_state_owner() faulted and was unable to handle the
	 * fault, unlock the rt_mutex and return the fault to userspace.
	 */
	if (ret == -EFAULT) {
		if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
			rt_mutex_unlock(pi_mutex);
	} else if (ret == -EINTR) {
	if (ret == -EINTR) {
		/*
		 * We've already been requeued, but cannot restart by calling
		 * futex_lock_pi() directly. We could restart this syscall, but
+11 −5
Original line number Diff line number Diff line
@@ -213,10 +213,9 @@ int __sched __down_write_common(struct rw_semaphore *sem, int state)
		 */
		if (sem->count == 0)
			break;
		if (signal_pending_state(state, current)) {
			ret = -EINTR;
			goto out;
		}
		if (signal_pending_state(state, current))
			goto out_nolock;

		set_current_state(state);
		raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
		schedule();
@@ -224,12 +223,19 @@ int __sched __down_write_common(struct rw_semaphore *sem, int state)
	}
	/* got the lock */
	sem->count = -1;
out:
	list_del(&waiter.list);

	raw_spin_unlock_irqrestore(&sem->wait_lock, flags);

	return ret;

out_nolock:
	list_del(&waiter.list);
	if (!list_empty(&sem->wait_list))
		__rwsem_do_wake(sem, 1);
	raw_spin_unlock_irqrestore(&sem->wait_lock, flags);

	return -EINTR;
}

void __sched __down_write(struct rw_semaphore *sem)