CVE-2021-46915 - Linux Kernel netfilter nft_limit Divide-By-Zero Vulnerability (In-depth Analysis & Exploit Details)

Published: 2021 | Last Update: 2024

Introduction

In early 2021, a vulnerability dubbed CVE-2021-46915 was discovered and subsequently patched in the Linux kernel, specifically within the netfilter nft_limit functionality. This bug allowed for a possible divide-by-zero or divide exception, leading to a kernel crash—*potentially opening the door to Denial-of-Service (DoS) attacks* from unprivileged user space.
This post breaks down the bug background, shows you the relevant code, and explains how the vulnerability could be abused, *all in simple terms*.


## Background: The netfilter/nft_limit component

- Netfilter is a framework inside the Linux kernel for packet filtering, network address translation, and other packet mangling.

nft_limit is part of netfilter’s rule set, used to impose limits (rate-limiting, etc.).

- Correct calculations and mathematics are critical for its safety, as unexpected values could crash the kernel.

What happened?

The bug was rooted in the misuse of division functions in the kernel math library.
In particular, nft_limit_init() used the div_u64() macro to divide a 64-bit (u64) variable by what could be another 64-bit (u64), but div_u64() is only safe for dividing by 32-bit (u32) values.

This type confusion caused a *divide-by-zero exception* when the denominator was zero or malformed by user input.

Here’s what a kernel crash looked like, as caught by Google Syzkaller’s fuzzing

divide error: 000 [#1] PREEMPT SMP KASAN
...
RIP: 001:div_u64_rem include/linux/math64.h:28 [inline]
RIP: 001:div_u64 include/linux/math64.h:127 [inline]
RIP: 001:nft_limit_init+x2a2/x5e net/netfilter/nft_limit.c:85
...

Here’s a simplified version illustrating the issue

#include <linux/math64.h>
...
u64 some_large_val;
u64 possibly_zero;
...
u64 res = div_u64(some_large_val, possibly_zero); // Unsafe! Denominator may be u64 and zero

The correct and safe approach is to use div64_u64()—the kernel’s built-in macro for dividing two 64-bit values, which also checks for zero and handles it safely.

The Patch

Here’s what the patch (see Patch Reference) looked like:

- u64 res = div_u64(some_large_val, possibly_zero);
+ u64 res = div64_u64(some_large_val, possibly_zero);

References

- Syzkaller Bug Report
- Upstream kernel commit
- CVE Page (NVD)

How Could It Be Exploited?

A local *unprivileged* user (or automated fuzzer like Syzkaller) could trigger this by injecting custom netfilter table expressions using something like the nft userspace utility. By providing a crafted payload that sets the denominator in limit calculations to zero (or an overly large value), the vulnerable code would hit the error.

Example Proof-of-Concept (POC) Exploit

*Below is a conceptual outline, not a weaponized tool.*

# Create a table
nft add table inet test

# Create a chain
nft add chain inet test limit_chain { type filter hook input priority \; }

# Add a bad rule that will trigger the buggy calculation
nft add rule inet test limit_chain limit rate over /second accept

- The critical line is limit rate over /second, which sets the denominator to zero.

The kernel will hit the faulty math function and crash with a divide error.

Result: The system will experience a kernel panic and instantly crash, *even from unprivileged userspace* (depending on configuration).

Exploit Impact

- DoS (Denial of Service): The most obvious and direct result is to crash the system, either repeatedly or on-demand.
- No privilege escalation is known, but in denial-of-service contexts even crashing a system is critical.

Detection: Monitor logs (dmesg or journalctl) for divide-by-zero panics in nft_limit_init.

- Mitigation: Update to a kernel version 5.12-rc5 or newer, or apply the backported patch on older versions.

As a workaround:

- Disable untrusted users from accessing/manipulating netfilter tables.
- Limit use of the nft utilities to root/admin only.

Summary

CVE-2021-46915 was a serious Linux kernel bug in netfilter's nft_limit, allowing for kernel panics via incorrect division operations. Although it didn't allow code execution or privilege escalation, *any crashable kernel bug is a potential incident*. Patching is highly recommended.

Stay safe, keep systems updated, and watch out for subtle kernel math errors!

*If you want to dig deeper, check out the upstream commit patch and the syzkaller report.*

Timeline

Published on: 02/27/2024 07:15:08 UTC
Last modified on: 04/10/2024 13:55:34 UTC