CVE-2026-45841
Description
In the Linux kernel, the following vulnerability has been resolved:
netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
nf_osf_match_one() computes ctx->window % f->wss.val in the OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a subsequent matching TCP SYN divides by zero and panics the kernel.
Reject the bogus fingerprint in nfnl_osf_add_callback() above the per-option for-loop. f->wss is per-fingerprint, not per-option, so the check must run regardless of f->opt_num (including 0). Also reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that as "should not happen".
Crash: Oops: divide error: 0000 [#1] SMP KASAN NOPTI RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) Call Trace:
nf_osf_match (net/netfilter/nfnetlink_osf.c:220) xt_osf_match_packet (net/netfilter/xt_osf.c:32) ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) nf_hook_slow (net/netfilter/core.c:622) ip_local_deliver (net/ipv4/ip_input.c:265) ip_rcv (include/linux/skbuff.h:1162) __netif_receive_skb_one_core (net/core/dev.c:6181) process_backlog (net/core/dev.c:6642) __napi_poll (net/core/dev.c:7710) net_rx_action (net/core/dev.c:7945) handle_softirqs (kernel/softirq.c:622)
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A CAP_NET_ADMIN user can trigger a kernel panic via a divide-by-zero in the Linux kernel's netfilter OSF module by adding a malicious TCP fingerprint with wss.val=0.
Vulnerability
In the Linux kernel, a divide-by-zero bug exists in nf_osf_match_one() (net/netfilter/nfnetlink_osf.c:98) within the OSF_WSS_MODULO branch. The computation ctx->window % f->wss.val is performed without validating that f->wss.val is non-zero. This flaw is exploitable because nfnetlink allows a CAP_NET_ADMIN user to add a crafted fingerprint via nfnl_osf_add_callback() without checking for a zero denominator. The fix, introduced in commit [1], adds validation to reject fingerprints where wss.val == 0 or wss.wc >= OSF_WSS_MAX. Affected versions include those prior to the stable commit [1].
Exploitation
An attacker with CAP_NET_ADMIN capabilities can add a malicious TCP fingerprint to the OSF (Open Source Fingerprinting) database via nfnetlink. The fingerprint must have the OSF_WSS_MODULO option set with wss.val equal to 0. Once added, any subsequent TCP SYN packet that matches this fingerprint will trigger the divide operation in nf_osf_match_one(), causing a division by zero. No additional user interaction or network access beyond the ability to send a matching TCP SYN is required, as the vulnerability is triggered during the packet processing path within the kernel's softirq context (as shown in the crash trace: handle_softirqs → net_rx_action → ... → nf_osf_match_one).
Impact
Successful exploitation results in a kernel panic (divide error), leading to a denial of service (DoS) for the entire system. The crash trace confirms an Oops with SMP KASAN NOPTI, indicating a complete kernel failure. The attack requires CAP_NET_ADMIN privileges, which are typically restricted to trusted users, but if an attacker gains such privileges, they can reliably crash the kernel. The impact is limited to availability; there is no evidence of privilege escalation or data corruption from this bug.
Mitigation
The vulnerability is fixed by the Linux kernel commit [1] (2195574dc6d9017d32ac346987e12659f931d932). This commit adds input validation in nfnl_osf_add_callback() to reject fingerprint configurations where f->wss.val == 0 or f->wss.wc >= OSF_WSS_MAX. Administrators should apply this patch or update to a kernel version that includes it (e.g., stable releases after the commit date). No workaround is available for unpatched systems, as the packet processing path cannot be easily disabled without removing the OSF match feature. The CVE is not listed in CISA's Known Exploited Vulnerabilities catalog as of the publication date.
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
108def8fbd23f4netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index da9d5d6de98f4d..000a5c280ef96c 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
c55940895245netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 9fc9544d4bc53d..2305c7d9761ebc 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
fb965b1cfe92netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 9fc9544d4bc53d..2305c7d9761ebc 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
9a05e195618anetfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 45d9ad231a9204..70172ca0785854 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
2195574dc6d9netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index d64ce21c7b5542..9de91fdd107cd9 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
8def8fbd23f4netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index da9d5d6de98f4d..000a5c280ef96c 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
9a05e195618anetfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 45d9ad231a9204..70172ca0785854 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
c55940895245netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 9fc9544d4bc53d..2305c7d9761ebc 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
fb965b1cfe92netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 9fc9544d4bc53d..2305c7d9761ebc 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
2195574dc6d9netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
1 file changed · +4 −1
net/netfilter/nfnetlink_osf.c+4 −1 modifieddiff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index d64ce21c7b5542..9de91fdd107cd9 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing input validation allows a fingerprint with wss.val == 0 to be added, causing a divide-by-zero in nf_osf_match_one()."
Attack vector
An attacker with `CAP_NET_ADMIN` privileges sends a crafted nfnetlink message to add an OS fingerprint whose window-size check type (`wss.wc`) is set to `OSF_WSS_MODULO` and whose `wss.val` is zero [patch_id=2654201]. When a TCP SYN packet subsequently traverses an iptables rule using the `xt_osf` match, `nf_osf_match_one()` performs a modulo operation with divisor zero, triggering a divide-by-zero exception that panics the kernel [patch_id=2654201]. The crash occurs in softirq context during network receive processing.
Affected code
The vulnerable code path is in `nf_osf_match_one()` at `net/netfilter/nfnetlink_osf.c:98`, where `ctx->window % f->wss.val` is computed without checking for `f->wss.val == 0`. The fingerprint is added via `nfnl_osf_add_callback()` in the same file, which previously lacked validation of `f->wss.wc` and `f->wss.val`.
What the fix does
The patch adds two input-validation checks in `nfnl_osf_add_callback()` before the per-option loop [patch_id=2654201]. It rejects any fingerprint where `f->wss.wc >= OSF_WSS_MAX` (an out-of-bounds window-size check type) or where `f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0` (the modulo divisor is zero). These checks are placed above the per-option loop because `f->wss` is a per-fingerprint field, not a per-option field, so the validation must run regardless of `f->opt_num` (including zero) [patch_id=2654201]. By rejecting the malformed fingerprint at addition time, the kernel prevents the divide-by-zero from ever being reached during packet matching.
Preconditions
- authAttacker must have CAP_NET_ADMIN capability to send nfnetlink messages.
- configA valid iptables rule using the xt_osf match must be installed on the target system.
- inputA TCP SYN packet must arrive that triggers the xt_osf match against the crafted fingerprint.
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- git.kernel.org/stable/c/2195574dc6d9017d32ac346987e12659f931d932nvd
- git.kernel.org/stable/c/8def8fbd23f40e945febe913d04b731012ce0082nvd
- git.kernel.org/stable/c/9a05e195618a6d474f2bcd5b6376d0ffc2f00366nvd
- git.kernel.org/stable/c/c55940895245d8ef658ab381248a28755218d625nvd
- git.kernel.org/stable/c/fb965b1cfe92b28d28b5ebe3116b81dbef9f2d2fnvd
News mentions
0No linked articles in our index yet.