Linux, as robust as it is, occasionally suffers from subtle vulnerabilities born from the complexity of interacting kernel components. CVE-2021-47013 is one such vulnerability, lurking in the EMAC network driver’s transmission buffer path (emac_mac_tx_buf_send). In this long read, you’ll gain a clear understanding of the bug, how it was exploited, and how the fix works. I'll keep the language simple, show you code, and provide references to the original advisory and patch.
What is CVE-2021-47013?
CVE-2021-47013 is a use-after-free vulnerability affecting certain versions of the Linux kernel. Specifically, it appears in the _EMAC_ (Ethernet Media Access Controller) driver, which is responsible for handling network data transmission to and from network hardware.
The problem lies in the way packet data buffers (skb, or "socket buffers") are handled during error conditions in the function emac_mac_tx_buf_send. When an error occurs, a network buffer may be freed, but the function still tries to use its fields—leading to undefined behavior, possible memory corruption, or potential privilege escalation.
Here’s a simplified version of the bad code (prior to the patch)
static int emac_mac_tx_buf_send(struct net_device *ndev, struct sk_buff *skb)
{
...
ret = emac_tx_fill_tpd(prv, skb, ...);
if (ret) {
// emac_tx_fill_tpd frees skb on failure
return ret;
}
/* Use length of skb */
netdev_sent_queue(ndev, skb->len);
...
}
emac_tx_fill_tpd(prv, skb, ...) processes the buffer.
- If an error occurs (ret is non-zero), this function frees the skb using dev_kfree_skb(skb).
- BUT THEN: The code accesses skb->len _after_ it could have been freed! This is called “use after free,” and it’s a classic kernel bug.
Why is this dangerous?
After freeing memory, its contents may be overwritten or reclaimed. Accessing skb->len after it’s freed could crash the system, cause data leaks, or even allow malicious attackers to execute code if they fill the freed memory with their own data.
How to Exploit It (Conceptually)?
Exploiting this bug generally would require a process capable of queuing data (sk_buffs) that can trigger the error path in emac_tx_fill_tpd. When the unsafe use-after-free code runs, the attacker may leverage this state to influence kernel control flow, possibly leading to local privilege escalation or system instability.
Exploitability in practice depends on allocation patterns and what objects are placed in that memory after it is freed. If an attacker can allocate data into the slot just freed (a classic "heap spray"), they may set the value of skb->len to a desired value, potentially controlling the behavior of netdev_sent_queue, causing accounting bugs or further memory corruption.
Because this is in the network stack, it could even be triggered remotely in certain setups—especially if EMAC is used with user-submitted frames.
The Patch: How Developers Fixed It
The fix is simple but effective: grab the length value before freeing, and use the saved value instead of accessing the potentially freed buffer.
Patch snippet
static int emac_mac_tx_buf_send(struct net_device *ndev, struct sk_buff *skb)
{
int ret;
unsigned int len = skb->len; // Save the length before possible free
ret = emac_tx_fill_tpd(prv, skb, ...);
if (ret) {
// skb freed inside emac_tx_fill_tpd on error
return ret;
}
netdev_sent_queue(ndev, len); // Use saved length
...
}
This small change eliminates use-after-free: skb->len is read while skb is still valid, and the value is saved. After the function that might free skb is called, the code now works with just len. Simple, safe!
Complete Patch Example
Here’s a close-to-real snippet adapted from the official patch (source):
@@ -234,11 +234,13 @@ static int emac_mac_tx_buf_send(struct net_device *ndev, struct sk_buff *skb)
- ret = emac_tx_fill_tpd(prv, skb, ...);
- if (ret)
- return ret;
-
- netdev_sent_queue(ndev, skb->len);
+ unsigned int len = skb->len;
+ ret = emac_tx_fill_tpd(prv, skb, ...);
+ if (ret)
+ return ret;
+
+ netdev_sent_queue(ndev, len);
References
- Main commit/patch: Linux upstream commit dabf3368cdbcf1c15c33
- CVE record: CVE-2021-47013 - NVD
- Linux Kernel Bugzilla: Linux Kernel Bugzilla #214121
- EMAC driver code: Linux source tree - emac driver
Why Does This Matter?
- Security: Use-after-free bugs are among the most dangerous in C/C++ code, especially in kernel land. They're not just theoretical—a motivated attacker can leverage bugs like this to take over systems.
- Stability: Even if not exploited, these bugs often lead to system crashes or data corruption, affecting anyone running affected kernel versions.
- Lesson: Always save values you need before freeing structures. Don’t touch memory after free.
TL;DR
CVE-2021-47013 was a nasty use-after-free in the Linux kernel’s EMAC MAC transmit path. If a certain error happened, the driver would free a network buffer and then immediately use it again—inviting crashes or potentially even attacks.
A one-line patch—in which the needed value was saved before freeing—fixed the bug.
Vulnerabilities don't always need complex remediation, but they do need vigilance and smart, simple programming.
Stay safe, and keep your kernel updated!
*For more details, see the official Linux commit patch and the CVE-2021-47013 advisory.*
Timeline
Published on: 02/28/2024 09:15:38 UTC
Last modified on: 12/09/2024 17:59:07 UTC