Bug 1215767 (CVE-2023-42756)

Summary: VUL-0: CVE-2023-42756: kernel-source: Linux kernel race condition in netfilter
Product: [Novell Products] SUSE Security Incidents Reporter: Gianluca Gabrielli <gianluca.gabrielli>
Component: IncidentsAssignee: Security Team bot <security-team>
Status: RESOLVED FIXED QA Contact: Security Team bot <security-team>
Severity: Normal    
Priority: P3 - Medium CC: chester.lin, denis.kirjanov, meissner, mkubecek
Version: unspecified   
Target Milestone: ---   
Hardware: Other   
OS: Other   
URL: https://smash.suse.de/issue/379891/
Whiteboard: CVSSv3.1:SUSE:CVE-2023-42756:5.5:(AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H)
Found By: --- Services Priority:
Business Priority: Blocker: ---
Marketing QA Status: --- IT Deployment: ---

Comment 6 Gianluca Gabrielli 2023-09-28 09:09:06 UTC
From the osss public ML
-----------------------

Hi there,

I recently found a race condition bug in the Linux kernel between
IPSET_CMD_ADD and IPSET_CMD_SWAP in netfilter/ip_set, which can
lead to the invocation of `__ip_set_put` on a wrong `set`, triggering
the `BUG_ON(set->ref == 0);` check in it, which leads to local DoS.
I confirm it at least affect upstream, v6.5.rc7, v6.1, and v5.10.

[Root Cause]
The bug is in the netfilter subsystem.
In `ip_set_swap` function, it will hold the `ip_set_ref_lock`
and then do the following to swap the sets:
~~~
        strncpy(from_name, from->name, IPSET_MAXNAMELEN);
        strncpy(from->name, to->name, IPSET_MAXNAMELEN);
        strncpy(to->name, from_name, IPSET_MAXNAMELEN);

        swap(from->ref, to->ref);
~~~
But in the retry loop in `call_ad`:
~~~
                if (retried) {
                        __ip_set_get(set);
                        nfnl_unlock(NFNL_SUBSYS_IPSET);
                        cond_resched();
                        nfnl_lock(NFNL_SUBSYS_IPSET);
                        __ip_set_put(set);
                }
~~~
No lock is hold when it does the `cond_resched()`.
As a result, `ip_set_ref_lock` (in thread 2) can swap the set with
another when thread 1 is doing the `cond_resched()`. When thread 1
wakes up, the `set` variable alreays means another `set`, calling
`__ip_set_put` on it will decrease the refcount on the wrong `set`,
triggering the `BUG_ON` call.

According to Jozsef Kadlecsik, who fixed the bug, the root cause is that
the `call_ad` function is using a wrong ref counter. Instead of using
`__ip_set_get`, which operates on `set->ref`, the correct way is to
operate on `set->ref_netlink`.

[Severity]
It will invoke a `BUG_ON` call, leading to kernel panic.
In other words, it will lead to local DoS.

[Patch]
Jozsef Kadlecsik prepared a patch and it got merged into mainline and
stables already.
The patch can be found here:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7433b6d2afd512d04398c73aa984d1e285be125b

[Proof-of-Concept]
A proof-of-concept code to trigger the bug is attached to this email.

Best,
Kyle
Comment 7 Chester Lin 2023-10-03 04:26:33 UTC
CVE information is published on 9/28:

https://nvd.nist.gov/vuln/detail/CVE-2023-42756
https://www.cve.org/CVERecord?id=CVE-2023-42756
Comment 9 Michal Kubeček 2023-10-03 07:36:47 UTC
introduced      24e227896bbf    6.4-rc6
fixed           7433b6d2afd5    6.6-rc3

The offending commit has not been backported into any older branch.

The fix has been submitted to all affected branches:

stable          5c8516c7353b    
SLE15-SP6       fd797f52ac9b

Reassigning back to security team.
Comment 16 Andrea Mattiazzo 2024-06-07 12:16:29 UTC
All done, closing.