royzah opened a new pull request, #20539:
URL: https://github.com/apache/nuttx/pull/20539

   ## Summary
   
   On ARMv6-M, ARMv7-M and ARMv8-M a signal action can be redirected twice, and 
the second redirect hard faults the thread.
   
   A signal that arrives while a thread is in a syscall is queued, and 
`SYS_syscall_return` dispatches it: `up_schedule_sigaction()` pends PendSV for 
the running thread. The same SVC can switch to another thread first 
(`sched_unlock()` in `nxsig_unmask_pendingsignal()`). PendSV then checks 
`sigdeliver` on the thread that is now running, not the target, so the redirect 
is lost, the target returns to user space without running its handler, and 
`sigdeliver` stays set. A later PendSV that lands on the target while it is 
already in `arm_sigdeliver()` redirects it again: `saved_regs` is overwritten, 
the inner delivery clears `sigdeliver`, and the outer one calls it as NULL and 
branches to address 0.
   
   This change:
   
   - checks `sigdeliver` in `arm_doirq()` on the thread being switched in, 
after the scheduler has picked it, instead of only on the thread PendSV 
interrupted
   - returns early from `up_schedule_sigaction()` while a redirect is active 
(`saved_regs != NULL`)
   - clears `saved_regs` in `arm_sigdeliver()` once the context is restored
   
   ## Impact
   
   Fixes a hard fault in signal delivery on ARMv6-M, ARMv7-M and ARMv8-M. Seen 
in a protected build under load; flat builds take the same `arm_doirq()` path. 
No API or configuration change.
   
   ## Testing
   
   Host: Ubuntu 24.04 x86_64, `ghcr.io/apache/nuttx/apache-nuttx-ci-linux`, 
`arm-none-eabi-gcc` 13.2.1, QEMU 6.2.0. Full logs: 
https://gist.github.com/royzah/2b82f04715cf2ce003a9bd64b71365ae
   
   **Hardware, Holybro Pixhawk 6X-RT (i.MX RT1176, ARMv7-M), protected build 
under load.** Downstream tree based on 12.11 carrying the same change.
   
   - before: in `sighand_test` the waiter's `sem_wait()` returns `EINTR` and it 
continues without running the handler, then the board hard faults with PC 0, LR 
in `arm_sigdeliver()` (`rt1176-before-*.log`)
   - after: full `ostest`, `Exiting with status 0` (`rt1176-after-ostest.log`)
   
   **QEMU** (does not reproduce the race: it needs a switch at syscall return 
under interrupt load, so these show no regression):
   
   | Config | master | this PR |
   | --- | --- | --- |
   | `mps2-an500:knsh` (ARMv7-M, protected) | `sighand`, `signest` (3720 
signals) pass, `Exiting with status 0` | same |
   | `mps2-an500:nsh` (ARMv7-M, flat) | `sighand`, `signest` pass; 
`perf_gettime.c:132` asserts later | same |
   | `mps3-an547:knsh` (ARMv8-M, protected) | stops in `vfork_test`, before the 
signal tests | same |
   
   The `perf_gettime` assertion and the `vfork_test` stop are on master too. 
ARMv6-M: `nucleo-l073rz:nsh` builds; there is no protected QEMU target to run 
it on. `tools/checkpatch.sh -u -m -g` and codespell pass.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to