Apache NuttX is a mature, real-time embedded operating system (RTOS) https://nuttx.apache.org/
Find a file
Marco Casaroli a652708efa arch/x86_64: Kill only the offending task on a user-space fault.
An unprivileged task that touched memory it does not own took the whole
system down.  The MMU refused the access, as it should, and then
x86_64_fault_panic_isr() panicked -- so a contained application bug
became a system-wide outage.  x86_64 had no user-fault recovery at all,
while arm64, RISC-V and esp32s3 each have one, and ISR13 and ISR14 here
went straight to a handler whose own comment says "Don't even brother
to recover, just dump the regs and PANIC."

The decision has to be made in the handler.  The user-task check in
_assert() looks like it already covers this, but a fault arrives as an
exception, so up_interrupt_context() is already true by the time it is
reached and the panic branch is taken no matter who faulted.

The CPL in the saved CS is the whole test, and on this architecture it
is exact:  everything that runs on behalf of a user task inside the
kernel -- a system call body, an interrupt handler, a kernel thread --
runs in ring 0, so a fault there is correctly refused recovery.  That is
what RISC-V reads out of STATUS_PPP and arm64 out of SPSR_MODE_EL0T.
x86_64 cannot use TCB_FLAG_SYSCALL the way those two do: it has never
set it, and making it do so is a separate change with its own hazards
(see the note in x86_64_syscall()).  The task type is checked as well,
as RISC-V does, so that a frame that cannot be trusted -- an early-boot
fault, before any user task exists -- cannot talk its way in with a
stale selector.

Recovery is the same shape as the other architectures -- RIP to _exit,
first argument SIGSEGV, TCB_FLAG_FORCED_CANCEL raised -- plus the three
x86_64 specifics:

  * CS and SS move to the kernel selectors together with RIP.  The frame
    being rewritten is the one x86_64_fullcontextrestore() is about to
    iretq from, and iretq takes the target privilege level from the CS
    it pops; in long mode it pops SS with it even when the level does
    not change.
  * RSP moves to the top of the task's own kernel stack.  _exit() must
    not run on the user stack the fault came from, because the address
    environment that stack belongs to is torn down while _exit() is
    still running.  The kernel stack is free -- the fault was taken in
    user mode, so no system call of this task is in flight.  The -8
    reproduces the offset a call would have left, which is what the SysV
    ABI states its 16-byte rule against and what up_initial_state() sets
    up for the same reason.
  * RFLAGS is reset to the value up_initial_state() gives a new thread
    rather than carried over.  The faulting task's flags are its own to
    set, and DF in particular must be clear on entry to any C function.

ISR6 is routed through the same handler.  An invalid opcode is
attributable to the instruction that raised it, so a user task running
garbage should die on its own rather than take the system with it --
the same conclusion esp32s3 reached for EXCCAUSE_ILLEGAL.  ISR8 keeps
panicking unconditionally: a double fault says an exception could not be
delivered at all, and there is nothing left to trust.

The message gives the fault address (CR2) only for a page fault, because
the other exceptions do not set CR2.

X86_GDT_PL_MASK and X86_GDT_RPL_USER now live in intel64/arch.h beside
the selectors they mask; x86_64_fork.c had a private copy of the latter.

Verified on qemu-intel64:knsh_romfs under QEMU TCG with
apps/examples/sandbox.  The probe targets kernel .text at _stext
(0x100909000).  This config sets CONFIG_RAM_START to 0x0, a Kconfig
default, so the address is given on the command line.  The "x" probes
call the address; that mode was added to the sandbox locally for the
test.

  sandbox r 0x100909000         -> Exception 14, error code 5, 2816
  sandbox w 0x100909000         -> Exception 14, error code 7, 2816
  sandbox x 0x100909000         -> Exception 14 at RIP=100909000, 2816
  sandbox r 0x8000000000000000  -> Exception 13 (non-canonical), 2816
  sandbox x 0x80000000d         -> Exception 6 at RIP=80000000d, 2816

All five probes run in one boot and report CONTAINED.  The offender
dies with SIGSEGV, the parent survives, a canary thread keeps running,
and the memory and descriptors of the offender come back.  The shell
answers after the last probe.  Without this change each probe panics
the system.

ostest exits with status 0 on knsh_romfs, fork and vfork included.  It
also exits with status 0 on the flat qemu-intel64:nsh with
CONFIG_SCHED_THREAD_LOCAL disabled.  With it enabled, ostest faults in
sched_thread_local_test() with and without this change.

Each vector is reached deliberately.  A non-canonical address is a #GP
rather than a #PF, which the read and call probes never produce on their
own.  The #UD needs no corrupt binary either:  the crt0 stub this
architecture links into every user ELF already ends in a ud2 at
_stext+0xd, and with CONFIG_ARCH_TEXT_VBASE at 0x800000000 the call
probe can simply be aimed at it, executing an invalid opcode in ring 3
out of the process's own text.

