• Mark Rutland's avatar
    io_uring: fix SQPOLL cpu validation · 975554b0
    Mark Rutland authored
    In io_sq_offload_start(), we call cpu_possible() on an unbounded cpu
    value from userspace. On v5.1-rc7 on arm64 with
    CONFIG_DEBUG_PER_CPU_MAPS, this results in a splat:
    
      WARNING: CPU: 1 PID: 27601 at include/linux/cpumask.h:121 cpu_max_bits_warn include/linux/cpumask.h:121 [inline]
    
    There was an attempt to fix this in commit:
    
      917257da ("io_uring: only test SQPOLL cpu after we've verified it")
    
    ... by adding a check after the cpu value had been limited to NR_CPU_IDS
    using array_index_nospec(). However, this left an unbound check at the
    start of the function, for which the warning still fires.
    
    Let's fix this correctly by checking that the cpu value is bound by
    nr_cpu_ids before passing it to cpu_possible(). Note that only
    nr_cpu_ids of a cpumask are guaranteed to exist at runtime, and
    nr_cpu_ids can be significantly smaller than NR_CPUs. For example, an
    arm64 defconfig has NR_CPUS=256, while my test VM has 4 vCPUs.
    
    Following the intent from the commit message for 917257da, the
    check is moved under the SQ_AFF branch, which is the only branch where
    the cpu values is consumed. The check is performed before bounding the
    value with array_index_nospec() so that we don't silently accept bogus
    cpu values from userspace, where array_index_nospec() would force these
    values to 0.
    
    I suspect we can remove the array_index_nospec() call entirely, but I've
    conservatively left that in place, updated to use nr_cpu_ids to match
    the prior check.
    
    Tested on arm64 with the Syzkaller reproducer:
    
      https://syzkaller.appspot.com/bug?extid=cd714a07c6de2bc34293
      https://syzkaller.appspot.com/x/repro.syz?x=15d8b397200000
    
    Full splat from before this patch:
    
    WARNING: CPU: 1 PID: 27601 at include/linux/cpumask.h:121 cpu_max_bits_warn include/linux/cpumask.h:121 [inline]
    WARNING: CPU: 1 PID: 27601 at include/linux/cpumask.h:121 cpumask_check include/linux/cpumask.h:128 [inline]
    WARNING: CPU: 1 PID: 27601 at include/linux/cpumask.h:121 cpumask_test_cpu include/linux/cpumask.h:344 [inline]
    WARNING: CPU: 1 PID: 27601 at include/linux/cpumask.h:121 io_sq_offload_start fs/io_uring.c:2244 [inline]
    WARNING: CPU: 1 PID: 27601 at include/linux/cpumask.h:121 io_uring_create fs/io_uring.c:2864 [inline]
    WARNING: CPU: 1 PID: 27601 at include/linux/cpumask.h:121 io_uring_setup+0x1108/0x15a0 fs/io_uring.c:2916
    Kernel panic - not syncing: panic_on_warn set ...
    CPU: 1 PID: 27601 Comm: syz-executor.0 Not tainted 5.1.0-rc7 #3
    Hardware name: linux,dummy-virt (DT)
    Call trace:
     dump_backtrace+0x0/0x2f0 include/linux/compiler.h:193
     show_stack+0x20/0x30 arch/arm64/kernel/traps.c:158
     __dump_stack lib/dump_stack.c:77 [inline]
     dump_stack+0x110/0x190 lib/dump_stack.c:113
     panic+0x384/0x68c kernel/panic.c:214
     __warn+0x2bc/0x2c0 kernel/panic.c:571
     report_bug+0x228/0x2d8 lib/bug.c:186
     bug_handler+0xa0/0x1a0 arch/arm64/kernel/traps.c:956
     call_break_hook arch/arm64/kernel/debug-monitors.c:301 [inline]
     brk_handler+0x1d4/0x388 arch/arm64/kernel/debug-monitors.c:316
     do_debug_exception+0x1a0/0x468 arch/arm64/mm/fault.c:831
     el1_dbg+0x18/0x8c
     cpu_max_bits_warn include/linux/cpumask.h:121 [inline]
     cpumask_check include/linux/cpumask.h:128 [inline]
     cpumask_test_cpu include/linux/cpumask.h:344 [inline]
     io_sq_offload_start fs/io_uring.c:2244 [inline]
     io_uring_create fs/io_uring.c:2864 [inline]
     io_uring_setup+0x1108/0x15a0 fs/io_uring.c:2916
     __do_sys_io_uring_setup fs/io_uring.c:2929 [inline]
     __se_sys_io_uring_setup fs/io_uring.c:2926 [inline]
     __arm64_sys_io_uring_setup+0x50/0x70 fs/io_uring.c:2926
     __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
     invoke_syscall arch/arm64/kernel/syscall.c:47 [inline]
     el0_svc_common.constprop.0+0x148/0x2e0 arch/arm64/kernel/syscall.c:83
     el0_svc_handler+0xdc/0x100 arch/arm64/kernel/syscall.c:129
     el0_svc+0x8/0xc arch/arm64/kernel/entry.S:948
    SMP: stopping secondary CPUs
    Dumping ftrace buffer:
       (ftrace buffer empty)
    Kernel Offset: disabled
    CPU features: 0x002,23000438
    Memory Limit: none
    Rebooting in 1 seconds..
    
    Fixes: 917257da ("io_uring: only test SQPOLL cpu after we've verified it")
    Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
    Cc: Jens Axboe <axboe@kernel.dk>
    Cc: Alexander Viro <viro@zeniv.linux.org.uk>
    Cc: linux-block@vger.kernel.org
    Cc: linux-fsdevel@vger.kernel.org
    Cc: linux-kernel@vger.kernel.org
    
    Simplied the logic
    Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
    975554b0
io_uring.c 72.4 KB