Commit 0a9ee9ce authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'locking_urgent_for_v6.17_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking fixes from Borislav Petkov:

 - Make sure sanity checks down in the mutex lock path happen on the
   correct type of task so that they don't trigger falsely

 - Use the write unsafe user access pairs when writing a futex value to
   prevent an error on PowerPC which does user read and write accesses
   differently

* tag 'locking_urgent_for_v6.17_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  locking: Fix __clear_task_blocked_on() warning from __ww_mutex_wound() path
  futex: Use user_write_access_begin/_end() in futex_put_value()
parents 99bade34 21924af6
Loading
Loading
Loading
Loading
+17 −12
Original line number Diff line number Diff line
@@ -2152,6 +2152,8 @@ static inline struct mutex *__get_task_blocked_on(struct task_struct *p)

static inline void __set_task_blocked_on(struct task_struct *p, struct mutex *m)
{
	struct mutex *blocked_on = READ_ONCE(p->blocked_on);

	WARN_ON_ONCE(!m);
	/* The task should only be setting itself as blocked */
	WARN_ON_ONCE(p != current);
@@ -2162,8 +2164,8 @@ static inline void __set_task_blocked_on(struct task_struct *p, struct mutex *m)
	 * with a different mutex. Note, setting it to the same
	 * lock repeatedly is ok.
	 */
	WARN_ON_ONCE(p->blocked_on && p->blocked_on != m);
	p->blocked_on = m;
	WARN_ON_ONCE(blocked_on && blocked_on != m);
	WRITE_ONCE(p->blocked_on, m);
}

static inline void set_task_blocked_on(struct task_struct *p, struct mutex *m)
@@ -2174,7 +2176,9 @@ static inline void set_task_blocked_on(struct task_struct *p, struct mutex *m)

static inline void __clear_task_blocked_on(struct task_struct *p, struct mutex *m)
{
	WARN_ON_ONCE(!m);
	if (m) {
		struct mutex *blocked_on = READ_ONCE(p->blocked_on);

		/* Currently we serialize blocked_on under the mutex::wait_lock */
		lockdep_assert_held_once(&m->wait_lock);
		/*
@@ -2182,8 +2186,9 @@ static inline void __clear_task_blocked_on(struct task_struct *p, struct mutex *
		 * blocked_on relationships, but make sure we are not
		 * clearing the relationship with a different lock.
		 */
	WARN_ON_ONCE(m && p->blocked_on && p->blocked_on != m);
	p->blocked_on = NULL;
		WARN_ON_ONCE(blocked_on && blocked_on != m);
	}
	WRITE_ONCE(p->blocked_on, NULL);
}

static inline void clear_task_blocked_on(struct task_struct *p, struct mutex *m)
+3 −3
Original line number Diff line number Diff line
@@ -319,13 +319,13 @@ static __always_inline int futex_put_value(u32 val, u32 __user *to)
{
	if (can_do_masked_user_access())
		to = masked_user_access_begin(to);
	else if (!user_read_access_begin(to, sizeof(*to)))
	else if (!user_write_access_begin(to, sizeof(*to)))
		return -EFAULT;
	unsafe_put_user(val, to, Efault);
	user_read_access_end();
	user_write_access_end();
	return 0;
Efault:
	user_read_access_end();
	user_write_access_end();
	return -EFAULT;
}

+5 −1
Original line number Diff line number Diff line
@@ -342,8 +342,12 @@ static bool __ww_mutex_wound(struct MUTEX *lock,
			 * When waking up the task to wound, be sure to clear the
			 * blocked_on pointer. Otherwise we can see circular
			 * blocked_on relationships that can't resolve.
			 *
			 * NOTE: We pass NULL here instead of lock, because we
			 * are waking the mutex owner, who may be currently
			 * blocked on a different mutex.
			 */
			__clear_task_blocked_on(owner, lock);
			__clear_task_blocked_on(owner, NULL);
			wake_q_add(wake_q, owner);
		}
		return true;