CVE-2021-46957

Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
27/02/2024
Last modified:
14/03/2025

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> riscv/kprobe: fix kernel panic when invoking sys_read traced by kprobe<br /> <br /> The execution of sys_read end up hitting a BUG_ON() in __find_get_block<br /> after installing kprobe at sys_read, the BUG message like the following:<br /> <br /> [ 65.708663] ------------[ cut here ]------------<br /> [ 65.709987] kernel BUG at fs/buffer.c:1251!<br /> [ 65.711283] Kernel BUG [#1]<br /> [ 65.712032] Modules linked in:<br /> [ 65.712925] CPU: 0 PID: 51 Comm: sh Not tainted 5.12.0-rc4 #1<br /> [ 65.714407] Hardware name: riscv-virtio,qemu (DT)<br /> [ 65.715696] epc : __find_get_block+0x218/0x2c8<br /> [ 65.716835] ra : __getblk_gfp+0x1c/0x4a<br /> [ 65.717831] epc : ffffffe00019f11e ra : ffffffe00019f56a sp : ffffffe002437930<br /> [ 65.719553] gp : ffffffe000f06030 tp : ffffffe0015abc00 t0 : ffffffe00191e038<br /> [ 65.721290] t1 : ffffffe00191e038 t2 : 000000000000000a s0 : ffffffe002437960<br /> [ 65.723051] s1 : ffffffe00160ad00 a0 : ffffffe00160ad00 a1 : 000000000000012a<br /> [ 65.724772] a2 : 0000000000000400 a3 : 0000000000000008 a4 : 0000000000000040<br /> [ 65.726545] a5 : 0000000000000000 a6 : ffffffe00191e000 a7 : 0000000000000000<br /> [ 65.728308] s2 : 000000000000012a s3 : 0000000000000400 s4 : 0000000000000008<br /> [ 65.730049] s5 : 000000000000006c s6 : ffffffe00240f800 s7 : ffffffe000f080a8<br /> [ 65.731802] s8 : 0000000000000001 s9 : 000000000000012a s10: 0000000000000008<br /> [ 65.733516] s11: 0000000000000008 t3 : 00000000000003ff t4 : 000000000000000f<br /> [ 65.734434] t5 : 00000000000003ff t6 : 0000000000040000<br /> [ 65.734613] status: 0000000000000100 badaddr: 0000000000000000 cause: 0000000000000003<br /> [ 65.734901] Call Trace:<br /> [ 65.735076] [] __find_get_block+0x218/0x2c8<br /> [ 65.735417] [] __ext4_get_inode_loc+0xb2/0x2f6<br /> [ 65.735618] [] ext4_get_inode_loc+0x3a/0x8a<br /> [ 65.735802] [] ext4_reserve_inode_write+0x2e/0x8c<br /> [ 65.735999] [] __ext4_mark_inode_dirty+0x4c/0x18e<br /> [ 65.736208] [] ext4_dirty_inode+0x46/0x66<br /> [ 65.736387] [] __mark_inode_dirty+0x12c/0x3da<br /> [ 65.736576] [] touch_atime+0x146/0x150<br /> [ 65.736748] [] filemap_read+0x234/0x246<br /> [ 65.736920] [] generic_file_read_iter+0xc0/0x114<br /> [ 65.737114] [] ext4_file_read_iter+0x42/0xea<br /> [ 65.737310] [] new_sync_read+0xe2/0x15a<br /> [ 65.737483] [] vfs_read+0xca/0xf2<br /> [ 65.737641] [] ksys_read+0x5e/0xc8<br /> [ 65.737816] [] sys_read+0xe/0x16<br /> [ 65.737973] [] ret_from_syscall+0x0/0x2<br /> [ 65.738858] ---[ end trace fe93f985456c935d ]---<br /> <br /> A simple reproducer looks like:<br /> echo &amp;#39;p:myprobe sys_read fd=%a0 buf=%a1 count=%a2&amp;#39; &gt; /sys/kernel/debug/tracing/kprobe_events<br /> echo 1 &gt; /sys/kernel/debug/tracing/events/kprobes/myprobe/enable<br /> cat /sys/kernel/debug/tracing/trace<br /> <br /> Here&amp;#39;s what happens to hit that BUG_ON():<br /> <br /> 1) After installing kprobe at entry of sys_read, the first instruction<br /> is replaced by &amp;#39;ebreak&amp;#39; instruction on riscv64 platform.<br /> <br /> 2) Once kernel reach the &amp;#39;ebreak&amp;#39; instruction at the entry of sys_read,<br /> it trap into the riscv breakpoint handler, where it do something to<br /> setup for coming single-step of origin instruction, including backup<br /> the &amp;#39;sstatus&amp;#39; in pt_regs, followed by disable interrupt during single<br /> stepping via clear &amp;#39;SIE&amp;#39; bit of &amp;#39;sstatus&amp;#39; in pt_regs.<br /> <br /> 3) Then kernel restore to the instruction slot contains two instructions,<br /> one is original instruction at entry of sys_read, the other is &amp;#39;ebreak&amp;#39;.<br /> Here it trigger a &amp;#39;Instruction page fault&amp;#39; exception (value at &amp;#39;scause&amp;#39;<br /> is &amp;#39;0xc&amp;#39;), if PF is not filled into PageTabe for that slot yet.<br /> <br /> 4) Again kernel trap into page fault exception handler, where it choose<br /> different policy according to the state of running kprobe. Because<br /> afte 2) the state is KPROBE_HIT_SS, so kernel reset the current kp<br /> ---truncated---

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.12 (including) 5.12.3 (excluding)