CVE-2021-47303
Publication date:
21/05/2024
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&#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->size_poke_tab; i++) {<br />
poke = &elem->aux->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->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->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&#39;t try to double free<br />
the poke_tab when free&#39;ing the subprog structures. This is easily solved by<br />
NULL&#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->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---
Severity CVSS v4.0: Pending analysis
Last modification:
26/12/2024