The negative direction was checked too, on the flat build, where the
same non-canonical read is taken at CPL 0: it reaches
x86_64_fault_panic_isr() exactly as before and panics with a full
register dump reporting CPL 0.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-10-08 15:51:41 -03:00
.github build(deps): bump docker/setup-buildx-action from 4.3.0 to 4.4.1 2026-09-21 16:28:50 +08:00
arch arch/x86_64: Kill only the offending task on a user-space fault. 2026-10-08 15:51:41 -03:00
audio audio: limit the buffer count guard to shared ring requests 2026-08-05 07:58:53 +02:00
binfmt binfmt: Update the TLS pid when exec() swaps the pids. 2026-10-07 21:55:25 +08:00
boards arch/arm/rtl8730e: add I2C master driver support 2026-10-08 15:49:34 -03:00
cmake cmake/nuttx_add_romfs.cmake: Improved process_all_directory_romfs function 2026-10-05 18:42:56 +08:00
crypto crypto: fix chacha constants under GCC 15. 2026-09-20 08:22:11 -03:00
Documentation Documentation: Describe the per-object wait lists of the scheduler. 2026-10-08 15:50:03 -03:00
drivers drivers/net/telnet: Send a bare carriage return as CR NUL. 2026-10-08 13:29:50 +08:00
dummy
fs fs/inode: Name the inode tree lock in the comments, not g_inode_sem. 2026-10-08 15:50:03 -03:00
graphics graphics/nxterm: consume SGR escape sequences 2026-08-23 10:46:02 +08:00
include arch/mips/pic32mz: add PHY ioctls and link interrupts to the Ethernet driver. 2026-10-08 09:53:45 -03:00
libs libs/libc: Generate the system symbol tables in the CMake build. 2026-10-08 14:24:56 -03:00
mm mm/iob: fix CONFIG_NET_TIMESTAMPING typo in iob_alloc 2026-09-19 16:36:47 -03:00
net net/netdev: add NETDEV_TX_STAMP and handle SIOCETHTOOL ETHTOOL_GET_TS_INFO 2026-09-28 12:53:24 -03:00
openamp cmake: Use NUTTX(_DIR/_BIN_DIR) instead CMAKE(_SRC_DIR/_BIN_DIR) 2026-08-09 11:13:08 -03:00
pass1 tools: fix stale archive members surviving a Kconfig-driven CSRCS change 2026-07-28 21:26:03 -03:00
sched sched: Remove the names of task lists that no longer exist from comments. 2026-10-08 15:50:03 -03:00
syscall fs: add chroot() syscall 2026-09-20 22:27:38 +08:00
tools tools/nxflat: Leave ARM unwind tables out of an NXFLAT module. 2026-09-28 16:45:09 -03:00
video video/videomode: Fix EDID parsing and formatting of video mode dumps 2026-08-29 11:09:11 -03:00
wireless wireless/bluetooth: Validate Number Of Completed Packets event. 2026-09-25 10:35:51 +02:00
.asf.yaml github: master branch protection tune. 2025-05-07 18:37:13 -05:00
.codespell-ignore-lines arch/arm/ra8m1: Add GPT timer support 2026-10-01 23:12:10 +08:00
.codespellrc zbus: Add linker support and documentation for the zbus port 2026-09-21 08:40:14 -03:00
.editorconfig .editorconfig: fix character encoding property specification 2025-11-28 19:12:13 +08:00
.gitignore boards/risc-v/eic7700x: Adopt the common board layout. 2026-08-19 01:40:57 +08:00
.gitmessage docs/contributing: Add a commit message template 2025-06-03 17:33:24 +08:00
.mcp.json arch/risc-v/eic7700x: Describe and configure the pads. 2026-09-28 16:19:01 +08:00
.pre-commit-config.yaml
.yamllint
AUTHORS AUTHORS: add Jorge Guzman 2026-08-25 08:43:13 -04:00
CMakeLists.txt cmake: reconfigure when .config changes 2026-09-14 18:40:45 -03:00
CONTRIBUTING.md contributing: Add requirement for 'Assisted-by' commit field 2026-07-12 09:42:28 +08:00
INVIOLABLES.md
Kconfig arm/nrf54l: add Bluetooth SoftDevice Controller support 2026-10-02 15:37:12 -03:00
LICENSE libs/libdsp: Add Matrix operations 2026-07-11 14:55:59 -03:00
Makefile !boards: enforce secure ROMFS passwd and TEA key setup 2026-07-09 22:41:11 +08:00
NOTICE
README.md ci/testing: Add MemBrowse Integration 2026-06-18 12:07:41 -03:00
ReleaseNotes

POSIX Badge License Issues Tracking Badge Contributors GitHub Build Badge Documentation Badge MemBrowse

Apache NuttX is a real-time operating system (RTOS) with an emphasis on standards compliance and small footprint. Scalable from 8-bit to 64-bit microcontroller environments, the primary governing standards in NuttX are POSIX and ANSI standards. Additional standard APIs from Unix and other common RTOSs (such as VxWorks) are adopted for functionality not available under these standards, or for functionality that is not appropriate for deeply-embedded environments (such as fork()).

For brevity, many parts of the documentation will refer to Apache NuttX as simply NuttX.

Getting Started

First time on NuttX? Read the Getting Started guide! If you don't have a board available, NuttX has its own simulator that you can run on terminal.

Documentation

You can find the current NuttX documentation on the Documentation Page.

Alternatively, you can build the documentation yourself by following the Documentation Build Instructions.

The old NuttX documentation is still available in the Apache wiki.

Supported Boards

NuttX supports a wide variety of platforms. See the full list on the Supported Platforms page.

Contributing

If you wish to contribute to the NuttX project, read the Contributing guidelines for information on Git usage, coding standard, workflow and the NuttX principles.

License

The code in this repository is under either the Apache 2 license, or a license compatible with the Apache 2 license. See the License Page for more information.