| From bippy-7c5fe7eed585 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2021-47069: ipc/mqueue, msg, sem: avoid relying on a stack reference past its expiry |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| ipc/mqueue, msg, sem: avoid relying on a stack reference past its expiry |
| |
| do_mq_timedreceive calls wq_sleep with a stack local address. The |
| sender (do_mq_timedsend) uses this address to later call pipelined_send. |
| |
| This leads to a very hard to trigger race where a do_mq_timedreceive |
| call might return and leave do_mq_timedsend to rely on an invalid |
| address, causing the following crash: |
| |
| RIP: 0010:wake_q_add_safe+0x13/0x60 |
| Call Trace: |
| __x64_sys_mq_timedsend+0x2a9/0x490 |
| do_syscall_64+0x80/0x680 |
| entry_SYSCALL_64_after_hwframe+0x44/0xa9 |
| RIP: 0033:0x7f5928e40343 |
| |
| The race occurs as: |
| |
| 1. do_mq_timedreceive calls wq_sleep with the address of `struct |
| ext_wait_queue` on function stack (aliased as `ewq_addr` here) - it |
| holds a valid `struct ext_wait_queue *` as long as the stack has not |
| been overwritten. |
| |
| 2. `ewq_addr` gets added to info->e_wait_q[RECV].list in wq_add, and |
| do_mq_timedsend receives it via wq_get_first_waiter(info, RECV) to call |
| __pipelined_op. |
| |
| 3. Sender calls __pipelined_op::smp_store_release(&this->state, |
| STATE_READY). Here is where the race window begins. (`this` is |
| `ewq_addr`.) |
| |
| 4. If the receiver wakes up now in do_mq_timedreceive::wq_sleep, it |
| will see `state == STATE_READY` and break. |
| |
| 5. do_mq_timedreceive returns, and `ewq_addr` is no longer guaranteed |
| to be a `struct ext_wait_queue *` since it was on do_mq_timedreceive's |
| stack. (Although the address may not get overwritten until another |
| function happens to touch it, which means it can persist around for an |
| indefinite time.) |
| |
| 6. do_mq_timedsend::__pipelined_op() still believes `ewq_addr` is a |
| `struct ext_wait_queue *`, and uses it to find a task_struct to pass to |
| the wake_q_add_safe call. In the lucky case where nothing has |
| overwritten `ewq_addr` yet, `ewq_addr->task` is the right task_struct. |
| In the unlucky case, __pipelined_op::wake_q_add_safe gets handed a |
| bogus address as the receiver's task_struct causing the crash. |
| |
| do_mq_timedsend::__pipelined_op() should not dereference `this` after |
| setting STATE_READY, as the receiver counterpart is now free to return. |
| Change __pipelined_op to call wake_q_add_safe on the receiver's |
| task_struct returned by get_task_struct, instead of dereferencing `this` |
| which sits on the receiver's stack. |
| |
| As Manfred pointed out, the race potentially also exists in |
| ipc/msg.c::expunge_all and ipc/sem.c::wake_up_sem_queue_prepare. Fix |
| those in the same way. |
| |
| The Linux kernel CVE team has assigned CVE-2021-47069 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 5.6 with commit c5b2cbdbdac563f46ecd5e187253ab1abbd6fc04 and fixed in 5.10.40 with commit 4528c0c323085e645b8765913b4a7fd42cf49b65 |
| Issue introduced in 5.6 with commit c5b2cbdbdac563f46ecd5e187253ab1abbd6fc04 and fixed in 5.12.7 with commit 807fa14536b26803b858da878b643be72952a097 |
| Issue introduced in 5.6 with commit c5b2cbdbdac563f46ecd5e187253ab1abbd6fc04 and fixed in 5.13 with commit a11ddb37bf367e6b5239b95ca759e5389bb46048 |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2021-47069 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| ipc/mqueue.c |
| ipc/msg.c |
| ipc/sem.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/4528c0c323085e645b8765913b4a7fd42cf49b65 |
| https://git.kernel.org/stable/c/807fa14536b26803b858da878b643be72952a097 |
| https://git.kernel.org/stable/c/a11ddb37bf367e6b5239b95ca759e5389bb46048 |