CVE-2024-41010
Severity CVSS v4.0:
Pending analysis
Type:
CWE-416
Use After Free
Publication date:
17/07/2024
Last modified:
19/07/2024
Description
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
bpf: Fix too early release of tcx_entry<br />
<br />
Pedro Pinto and later independently also Hyunwoo Kim and Wongi Lee reported<br />
an issue that the tcx_entry can be released too early leading to a use<br />
after free (UAF) when an active old-style ingress or clsact qdisc with a<br />
shared tc block is later replaced by another ingress or clsact instance.<br />
<br />
Essentially, the sequence to trigger the UAF (one example) can be as follows:<br />
<br />
1. A network namespace is created<br />
2. An ingress qdisc is created. This allocates a tcx_entry, and<br />
&tcx_entry->miniq is stored in the qdisc&#39;s miniqp->p_miniq. At the<br />
same time, a tcf block with index 1 is created.<br />
3. chain0 is attached to the tcf block. chain0 must be connected to<br />
the block linked to the ingress qdisc to later reach the function<br />
tcf_chain0_head_change_cb_del() which triggers the UAF.<br />
4. Create and graft a clsact qdisc. This causes the ingress qdisc<br />
created in step 1 to be removed, thus freeing the previously linked<br />
tcx_entry:<br />
<br />
rtnetlink_rcv_msg()<br />
=> tc_modify_qdisc()<br />
=> qdisc_create()<br />
=> clsact_init() [a]<br />
=> qdisc_graft()<br />
=> qdisc_destroy()<br />
=> __qdisc_destroy()<br />
=> ingress_destroy() [b]<br />
=> tcx_entry_free()<br />
=> kfree_rcu() // tcx_entry freed<br />
<br />
5. Finally, the network namespace is closed. This registers the<br />
cleanup_net worker, and during the process of releasing the<br />
remaining clsact qdisc, it accesses the tcx_entry that was<br />
already freed in step 4, causing the UAF to occur:<br />
<br />
cleanup_net()<br />
=> ops_exit_list()<br />
=> default_device_exit_batch()<br />
=> unregister_netdevice_many()<br />
=> unregister_netdevice_many_notify()<br />
=> dev_shutdown()<br />
=> qdisc_put()<br />
=> clsact_destroy() [c]<br />
=> tcf_block_put_ext()<br />
=> tcf_chain0_head_change_cb_del()<br />
=> tcf_chain_head_change_item()<br />
=> clsact_chain_head_change()<br />
=> mini_qdisc_pair_swap() // UAF<br />
<br />
There are also other variants, the gist is to add an ingress (or clsact)<br />
qdisc with a specific shared block, then to replace that qdisc, waiting<br />
for the tcx_entry kfree_rcu() to be executed and subsequently accessing<br />
the current active qdisc&#39;s miniq one way or another.<br />
<br />
The correct fix is to turn the miniq_active boolean into a counter. What<br />
can be observed, at step 2 above, the counter transitions from 0->1, at<br />
step [a] from 1->2 (in order for the miniq object to remain active during<br />
the replacement), then in [b] from 2->1 and finally [c] 1->0 with the<br />
eventual release. The reference counter in general ranges from [0,2] and<br />
it does not need to be atomic since all access to the counter is protected<br />
by the rtnl mutex. With this in place, there is no longer a UAF happening<br />
and the tcx_entry is freed at the correct time.
Impact
Base Score 3.x
5.50
Severity 3.x
MEDIUM
Vulnerable products and versions
CPE | From | Up to |
---|---|---|
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 6.6 (including) | 6.6.41 (excluding) |
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 6.7 (including) | 6.9.10 (excluding) |
To consult the complete list of CPE names with products and versions, see this page