CVE-2022-49236

Severity CVSS v4.0:
Pending analysis
Type:
CWE-416 Use After Free
Publication date:
26/02/2025
Last modified:
25/03/2025

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> bpf: Fix UAF due to race between btf_try_get_module and load_module<br /> <br /> While working on code to populate kfunc BTF ID sets for module BTF from<br /> its initcall, I noticed that by the time the initcall is invoked, the<br /> module BTF can already be seen by userspace (and the BPF verifier). The<br /> existing btf_try_get_module calls try_module_get which only fails if<br /> mod-&gt;state == MODULE_STATE_GOING, i.e. it can increment module reference<br /> when module initcall is happening in parallel.<br /> <br /> Currently, BTF parsing happens from MODULE_STATE_COMING notifier<br /> callback. At this point, the module initcalls have not been invoked.<br /> The notifier callback parses and prepares the module BTF, allocates an<br /> ID, which publishes it to userspace, and then adds it to the btf_modules<br /> list allowing the kernel to invoke btf_try_get_module for the BTF.<br /> <br /> However, at this point, the module has not been fully initialized (i.e.<br /> its initcalls have not finished). The code in module.c can still fail<br /> and free the module, without caring for other users. However, nothing<br /> stops btf_try_get_module from succeeding between the state transition<br /> from MODULE_STATE_COMING to MODULE_STATE_LIVE.<br /> <br /> This leads to a use-after-free issue when BPF program loads<br /> successfully in the state transition, load_module&amp;#39;s do_init_module call<br /> fails and frees the module, and BPF program fd on close calls module_put<br /> for the freed module. Future patch has test case to verify we don&amp;#39;t<br /> regress in this area in future.<br /> <br /> There are multiple points after prepare_coming_module (in load_module)<br /> where failure can occur and module loading can return error. We<br /> illustrate and test for the race using the last point where it can<br /> practically occur (in module __init function).<br /> <br /> An illustration of the race:<br /> <br /> CPU 0 CPU 1<br /> load_module<br /> notifier_call(MODULE_STATE_COMING)<br /> btf_parse_module<br /> btf_alloc_id // Published to userspace<br /> list_add(&amp;btf_mod-&gt;list, btf_modules)<br /> mod-&gt;init(...)<br /> ... ^<br /> bpf_check |<br /> check_pseudo_btf_id |<br /> btf_try_get_module |<br /> returns true | ...<br /> ... | module __init in progress<br /> return prog_fd | ...<br /> ... V<br /> if (ret

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.12 (including) 5.15.33 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.16 (including) 5.16.19 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.17 (including) 5.17.2 (excluding)