skbuff: Fix a race between coalescing and releasing SKBs
CVE: CVE-2023-53186
Component: kernel
CWE: CWE-416
Severity: Important
CVSS v3: 6.9/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H
Release date: 2023-01-01T00:00:00+00:00

In the Linux kernel, the following vulnerability has been resolved:

skbuff: Fix a race between coalescing and releasing SKBs

Commit 1effe8ca4e34 ("skbuff: fix coalescing for page_pool fragment
recycling") allowed coalescing to proceed with non page pool page and page
pool page when @from is cloned, i.e.

to->pp_recycle    --> false
from->pp_recycle  --> true
skb_cloned(from)  --> true

However, it actually requires skb_cloned(@from) to hold true until
coalescing finishes in this situation. If the other cloned SKB is
released while the merging is in process, from_shinfo->nr_frags will be
set to 0 toward the end of the function, causing the increment of frag
page _refcount to be unexpectedly skipped resulting in inconsistent
reference counts. Later when SKB(@to) is released, it frees the page
directly even though the page pool page is still in use, leading to
use-after-free or double-free errors. So it should be prohibited.

The double-free error message below prompted us to investigate:
BUG: Bad page state in process swapper/1  pfn:0e0d1
page:00000000c6548b28 refcount:-1 mapcount:0 mapping:0000000000000000
index:0x2 pfn:0xe0d1
flags: 0xfffffc0000000(node=0|zone=1|lastcpupid=0x1fffff)
raw: 000fffffc0000000 0000000000000000 ffffffff00000101 0000000000000000
raw: 0000000000000002 0000000000000000 ffffffffffffffff 0000000000000000
page dumped because: nonzero _refcount

CPU: 1 PID: 0 Comm: swapper/1 Tainted: G            E      6.2.0+
Call Trace:
 <IRQ>
dump_stack_lvl+0x32/0x50
bad_page+0x69/0xf0
free_pcp_prepare+0x260/0x2f0
free_unref_page+0x20/0x1c0
skb_release_data+0x10b/0x1a0
napi_consume_skb+0x56/0x150
net_rx_action+0xf0/0x350
? __napi_schedule+0x79/0x90
__do_softirq+0xc8/0x2b1
__irq_exit_rcu+0xb9/0xf0
common_interrupt+0x82/0xa0
</IRQ>
<TASK>
asm_common_interrupt+0x22/0x40
RIP: 0010:default_idle+0xb/0x20

Statement: A race condition in skb_try_coalesce() could lead to use-after-free or double-free when a cloned SKB with page_pool pages is released during coalescing. This results in inconsistent reference counts and potential kernel crashes.
While primarily a denial-of-service issue, exploitation could theoretically be extended to arbitrary code execution, though the complexity of reliably triggering the race is high.
The flaw only affects systems with NIC drivers using the page_pool API, limiting its exposure in practice.
The bug not actual for Red Hat Enterprise Linux 8 (all versions) and actual only for versions of the Red Hat Enterprise Linux 9 before 9.3.

Remediation:
For details on how to apply this update, which includes the changes described in this advisory, refer to:

https://access.redhat.com/articles/11258

The system must be rebooted for this update to take effect.
For details on how to apply this update, which includes the changes described in this advisory, refer to:

https://access.redhat.com/articles/11258

The system must be rebooted for this update to take effect.
It is not possible to completely eliminate the theoretical risk of a remote exploit, but the attack is fairly complex and in many realistic deployments cannot be triggered from outside the local network. You can substantially reduce the likelihood of a successful attack by disabling network features that cause drivers to use the page_pool/zero-copy receive paths. The following commands are a conceptual example of mitigations — adapt them to your interface and driver:

# replace eth0 with the actual interface name

# turn off generic offloads that often change skb handling
ethtool -K eth0 gro off lro off gso off tso off rx off
# disable rx/tx offload flags separately:
ethtool -K eth0 rxvlan off rxhash off
# disable specific features (driver dependent)
ethtool -k eth0