casaroli opened a new pull request, #19565: URL: https://github.com/apache/nuttx/pull/19565
*Note: Please adhere to [Contributing Guidelines](https://github.com/apache/nuttx/blob/master/CONTRIBUTING.md).* ## Summary `arm_fork()` copies the caller's saved system call state to the child so that the child can return through `SYS_syscall_return` the way its parent would. It copies `sysreturn` and `excreturn`, but not `ctrlreturn`. On Cortex-M in a protected build, `arm_svcall.c` treats CONTROL as part of that saved state: it stores the caller's CONTROL in `xcp.syscall[].ctrlreturn` on entry and restores it from there on `SYS_syscall_return`. All three Cortex-M profiles do this — armv6-m, armv7-m and armv8-m each define the field in `arch/arm/include/<arch>/irq.h` and use it symmetrically. The child's TCB comes from `kmm_zalloc()`, so the field is zero, and `CONTROL == 0` is **nPRIV clear — privileged**. The child therefore returns to user space privileged while its parent returns unprivileged, and runs out its life with the MPU restrictions its parent is under silently lifted. That is precisely the isolation `CONFIG_BUILD_PROTECTED` exists to provide. ## Impact A `fork()` child in `CONFIG_BUILD_PROTECTED` on Cortex-M currently executes with kernel privilege. This restores it to the parent's. Nothing faults without the fix, which is why it has survived: `CONTROL == 0` also selects MSP, which sounds like it should crash immediately, but NuttX already runs Cortex-M threads on MSP — the parent's saved value is `0x1`, nPRIV set and SPSEL clear — so the two differ only in the privilege bit and there is no stack change to trip over. Privileged code then passes every test unprivileged code passes, so `ostest` cannot see it either. `CONFIG_BUILD_FLAT` is unaffected: without `CONFIG_LIB_SYSCALL`, `nsyscalls` is 0 and the whole block is skipped. armv7-a and armv7-r are unaffected too; they carry `cpsr` instead, and that is already copied. ## Testing Measured on a Raspberry Pi RP2350 (Cortex-M33) in `BUILD_PROTECTED`, breaking at the `nxtask_start_fork()` call during a fork test: ``` parent xcp.syscall[0].ctrlreturn = 0x00000001 (nPRIV set, unprivileged) child xcp.syscall[0].ctrlreturn = 0x00000000 (nPRIV clear, PRIVILEGED) ``` With this change both read `0x00000001`. Build-tested `mps2-an521:nsh` (armv8-m) on macOS/arm64 with Arm GNU `arm-none-eabi-gcc` 14.2.Rel1. `tools/checkpatch.sh -c -u -m -g` clean. -- 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]
