Skip to content

arch/risc-v: fix fault handler misattributing kernel faults to user t…#19471

Open
hitHuang wants to merge 1 commit into
apache:masterfrom
hitHuang:fix/riscv_fault_handler
Open

arch/risc-v: fix fault handler misattributing kernel faults to user t…#19471
hitHuang wants to merge 1 commit into
apache:masterfrom
hitHuang:fix/riscv_fault_handler

Conversation

@hitHuang

Copy link
Copy Markdown
Contributor

Summary

If a fault happens inside an interrupt handler, this_task() returns whatever user task happened to be interrupted, not the code that actually faulted. riscv_fault_handler() didn't distinguish these cases, so it killed that unrelated user task with SIGSEGV instead of panicking, hiding the real kernel bug.

The fix checks the trap frame's previous privilege level (STATUS_PPP): only a fault that actually came from user mode gets the SIGSEGV-and-kill treatment. Anything trapping from kernel mode (interrupt handlers, syscall bodies, kernel threads) now panics.

Impact

Only CONFIG_BUILD_KERNEL is affected. Genuine user-mode faults still get killed with SIGSEGV as before. Faults from kernel-mode code (interrupt handlers, syscall bodies, kernel threads) now panic instead of killing whichever user task happened to be interrupted, so kernel bugs are no longer masked as application bugs.

Dependency

Depends on #19468. This fix reads STATUS_PPP from the current trap frame, which is only trustworthy if a nested trap hasn't clobbered it — the exact bug #19468 fixes on qemu-rv.

Testing

Config: CONFIG_BUILD_KERNEL=y.

Boards: qemu rv-virt:knsh (RV32) and rv-virt:knsh64 (RV64).

For CONFIG_BUILD_KERNEL, when an interrupt arrives it may interrupt a task running in user mode. If that interrupt handler itself then triggers an unrecoverable exception (e.g. a NULL pointer access causing a crash), the kernel should panic — but the existing implementation only killed the interrupted application instead.

To reliably construct a scenario where an interrupt lands exactly while an app is executing in user mode, a modified hello app was used:

int main(int argc, FAR char *argv[])
{
  printf("Hello, World!!\n");
  while (1);
  return 0;
}

An unrecoverable exception (NULL pointer access) was then deliberately introduced in the tick interrupt handler.

Before fix:

ABC

NuttShell (NSH) NuttX-13.0.0
nsh> hello &
hello [0:100]
nsh> Hello, World!!

nsh> ps
  TID   PID  PPID PRI POLICY   TYPE    NPX STATE    EVENT     SIGMASK            STACK COMMAND
    0     0     0   0 FIFO     Kthread   - Ready              0000000000000000 0003040 Idle_Task
    1     0     0 100 RR       Kthread   - Waiting  Semaphore 0000000000000000 0001968 lpwork 0x80600010 0x80600060
    3     3     0 100 RR       Task      - Running            0000000000000000 0003008 /system/bin/init
    4     4     3 100 RR       Task      - Ready              0000000000000000 0002000 hello
nsh> [   11.510000] riscv_exception: EXCEPTION: Store/AMO access fault. MCAUSE: 00000007, EPC: 8020cc8e, MTVAL: 00000000
[   11.510000] riscv_fault_handler: Segmentation fault in hello (PID 4: hello)

This shows that in this case, only the running application was killed.

After fix:

ABC

NuttShell (NSH) NuttX-13.0.0
nsh> hello &
hello [0:100]
nsh> Hello, World!!

nsh> ps
  TID   PID  PPID PRI POLICY   TYPE    NPX STATE    EVENT     SIGMASK            STACK COMMAND
    0     0     0   0 FIFO     Kthread   - Ready              0000000000000000 0003040 Idle_Task
    1     0     0 100 RR       Kthread   - Waiting  Semaphore 0000000000000000 0001968 lpwork 0x80600010 0x80600060
    3     3     0 100 RR       Task      - Running            0000000000000000 0003008 /system/bin/init
    4     4     3 100 RR       Task      - Ready              0000000000000000 0002000 hello
