powerpc/rtas_flash: allow user copy to flash block cache objects
authorNathan Lynch <nathanl@linux.ibm.com>
Fri, 11 Aug 2023 03:37:55 +0000 (22:37 -0500)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 16 Aug 2023 23:46:14 +0000 (09:46 +1000)
With hardened usercopy enabled (CONFIG_HARDENED_USERCOPY=y), using the
/proc/powerpc/rtas/firmware_update interface to prepare a system
firmware update yields a BUG():

  kernel BUG at mm/usercopy.c:102!
  Oops: Exception in kernel mode, sig: 5 [#1]
  LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA pSeries
  Modules linked in:
  CPU: 0 PID: 2232 Comm: dd Not tainted 6.5.0-rc3+ #2
  Hardware name: IBM,8408-E8E POWER8E (raw) 0x4b0201 0xf000004 of:IBM,FW860.50 (SV860_146) hv:phyp pSeries
  NIP:  c0000000005991d0 LR: c0000000005991cc CTR: 0000000000000000
  REGS: c0000000148c76a0 TRAP: 0700   Not tainted  (6.5.0-rc3+)
  MSR:  8000000000029033 <SF,EE,ME,IR,DR,RI,LE>  CR: 24002242  XER: 0000000c
  CFAR: c0000000001fbd34 IRQMASK: 0
  [ ... GPRs omitted ... ]
  NIP usercopy_abort+0xa0/0xb0
  LR  usercopy_abort+0x9c/0xb0
  Call Trace:
    usercopy_abort+0x9c/0xb0 (unreliable)
    __check_heap_object+0x1b4/0x1d0
    __check_object_size+0x2d0/0x380
    rtas_flash_write+0xe4/0x250
    proc_reg_write+0xfc/0x160
    vfs_write+0xfc/0x4e0
    ksys_write+0x90/0x160
    system_call_exception+0x178/0x320
    system_call_common+0x160/0x2c4

The blocks of the firmware image are copied directly from user memory
to objects allocated from flash_block_cache, so flash_block_cache must
be created using kmem_cache_create_usercopy() to mark it safe for user
access.

Fixes: 6d07d1cd300f ("usercopy: Restrict non-usercopy caches to size 0")
Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
[mpe: Trim and indent oops]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230810-rtas-flash-vs-hardened-usercopy-v2-1-dcf63793a938@linux.ibm.com
arch/powerpc/kernel/rtas_flash.c

index 4caf5e3..359577e 100644 (file)
@@ -709,9 +709,9 @@ static int __init rtas_flash_init(void)
        if (!rtas_validate_flash_data.buf)
                return -ENOMEM;
 
-       flash_block_cache = kmem_cache_create("rtas_flash_cache",
-                                             RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0,
-                                             NULL);
+       flash_block_cache = kmem_cache_create_usercopy("rtas_flash_cache",
+                                                      RTAS_BLK_SIZE, RTAS_BLK_SIZE,
+                                                      0, 0, RTAS_BLK_SIZE, NULL);
        if (!flash_block_cache) {
                printk(KERN_ERR "%s: failed to create block cache\n",
                                __func__);