oxinit is pre-alpha. There is no release, no user base, and no formal security process. There is no advisory pipeline, no CVE workflow, no embargo policy, and no committed response time.
This document exists so that the threat model is written down before the code is, and so there is an address to send a report to.
Do not run oxinit on a machine you care about.
PID 1 has a position no other process on the machine has:
- It runs as root, and it is the only process that cannot be restarted by something above it. If it exits, the kernel panics.
- It is the parent of every process on the machine, directly or by reparenting.
- It owns the cgroup hierarchy under
/sys/fs/cgroup/oxinit.slice/, which is what enforces every service's resource limits and what makescgroup.killwork. - It holds the listening file descriptors for socket activation before any service exists to receive them.
- It decides the order in which the system shuts down, including whether filesystems are unmounted cleanly.
Code execution in PID 1 is code execution as root with no supervisor. A crash in PID 1 is a kernel panic — availability loss for the whole machine, not one service. Both outcomes are total.
The design decisions that follow from this — no panicking constructs, unwinding
rather than aborting, catch_unwind at handler boundaries, quarantined
unsafe, no async runtime, minimal dependency tree — are described in
ARCHITECTURE.md. They are security properties, not style.
Three interfaces process input that oxinit did not produce.
oxinit-unit parses TOML from /etc/oxinit/units/ and
/usr/lib/oxinit/units/. Under a correct installation both directories are
root-owned and mode 0755, so their contents are trusted input.
They are not always correct. If either directory, or any path component leading
to it, is writable by a non-root user, unit files become attacker-controlled
input to a parser running as PID 1. Unit files also specify user, exec, and
resource limits, so write access to them is equivalent to root regardless of any
parser bug.
The parser is written to reject rather than guess: unknown keys and sections are errors, values of the wrong type are errors, and a load error means oxinit does not start rather than starting with a partially applied configuration. It is still the largest piece of untrusted-input handling in the project.
Relevant to a report: parser crashes, unbounded allocation from a crafted file, integer overflow in the duration or size parsers, path traversal via a unit name.
SOCK_SEQPACKET at /run/oxinit/control.sock, mode 0600, root-owned, in a
root-owned directory. Authorization is entirely the socket's permissions. There
is no in-protocol authentication and no per-command permission model.
Access to this socket is full control of the machine: it can start and stop
arbitrary units. This is intended — the socket is not meant to be reachable by
anything but root — but it means a permissions mistake on /run/oxinit/ is a
complete compromise, with no second layer behind it.
Relevant to a report: any path by which a non-root process can reach the socket, and any message that causes PID 1 to crash, hang, or consume unbounded memory.
SOCK_DGRAM at /run/oxinit/notify. Services with type = "notify" send
READY=1, STATUS=, and WATCHDOG=1 datagrams here.
Unlike the control socket, this one is reachable by every service, including
services running as unprivileged users — that is what it is for. The datagram
payload is unauthenticated by construction, so oxinit sets SO_PASSCRED on the
socket, reads with recvmsg, and takes the sender's identity from the
kernel-attached SCM_CREDENTIALS ancillary message rather than from anything in
the payload. Datagrams with no credentials attached, or whose pid is not in a
known service cgroup, are dropped.
That check is the whole boundary. If it can be bypassed, a service can mark another service ready, keep a hung service's watchdog alive, or write arbitrary text into another unit's status field.
SCM_CREDENTIALS gives a pid the sender cannot forge, but a pid is not a
durable identity: the sending process can exit and its pid be reused before
oxinit resolves it to a cgroup. That window is the known weak point.
Relevant to a report: any way to attribute a datagram to a cgroup that did not
send it, including pid reuse races; crashes from a malformed datagram;
unbounded STATUS= strings.
- Anything requiring root access to begin with. Root can replace the binary.
- Denial of service by a service exhausting its own configured limits.
- Configuration mistakes: a
0666control socket directory, a world-writable/etc/oxinit/units/, a unit that runs an untrusted binary as root.
Email youri@youhide.com.br with a description, affected component, and reproduction steps if you have them.
Do not open a public issue for a security report.
Expect a slow response. This is a pre-alpha project with no security team. You will get an acknowledgement and an honest answer about whether and when it will be fixed. There is no bounty.
Since there is no release and no user base, the current default is to fix in public with a normal commit and an explanatory message. If that is wrong for something you have found, say so in your report.