nsh> [1885490642944000.001000] riscv_exception: EXCEPTION: Store/AMO access fault. MCAUSE: 00000007, EPC: 8020cc52, MTVAL: 00000000
[1885490642944000.001000] riscv_fault_handler: PANIC!!! Exception = 00000007
[1885490642944000.001000] dump_assert_info: Current Version: NuttX  13.0.0 12149a3174-dirty Jul 18 2026 20:38:24 risc-v
[1885490642944000.001000] dump_assert_info: Assertion failed panic: at file: common/riscv_exception.c:150 task: hello process: hello 0xc0000716
[1885490642944000.001000] up_dump_register: EPC: 8020cc52
[1885490642944000.001000] up_dump_register: A0: 00000015 A1: 80610a74 A2: 80600138 A3: 80000005
[1885490642944000.001000] up_dump_register: A4: 00000001 A5: 00000001 A6: 00000000 A7: 00000000
···
···
[1885490642944000.001000] stack_dump: 0xc08027f0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[1885490642944000.001000] sched_dumpstack: backtrace| 4: 0x80218e28 0x8021c972 0x802172bc 0x8020c86a 0x80201fec 0x8020162a 0x80201262 0x802001e8
[1885490642944000.001000] sched_dumpstack: backtrace| 4: 0x8020cc52 0x8020162a 0x80201262 0x802001e8 0xc0000742 0xc000072e 0x8020cc52 0x8020162a
[1885490642944000.001000] sched_dumpstack: backtrace| 4: 0x80201262 0x802001e8 0xc0000742 0xc000072e
[1885490642944000.001000] dump_tasks:    PID GROUP PRI POLICY   TYPE    NPX STATE   EVENT      SIGMASK          STACKBASE  STACKSIZE   COMMAND
[1885490642944000.001000] dump_tasks:   ----   --- --- -------- ------- --- ------- ---------- ---------------- 0x80606000      2048   irq
[1885490642944000.001000] dump_task:       0     0   0 FIFO     Kthread -   Ready              0000000000000000 0x80607b60      3040   Idle_Task
[1885490642944000.001000] dump_task:       1     0 100 RR       Kthread -   Waiting Semaphore  0000000000000000 0x8060a050      1968   lpwork 0x80600010 0x80600060
[1885490642944000.001000] dump_task:       3     3 100 RR       Task    -   Waiting Semaphore  0000000000000000 0xc0802040      3008   /system/bin/init
[1885490642944000.001000] dump_task:       4     4 100 RR       Task    -   Running            0000000000000000 0xc0802030      2000   hello
[1885490642944000.001000] sched_dumpstack: backtrace| 0: 0x8020cf84 0x80608730 0x802011d6 0x8020004a
[1885490642944000.001000] sched_dumpstack: backtrace| 1: 0x8020cb06 0x80218fdc 0x80208cfc 0x80208d20 0x8020312c 0x80202a94
[1885490642944000.001000] sched_dumpstack: backtrace| 3: 0xc000c348 0xc00027ca 0xc0003ff0 0xc000288a 0xc000264e 0xc0002542 0xc0000b4a 0xc0000b08
[1885490642944000.001000] sched_dumpstack: backtrace| 4: 0x80218e28 0x8021c972 0x80216e66 0x802187ec 0x8021731c 0x8020c86a 0x80201fec 0x8020162a
[1885490642944000.001000] sched_dumpstack: backtrace| 4: 0x80201262 0x802001e8 0x8020cc52 0x8020162a 0x80201262 0x802001e8 0xc0000742 0xc000072e
[1885490642944000.001000] sched_dumpstack: backtrace| 4: 0x8020cc52 0x8020162a 0x80201262 0x802001e8 0xc0000742 0xc000072e

After the fix, the kernel correctly panics with a full backtrace instead of silently killing hello.

…asks

riscv_fault_handler() only checked the task type and SYSCALL flag, so a
fault taken inside an interrupt handler (running in kernel mode) was
blamed on the user task that happened to be interrupted and killed with
SIGSEGV, hiding the real kernel bug.  Use the STATUS_PPP bit of the trap
frame to tell whether the fault originated from user mode: only then is
it safe to kill the task.

Signed-off-by: liang.huang <liang.huang@houmo.ai>
@hitHuang
hitHuang requested review from tmedicci and yf13 as code owners July 18, 2026 13:21
@github-actions github-actions Bot added Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Size: S The size of the change in this PR is small labels Jul 18, 2026
@github-actions

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants