CVE-2021-47303

Severity CVSS v4.0:
Pending analysis
Type:
CWE-416 Use After Free
Publication date:
21/05/2024
Last modified:
26/12/2024

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> bpf: Track subprog poke descriptors correctly and fix use-after-free<br /> <br /> Subprograms are calling map_poke_track(), but on program release there is no<br /> hook to call map_poke_untrack(). However, on program release, the aux memory<br /> (and poke descriptor table) is freed even though we still have a reference to<br /> it in the element list of the map aux data. When we run map_poke_run(), we then<br /> end up accessing free&amp;#39;d memory, triggering KASAN in prog_array_map_poke_run():<br /> <br /> [...]<br /> [ 402.824689] BUG: KASAN: use-after-free in prog_array_map_poke_run+0xc2/0x34e<br /> [ 402.824698] Read of size 4 at addr ffff8881905a7940 by task hubble-fgs/4337<br /> [ 402.824705] CPU: 1 PID: 4337 Comm: hubble-fgs Tainted: G I 5.12.0+ #399<br /> [ 402.824715] Call Trace:<br /> [ 402.824719] dump_stack+0x93/0xc2<br /> [ 402.824727] print_address_description.constprop.0+0x1a/0x140<br /> [ 402.824736] ? prog_array_map_poke_run+0xc2/0x34e<br /> [ 402.824740] ? prog_array_map_poke_run+0xc2/0x34e<br /> [ 402.824744] kasan_report.cold+0x7c/0xd8<br /> [ 402.824752] ? prog_array_map_poke_run+0xc2/0x34e<br /> [ 402.824757] prog_array_map_poke_run+0xc2/0x34e<br /> [ 402.824765] bpf_fd_array_map_update_elem+0x124/0x1a0<br /> [...]<br /> <br /> The elements concerned are walked as follows:<br /> <br /> for (i = 0; i aux-&gt;size_poke_tab; i++) {<br /> poke = &amp;elem-&gt;aux-&gt;poke_tab[i];<br /> [...]<br /> <br /> The access to size_poke_tab is a 4 byte read, verified by checking offsets<br /> in the KASAN dump:<br /> <br /> [ 402.825004] The buggy address belongs to the object at ffff8881905a7800<br /> which belongs to the cache kmalloc-1k of size 1024<br /> [ 402.825008] The buggy address is located 320 bytes inside of<br /> 1024-byte region [ffff8881905a7800, ffff8881905a7c00)<br /> <br /> The pahole output of bpf_prog_aux:<br /> <br /> struct bpf_prog_aux {<br /> [...]<br /> /* --- cacheline 5 boundary (320 bytes) --- */<br /> u32 size_poke_tab; /* 320 4 */<br /> [...]<br /> <br /> In general, subprograms do not necessarily manage their own data structures.<br /> For example, BTF func_info and linfo are just pointers to the main program<br /> structure. This allows reference counting and cleanup to be done on the latter<br /> which simplifies their management a bit. The aux-&gt;poke_tab struct, however,<br /> did not follow this logic. The initial proposed fix for this use-after-free<br /> bug further embedded poke data tracking into the subprogram with proper<br /> reference counting. However, Daniel and Alexei questioned why we were treating<br /> these objects special; I agree, its unnecessary. The fix here removes the per<br /> subprogram poke table allocation and map tracking and instead simply points<br /> the aux-&gt;poke_tab pointer at the main programs poke table. This way, map<br /> tracking is simplified to the main program and we do not need to manage them<br /> per subprogram.<br /> <br /> This also means, bpf_prog_free_deferred(), which unwinds the program reference<br /> counting and kfrees objects, needs to ensure that we don&amp;#39;t try to double free<br /> the poke_tab when free&amp;#39;ing the subprog structures. This is easily solved by<br /> NULL&amp;#39;ing the poke_tab pointer. The second detail is to ensure that per<br /> subprogram JIT logic only does fixups on poke_tab[] entries it owns. To do<br /> this, we add a pointer in the poke structure to point at the subprogram value<br /> so JITs can easily check while walking the poke_tab structure if the current<br /> entry belongs to the current program. The aux pointer is stable and therefore<br /> suitable for such comparison. On the jit_subprogs() error path, we omit<br /> cleaning up the poke-&gt;aux field because these are only ever referenced from<br /> the JIT side, but on error we will never make it to the JIT, so its fine to<br /> leave them dangling. Removing these pointers would complicate the error path<br /> for no reason. However, we do need to untrack all poke descriptors from the<br /> main program as otherwise they could race with the freeing of JIT memory from<br /> the subprograms. Lastly, a748c6975dea3 ("bpf: propagate poke des<br /> ---truncated---

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.10 (including) 5.10.53 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.11 (including) 5.13.5 (excluding)
cpe:2.3:o:linux:linux_kernel:5.14:rc1:*:*:*:*:*:*