#syscalls #policy #security #sandbox #linux #api-bindings #enums

bin+lib restrict

A DX-focused crate that lets you allow or deny Linux syscalls using an ergonomic, auto-generated enum tailored to your system architecture

3 releases

new 0.1.2 May 2, 2025
0.1.1 May 2, 2025
0.1.0 May 2, 2025

#490 in Unix APIs

34 downloads per month

MIT license

21KB
320 lines

restrict

Ergonomic and DX-first Linux syscall filtering crate

restrict offers a clean, expressive API to allow or deny syscalls on Linux. It generates a system-aware Syscall enum at build time and exposes a safe policy manager to configure syscall rules for your application.


✨ Features

  • 🚀 Auto-generated Syscall enum tailored to your host architecture
  • 📝 Ergonomic API: policy.allow(Syscall::Write)?;
  • 🔒 Safe wrapper: no unsafe blocks or raw pointers
  • 🎛️ Allow-by-default or deny-by-default policy modes
  • 🔍 Runtime inspection: list allowed or killed syscalls

🚀 Quickstart

allow_all() is the recommended default for most use cases to avoid unintentionally blocking essential syscalls.

use restrict::{Policy, Syscall, Action};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Start with all syscalls allowed
    let mut policy = Policy::allow_all()?; // recommended

    policy
        .deny(Syscall::Execve)?   // prevent process spawning
        .deny(Syscall::Ptrace)?   // prevent tracing/hijacking
        .apply()?;                // apply the final filter set

    // Your program continues safely here
    Ok(())
}

Or, for a stricter base policy:

use restrict::{Policy, Syscall};

fn main() -> Result<(), Box<dyn std::error::Error>> {

    let mut policy = Policy::deny_all()?;  
    policy
        .allow(Syscall::Read)?
        .allow(Syscall::Write)?
        .apply()?;  

    // only allow read and write
    Ok(())
}

🛠️ API Overview

  • Policy::allow_all() Starts with all syscalls allowed; then call .deny(...) for any you want to block.

  • Policy::deny_all() Starts with all syscalls denied; then call .allow(...) for any you need.

  • policy.allow(syscall: Syscall)&mut Self Mark a syscall as allowed.

  • policy.deny(syscall: Syscall)&mut Self Mark a syscall as killed.

  • policy.apply()() Finalize and load all collected filters into the kernel.

  • policy.list_allowed_syscalls() -> Vec<Syscall> Retrieve the list of syscalls you’ve allowed(by allow()).

  • policy.list_killed_syscalls() -> Vec<Syscall> Retrieve the list of syscalls you’ve denied(by deny()).

📦 Generated Syscall Enum

During build, restrict parses your system headers (e.g. /usr/include/asm/unistd_64.h) and emits:

/// System call list generated from `/usr/include/asm/unistd_64.h`
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Syscall {
    Read = 0,
    Write = 1,
    Open = 2,
    // … etc …
}

This ensures accuracy across architectures (x86_64, aarch64, etc.). To override the header location:

SYSCALL_INCLUDE_DIR=/path/to/other/asm cargo build

License

This project is licensed under the terms of the MIT license.

See the LICENSE file for more details.

Dependencies

~0.2–1MB
~21K SLoC