Bug: Write fault blocked by KUAP! (kernel 6.2-rc6, Talos II)

Christophe Leroy christophe.leroy at csgroup.eu
Thu Feb 9 18:21:55 AEDT 2023



Le 03/02/2023 à 03:45, Nicholas Piggin a écrit :
> On Fri Feb 3, 2023 at 12:02 PM AEST, Benjamin Gray wrote:
>> On Fri, 2023-02-03 at 00:46 +0100, Erhard F. wrote:
>>> Happened during boot:
>>>
>>> [...]
>>> Creating 6 MTD partitions on "flash at 0":
>>> 0x000000000000-0x000004000000 : "PNOR"
>>> 0x000001b21000-0x000003921000 : "BOOTKERNEL"
>>> 0x000003a44000-0x000003a68000 : "CAPP"
>>> 0x000003a88000-0x000003a89000 : "VERSION"
>>> 0x000003a89000-0x000003ac9000 : "IMA_CATALOG"
>>> 0x000003e10000-0x000004000000 : "BOOTKERNFW"
>>> BTRFS info: devid 1 device path /dev/root changed to /dev/nvme0n1p3
>>> scanned by systemd-udevd (387)
>>> Kernel attempted to write user page (aa55c280000) - exploit attempt?
>>> (uid: 0)
>>> ------------[ cut here ]------------
>>> Bug: Write fault blocked by KUAP!
> 
> KUAP is a red herring of course, the KUAP test just checks if the
> faulting address is below TASK_SIZE.
> 
> [snip]
> 
>>> --- interrupt: 300 at __patch_instruction+0x50/0x70
>>> NIP:  c000000000064670 LR: c000000000064c2c CTR: c000000000048ee0
>>> REGS: c000000023b57630 TRAP: 0300   Tainted: G                T
>>> (6.2.0-rc6-P9)
>>> MSR:  900000000280b032 <SF,HV,VEC,VSX,EE,FP,ME,IR,DR,RI>  CR:
>>> 24222244  XER: 00000000
>>> CFAR: c00000000006462c DAR: 00000aa55c280000 DSISR: 42000000 IRQMASK:
>                                              ^^^^        ^^
> First byte of page, store, no PTE.
> 
>>> 1
>>> GPR00: 0000000000000000 c000000023b578d0 c000000000e7cc00
>>> c00800000ce33ffc
>>> GPR04: 041ae13000000000 00000aa55c27fffc 0000000000000000
>                                          ^^^^
> Last word of previous page.
> 
> Probably from create_stub function descriptor patching, which is not
> actually patching in an instruction so it probably gets unlucky and
> gets some data that matches prefix opcode and so it tries to store
> 8 bytes.

An easy fix would probably be to also check the suffix as a prefixed 
instruction with 0 as suffix is not valid :

diff --git a/arch/powerpc/include/asm/inst.h 
b/arch/powerpc/include/asm/inst.h
index 684d3f453282..87084a52598b 100644
--- a/arch/powerpc/include/asm/inst.h
+++ b/arch/powerpc/include/asm/inst.h
@@ -86,7 +86,7 @@ static inline ppc_inst_t ppc_inst_read(const u32 *ptr)

  static inline bool ppc_inst_prefixed(ppc_inst_t x)
  {
-	return IS_ENABLED(CONFIG_PPC64) && ppc_inst_primary_opcode(x) == 
OP_PREFIX;
+	return IS_ENABLED(CONFIG_PPC64) && ppc_inst_primary_opcode(x) == 
OP_PREFIX && ppc_inst_suffix(x);
  }

  static inline ppc_inst_t ppc_inst_swab(ppc_inst_t x)


> 
> So not your bug, your temp mm code just exposed it. Data shouldn't
> be patched using patch_instruction. We should have a patch_data_u32
> or similar that doesn't use instructions.

There is work in progress on this but if the above check works, it is 
probably a better approach as a fix that can be backported.


More information about the Linuxppc-dev mailing list