CVE-2021-47069: ipc/mqueue, msg, sem: avoid relying on a stack reference past its expiry
In the Linux kernel, the following vulnerability has been resolved:
ipc/mqueue, msg, sem: avoid relying on a stack reference past its expiry
domqtimedreceive calls wqsleep with a stack local address. The sender (domqtimedsend) uses this address to later call pipelinedsend.
This leads to a very hard to trigger race where a domqtimedreceive call might return and leave domqtimedsend to rely on an invalid address, causing the following crash:
RIP: 0010:wakeqaddsafe+0x13/0x60 Call Trace: x64sysmqtimedsend+0x2a9/0x490 dosyscall64+0x80/0x680 entrySYSCALL64afterhwframe+0x44/0xa9 RIP: 0033:0x7f5928e40343
The race occurs as:
1. domqtimedreceive calls wqsleep with the address of struct extwaitqueue on function stack (aliased as ewqaddr here) - it holds a valid struct extwaitqueue as long as the stack has not been overwritten.
2. ewqaddr gets added to info->ewaitq[RECV].list in wqadd, and domqtimedsend receives it via wqgetfirstwaiter(info, RECV) to call pipelinedop.
3. Sender calls pipelinedop::smpstorerelease(&this->state, STATEREADY). Here is where the race window begins. (this is ewqaddr.)
4. If the receiver wakes up now in domqtimedreceive::wqsleep, it will see state == STATEREADY and break.
5. domqtimedreceive returns, and ewqaddr is no longer guaranteed to be a struct extwaitqueue since it was on domqtimedreceive'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. domqtimedsend::pipelinedop() still believes ewqaddr is a struct extwaitqueue , and uses it to find a taskstruct to pass to the wakeqaddsafe call. In the lucky case where nothing has overwritten ewqaddr yet, ewqaddr->task is the right taskstruct. In the unlucky case, pipelinedop::wakeqaddsafe gets handed a bogus address as the receiver's taskstruct causing the crash.
domqtimedsend::pipelinedop() should not dereference this after setting STATEREADY, as the receiver counterpart is now free to return. Change pipelinedop to call wakeqaddsafe on the receiver's taskstruct returned by gettaskstruct, instead of dereferencing this which sits on the receiver's stack.
As Manfred pointed out, the race potentially also exists in ipc/msg.c::expungeall and ipc/sem.c::wakeupsemqueueprepare. Fix those in the same way.
Other sources
In the Linux kernel, the following vulnerability has been resolved:
ipc/mqueue, msg, sem: avoid relying on a stack reference past its expiry
The Linux kernel CVE team has assigned CVE-2021-47069 to this issue.
Upstream advisory: https://lore.kernel.org/linux-cve-announce/2024030141-CVE-2021-47069-5797@gregkh/T/#u
— Red Hat
Affected Software
Remediation
Event History
Frequently Asked Questions
What is the severity of CVE-2021-47069?
CVE-2021-47069 has been classified as a high severity vulnerability in the Linux kernel.
How do I fix CVE-2021-47069?
To mitigate CVE-2021-47069, users should upgrade their Linux kernel to a version later than 5.10.40, 5.12.7, or any stable release after 5.13-rc2.
What components are affected by CVE-2021-47069?
CVE-2021-47069 affects the IPC mechanisms in the Linux kernel, specifically message queues and semaphores.
Which versions of the Linux kernel are vulnerable to CVE-2021-47069?
The vulnerable versions include Linux kernel versions 5.6 to 5.10.40 and from 5.11 to 5.12.7.
What impacts can result from exploiting CVE-2021-47069?
Exploitation of CVE-2021-47069 can lead to a potential denial of service by causing stack corruption in the Linux kernel.