Home / Security

Security

Memory-safe by language, least-privilege by design, and continuously hardened through systematic adversarial auditing.

Principles

Security is the architecture, not a feature

ONCRIX treats security as a property of the system's shape. A microkernel keeps the privileged core small, the language removes whole bug classes, and every authority is a thing you must explicitly hold — never something you implicitly have.

// minimal TCB

Minimal trusted computing base

The kernel keeps only scheduling, memory management, and IPC. Drivers, filesystems, and services run in user space, so the amount of code that must be trusted absolutely is kept as small as the design allows.

// separation

Privilege separation

Each service runs in its own isolated address space with only the authority it needs to do its job. A compromise in one component does not hand the attacker the whole system.

// capabilities

Capability-based access

Access to a resource requires holding an unforgeable capability for it. There is no ambient authority and no global namespace that any process can reach by default.

// fail closed

Fail-closed defaults

When a check cannot be satisfied or a pointer cannot be validated, the operation is refused. The default answer to an unverified request is "no", not "probably fine".

// layers

Defense in depth

Language-level memory safety, address-space isolation, capability checks, and validated syscall boundaries are independent layers. Defeating one does not defeat the rest.

// least privilege

Least privilege

Components are granted the narrowest authority that lets them function, and nothing more. Privilege is something you are given deliberately, not something you accumulate.

Memory safety by language

Whole bug classes deleted at the source

ONCRIX is written in Rust. The kernel is #![no_std] and #![no_main], and the same ownership and borrowing rules that protect application code protect the kernel itself.

In safe Rust, null-pointer dereferences, use-after-free, double-free, and data races on shared mutable state are not bugs you have to remember to avoid — they do not compile. That removes an entire category of vulnerabilities that has historically dominated kernel CVEs in memory-unsafe languages.

Some kernel work genuinely requires raw hardware access and cannot be expressed in safe Rust. ONCRIX does not scatter unsafe through the codebase. Instead:

  • Unsafe is wrapped. Every unsafe block lives behind a safe abstraction, so the dangerous operation is auditable in one place rather than duplicated across callers.
  • Invariants are documented. Each unsafe block carries a // SAFETY: comment stating exactly which invariant makes the operation sound, so a reviewer can check the claim instead of guessing.
  • No unwrap / expect in production paths. Fallible operations return Result<T, E> and propagate errors with ?, so an unexpected condition is handled deliberately rather than panicking the kernel.

This last point matters because a ring-0 fault is treated as fatal. A kernel cannot safely continue after dereferencing a bad pointer, so the only acceptable strategy is to never reach that state. Every kernel dereference of untrusted input — user-supplied pointers, lengths, and offsets crossing the syscall boundary — is validated before it is used.

crates/syscall — validate before you touch
// Untrusted (ptr, len) arrive from user space across the syscall boundary.
// Validate the whole range first; only then is a read sound.
fn sys_write(fd: Fd, ptr: UserPtr, len: usize) -> Result<usize, Errno> {
    // SAFETY of the later read depends on this check succeeding.
    let region = current_addr_space()
        .validate_user_range(ptr, len)?;   // fail-closed: EFAULT on any miss

    let file = current_caps()
        .resolve(fd)?;                      // capability check, not ambient access

    file.write(region)                      // no unwrap/expect on this path
}

Capability-based access control

Authority you hold, not authority you have

ONCRIX governs access with capabilities: unforgeable handles that name a specific resource together with the rights you are permitted to exercise on it.

A process can only act on resources it has been explicitly handed a capability for. There is no ambient authority — possessing a name or guessing an identifier grants nothing, because the right to act is carried by the handle itself, not by the caller's identity. Capabilities are unforgeable: they are issued and tracked by the kernel and cannot be fabricated by a process, only received, used within their granted rights, or passed on.

This makes least privilege the path of least resistance. A service is started with exactly the capabilities its job requires. To reach anything else it would need a handle it was never given, which is precisely what the model is built to prevent.

request: process holds cap(file, {read})kernel checks the handle → rights include read? → allow request: process holds cap(file, {read}), asks to writekernel checks the handle → right not granted → deny (fail-closed) request: process holds no capability for the resource → nothing to check against → deny

Isolation

A driver bug stays a driver bug

In a monolithic kernel, a flaw in a single device driver runs with full kernel privilege. In ONCRIX, drivers and services live in user space, behind IPC boundaries.

User-space drivers and services do not share the kernel's address space and cannot call into it directly. They communicate with the rest of the system only by passing messages through the IPC layer, and they can only act on resources for which they hold capabilities. The kernel validates what crosses the boundary; the boundary itself is enforced by hardware-backed address-space separation.

The consequence is containment. A bug — or a compromise — in a user-space driver cannot take down the kernel and cannot reach memory or resources it was never granted. A faulty driver fails inside its own isolated component, where it can be confined, restarted, or replaced, instead of corrupting the privileged core.

hardware interrupt → HALkernel: minimal handler → message via IPC → user-space driver → driver acts only within its granted capabilities if the driver misbehaves: fault is contained in its address space, the kernel core keeps running

Continuous adversarial auditing

Hardening is a process, not a milestone

Language safety removes many bugs, but not logic flaws. ONCRIX is repeatedly read with an attacker's mindset to find them.

The codebase is audited not for one bug at a time but for whole classes of security defects. When a finding is confirmed, it is fixed, and the fix is then independently re-verified rather than assumed correct. Every change must pass the CI gate before it lands: a Rust quality job (formatting, a zero-warning cargo clippy --workspace -- -D warnings policy, and a workspace build) and a QEMU boot integration test that confirms the kernel still boots to userspace.

The bug classes that are systematically hunted include:

Bug classWhat is looked for
Unvalidated input → out-of-bounds access User, disk, network, or device data used as a pointer, length, or index without first validating that the access stays in bounds.
Missing or inverted permission checks Permission and capability checks that are absent, reachable on a path that skips them, or wired up with the comparison reversed.
Integer overflow in size/offset math Arithmetic on sizes, counts, and offsets that can wrap and turn a bounds check into a lie — especially before allocation or copy operations.
Weak or placeholder cryptography Cryptographic primitives that are stubbed, weak, or stand-in placeholders being trusted as if they were production-grade.
Trusting attacker-supplied identity Authorization decisions that believe an identifier, name, or token supplied by the caller instead of an authority the kernel itself can vouch for.

Security here is an ongoing process, not a checkbox. No audit pass "completes" security. New code introduces new surface, and each round of hardening is followed by another. ONCRIX treats adversarial review, fixing, and independent re-verification as a permanent part of development — gated by CI — rather than a one-time certification.

Reporting

Found something? Tell us.

Responsible disclosure makes ONCRIX safer for everyone. If you believe you have found a security issue, please reach out through the project's GitHub repository.

Security reports and disclosures are handled through the ONCRIX GitHub repository — via its issues and security channels. Please include enough detail to reproduce the problem, and give maintainers a reasonable opportunity to investigate and ship a fix before any public disclosure. The source, the design docs, and the full history are open, so reports can be discussed and verified in the open as well.