MMotor OS
System

Processes and roles

Motor OS has no users, no groups, and no root account. A process's authority is a capability word fixed at creation, and three roles derived from that word decide what it may do with files.

Capabilities

Every process carries an immutable 64-bit capability word, set when the process is created and readable by the process itself without a syscall (it is in a read-only page the kernel maps into every process). Ten bits are defined: system authority, device access, spawning, logging, shutdown, detached spawning, the user's authority, vsock, the network, and filesystem writes. The kernel decides what a parent may grant a child, and a capability can never be gained after creation, so a process cannot escalate. Capabilities describes every bit, the grant rules, network and filesystem-write access, and how rush and rmux use them.

The three roles

A role is derived from the capability word: CAP_SYS means System; otherwise CAP_INTERACTIVE means Interactive; otherwise the role is None. The roles are ordered, System above Interactive above None, and they are the only identity the filesystem knows about: every file and directory stores one permission byte per role.

RoleMeaningTypical holders
SystemThe OS itself; owns installed content and system logs.sys-io, sys-init, strobe
InteractiveThe logged-in user's authority: may read and run installed programs, and owns /user.sys-tty, russhd, console and SSH shells, the commands they run, user daemons
NoneLeast privilege: public read and execute, writes only to shared scratch directories.dns-resolver, other services, deliberately sandboxed children

A server that wants to know who it is talking to asks the kernel for the capabilities of the process at the other end of a connection; the answer comes from the kernel, not from the client, so it cannot be forged. sys-io does this once per filesystem connection and uses the result for every permission check on that connection. If the query fails, the connection is dropped rather than given a default role. Servers that clients find by name check each other the same way; see Named IPC services.

Spawning

There is no fork and no exec. std::process::Command works, and behind it the runtime in the parent builds the child directly: it creates an address space, loads the ELF executable into it, maps the runtime, writes the arguments and environment, sets up stdio, creates the process object with the chosen capabilities, and wakes the main thread. The program file's execute permission for the parent's role is checked before loading; a script needs both the script and its interpreter to be executable. A failed spawn says why: PermissionDenied for a program the parent's role cannot execute, InvalidInput for a file that is not a loadable executable, and OutOfMemory when the kernel refuses memory for the program's segments.

The child's capabilities come from an environment key that the parent's runtime consumes at spawn time and the child never sees:

Without MOTOR_OS_CAPS the default depends on the parent's role. An Interactive parent gets an Interactive child (a shell and the commands it runs), without CAP_LOG. A System parent gets a None child by default: a system service must say explicitly when it is creating a user session, so that a logged-in session cannot appear by accident. A None parent gets a None child. In every case the default is intersected with what the parent holds, and CAP_SPAWN is included so that children can have children. CAP_VSOCK, CAP_NET, and CAP_FS_WRITE follow whenever the parent holds them, so a restriction applies to all descendants. The full rules are under Capabilities.

How a session gets its role

The chain is explicit at every step. sys-init starts sys-tty and russhd with a mask that includes CAP_INTERACTIVE; sys-tty starts the console shell with the same role it has itself; russhd gives each authenticated session shell the Interactive bit; and from there the default rule carries Interactive down to every command. The shipped sys-init.cfg gives russhd the mask 1020 (CAP_SPAWN | CAP_LOG | CAP_SHUTDOWN | CAP_SPAWN_DETACHED | CAP_INTERACTIVE | CAP_VSOCK | CAP_NET | CAP_FS_WRITE) and the DNS resolver the mask 264 (CAP_LOG | CAP_NET). A test image variant runs the serial console as System instead, using tty:system: in the configuration.

russhd itself runs as Interactive, including its pre-authentication code and its in-process SFTP implementation. This is an explicit interim choice: a non-System parent cannot pass on a capability it does not hold, and SFTP needs filesystem authority. The authentication boundary protects that authority; a future change may keep the network front end at None and hand each authenticated session to an Interactive worker.

What roles mean day to day

The permission bits themselves, and the policy that assigns them when an image is built, are described under Filesystem. The design documents are docs/process-roles.md and src/sys/lib/motor-fs/PERMISSIONS_DESIGN.md in the repository.

Threads, killing, and exit

Threads are kernel objects created with a syscall; the runtime implements std::thread, thread-local storage, and futex-based synchronization on top. A parent can kill its child (Child::kill) and wait for it; there is no signal to catch, so a killed process simply stops. Ctrl+C from a terminal terminates a process with status 130 unless it registered a handler; see Terminals. Exit codes are reported to the parent as on other systems, and rush treats 130 as an interrupt.