Skip to main content

Crate subc_os

Crate subc_os 

Source
Expand description

Operating-system primitives the subc daemon needs and cannot reach without unsafe code, each behind a small safe API.

The daemon crates forbid unsafe code. This crate is the one deliberate exception (like subc-uptime and subc-cgroup): every unsafe block here is a single foreign call with its preconditions stated beside it, and nothing unsafe is exported.

Today it answers one question: is the process now holding pid N the same process the daemon spawned earlier? A pid alone cannot say, because the kernel reuses pids once a process has been reaped. Process reads the two facts that tell processes apart, the kernel’s start time for the pid and the file identity (device and inode) of the executable image it runs, and sends signals to it.

Sources, per platform:

  • Linux: the start time is field 22 of /proc/<pid>/stat (clock ticks since boot), and the executable is stat through /proc/<pid>/exe, which resolves to the running image even if its file has since been replaced or deleted. A pidfd is opened before either is read and signals go through it (pidfd_send_signal), so the process that was checked is the process that is signalled. No unsafe code is needed: rustix wraps both calls.
  • macOS: the start time is kp_proc.p_starttime from sysctl KERN_PROC_PID (microseconds since the epoch), and the executable is the path proc_pidpath reports, then stat on that path. These two calls are unsafe. macOS has no pidfd, so a signal is a plain kill sent right after the checks; see Process::signal.
  • Anywhere else: Process::open reports std::io::ErrorKind::Unsupported.

For persisted PID owners, process_identity reads versioned kernel start identities and distinguishes alive, dead and unknown without spawning a process. Its foreign calls are signal-zero kill on Unix and proc_pidinfo on macOS. Only dead owners may be reclaimed; unknown owners stay protected.

It also reads how much memory and CPU time one process is using, for reporting only; see resource_usage. On Linux that is procfs again; on macOS it is proc_pid_rusage, plus mach_timebase_info to convert its CPU times to nanoseconds, the other two unsafe calls in the crate.

And it carries the launch nonce from the daemon to each module it spawns over an inherited pipe instead of the environment: [launch_nonce] is the one reader every module uses, and LaunchNonceHandoff the daemon’s half. That module’s unsafe code is dup2, fcntl, fstat and ioctl on descriptors, each with its preconditions stated beside it.

Re-exports§

pub use launch_nonce::LaunchNonceHandoff;
pub use launch_nonce::launch_nonce;
pub use launch_nonce::LaunchNonce;
pub use launch_nonce::LaunchNonceError;
pub use launch_nonce::LaunchNonceSource;
pub use launch_nonce::LAUNCH_NONCE_ENV;
pub use launch_nonce::LAUNCH_NONCE_FD;
pub use launch_nonce::LAUNCH_NONCE_FD_ENV;

Modules§

launch_nonce
The launch nonce: the secret the daemon gives each module it spawns, which the module presents to be admitted as itself.
privacy_identity
macOS responsibility isolation at exec. macOS charges privacy permissions (Screen Recording, Accessibility, Files and Folders) to a process’s “responsible process”, which is normally the program that launched it, so a supervised module would otherwise borrow the daemon’s grants. The daemon therefore launches each module through a trampoline: ck-subc re-executed with a hidden first argument. The trampoline calls posix_spawnp with POSIX_SPAWN_SETEXEC, a Darwin flag that replaces the calling process’s image in place (like execve) instead of creating a child, after marking the spawn as disclaiming responsibility. The module keeps the trampoline’s pid, process group, pipes and fd-3 launch-nonce descriptor, and becomes its own responsible process.
process_identity
PID-reuse-safe liveness checks using versioned kernel start-time identities.

Structs§

FileIdentity
Device and inode of a file: which file, independent of the name used to reach it.
Observation
What a live process looks like right now.
Process
A handle on the process holding one pid at the moment it was opened.
ResourceUsage
One reading of a process’s memory and cumulative CPU time.

Enums§

MemoryKind
What ResourceUsage::memory_bytes measures. The platforms offer different figures, and they are not interchangeable.
Signal
A signal Process::signal can send.

Constants§

PROCESS_IDENTITY_SUPPORTED
True where Process can identify and signal a process by pid.
RESOURCE_USAGE_SUPPORTED
True where resource_usage can read a live process. Elsewhere it always answers None, and a caller can use this to say “not supported here” rather than “could not read”.

Functions§

file_identity
The device and inode of the file at path, following symlinks. None if it cannot be read or the platform has no inode numbers.
resource_usage
Memory and cumulative CPU time of the process holding pid, read now.
start_time
The kernel start time of the process holding pid, or None if there is none, it has already exited (a zombie waiting to be reaped counts as exited), or the platform has no source.