title: locking/qrwlock: Fix ordering in queued_write_lock_slowpath()
description: In the Linux kernel, the following vulnerability has been resolved:
locking/qrwlock: Fix ordering in queued_write_lock_slowpath()
While this code is executed with the wait_lock held, a reader can
acquire the lock without holding wait_lock.  The writer side loops
checking the value with the atomic_cond_read_acquire(), but only truly
acquires the lock when the compare-and-exchange is completed
successfully which isn’t ordered. This exposes the window between the
acquire and the cmpxchg to an A-B-A problem which allows reads
following the lock acquisition to observe values speculatively before
the write lock is truly acquired.
We've seen a problem in epoll where the reader does a xchg while
holding the read lock, but the writer can see a value change out from
under it.
Writer                                | Reader
--------------------------------------------------------------------------------
ep_scan_ready_list()                  |
|- write_lock_irq()                   |
|- queued_write_lock_slowpath()   |
|- atomic_cond_read_acquire()   |
| read_lock_irqsave(&ep->lock, flags);
--> (observes value before unlock) |  chain_epi_lockless()
|                                  |    epi->next = xchg(&ep->ovflist, epi);
|                                  | read_unlock_irqrestore(&ep->lock, flags);
|                                  |
|     atomic_cmpxchg_relaxed()     |
|-- READ_ONCE(ep->ovflist);        |
A core can order the read of the ovflist ahead of the
atomic_cmpxchg_relaxed(). Switching the cmpxchg to use acquire
semantics addresses this issue at which point the atomic_cond_read can
be switched to use relaxed semantics.
[peterz: use try_cmpxchg()]
affected:
{
product: Linux
vendor: Linux
defaultStatus: unaffected
repo: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
versions:
version: b519b56e378e, lessThan: 5902f9453a31, status: affected, versionType: git
version: b519b56e378e, lessThan: 82808cc02681, status: affected, versionType: git
version: b519b56e378e, lessThan: 82fa9ced35d8, status: affected, versionType: git
version: b519b56e378e, lessThan: d558fcdb1713, status: affected, versionType: git
version: b519b56e378e, lessThan: 84a24bf8c52e, status: affected, versionType: git
}
{
product: Linux
vendor: Linux
defaultStatus: affected
repo: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
versions:
version: 4.15, status: affected
version: 0, lessThan: 4.15, status: unaffected, versionType: custom
version: 4.19.189, lessThanOrEqual: 4.19.*, status: unaffected, versionType: custom
version: 5.4.115, lessThanOrEqual: 5.4.*, status: unaffected, versionType: custom
version: 5.10.33, lessThanOrEqual: 5.10.*, status: unaffected, versionType: custom
version: 5.11.17, lessThanOrEqual: 5.11.*, status: unaffected, versionType: custom
version: 5.12, lessThanOrEqual: *, status: unaffected, versionType: original_commit_for_fix
}
