#linux-process #security #sandbox #sandboxing #resources #process-isolation #linux-namespaces

bin+lib hakoniwa-cli

Process isolation for Linux using namespaces, resource limits and seccomp

13 releases

0.5.2 Apr 22, 2024
0.5.1 Feb 20, 2024
0.5.0 Nov 4, 2023
0.4.8 Aug 27, 2023
0.2.1 Aug 18, 2022

#595 in Configuration

Download history 30/week @ 2024-07-21 62/week @ 2024-07-28 10/week @ 2024-09-22 1/week @ 2024-09-29

740 downloads per month

MIT/Apache

110KB
2K SLoC

Hakoniwa

Process isolation for Linux using namespaces, resource limits and seccomp. It works by creating a new, completely empty, mount namespace where the root is on a tmpfs that is invisible from the host, and will be automatically cleaned up when the last process exits. You can then use a policy configuration file or commandline options to construct the root filesystem and process environment and command to run in the namespace.

Installation

Cargo

  • Install libseccomp by following this guide.
  • Install the rust toolchain in order to have cargo installed by following this guide.
  • Run cargo install hakoniwa-cli.

Usage

CLI

When use commandline, hakoniwa-run will load a default policy configuration named KISS-policy.toml to ensure a minimal mount namespace created, use --policy-file to use your custom version.

$ hakoniwa run --verbose -- /bin/bash
[2022-08-21T09:14:11Z INFO  hakoniwa::cli::run] Configuration: "KISS-policy.toml"
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/tmp/hakoniwa-EJemcsRL", container_path: "/"
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "", container_path: "/proc", fstype: "proc"
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/usr/bin", container_path: "/bin", fstype: "", rw: false
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/usr/lib", container_path: "/lib", fstype: "", rw: false
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/usr/lib", container_path: "/lib64", fstype: "", rw: false
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/usr", container_path: "/usr", fstype: "", rw: false
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/dev/null", container_path: "/dev/null", fstype: "", rw: true
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/dev/random", container_path: "/dev/random", fstype: "", rw: true
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/dev/urandom", container_path: "/dev/urandom", fstype: "", rw: true
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Mount point: host_path: "/dev/zero", container_path: "/dev/zero", fstype: "", rw: true
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] UID map: host_id: 5001, container_id: 5001
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] GID map: host_id: 1000, container_id: 1000
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Seccomp: disabled
[2022-08-21T09:14:11Z INFO  hakoniwa::executor] Execve: /bin/bash ["/bin/bash"]
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
bash-5.1$ pwd
/
bash-5.1$ ls
bin  dev  lib  lib64  proc  usr
bash-5.1$ ls /dev
null  random  urandom  zero
bash-5.1$ ls /proc
1           bus        crypto         execdomains  ioports    kmsg           locks    mtrr          scsi      sys            uptime
4           cgroups    devices        fb           irq        kpagecgroup    meminfo  net           self      sysrq-trigger  version
acpi        cmdline    diskstats      filesystems  kallsyms   kpagecount     misc     pagetypeinfo  slabinfo  sysvipc        vmallocinfo
asound      config.gz  dma            fs           kcore      kpageflags     modules  partitions    softirqs  thread-self    vmstat
bootconfig  consoles   driver         interrupts   key-users  latency_stats  mounts   pressure      stat      timer_list     zoneinfo
buddyinfo   cpuinfo    dynamic_debug  iomem        keys       loadavg        mtd      schedstat     swaps     tty
bash-5.1$ exit
exit
[2022-08-21T09:14:27Z INFO  hakoniwa::executor] Result: {"status":"OK","reason":"","exit_code":0,"start_time":"2022-08-21T09:14:11.058546277Z","real_time":{"secs":16,"nanos":460452556},"system_time":{"secs":0,"nanos":8744000},"user_time":{"secs":0,"nanos":3149000},"max_rss":3780}

More examples can be found in hakoniwa-cli/examples.

Rust Library

The code below is almost eq to hakoniwa run --policy-file KISS-policy.toml -- /bin/bash:

use hakoniwa::{Error, Sandbox, SandboxPolicy, Stdio};

fn main() -> Result<(), Error> {
    let policy = SandboxPolicy::from_str(
        r#"
mounts = [
  { source = "/bin"        , target = "/bin"         },
  { source = "/lib"        , target = "/lib"         },
  { source = "/lib64"      , target = "/lib64"       },
  { source = "/usr"        , target = "/usr"         },
  { source = "/dev/null"   , target = "/dev/null"     , rw = true },
  { source = "/dev/random" , target = "/dev/random"   , rw = true },
  { source = "/dev/urandom", target = "/dev/urandom"  , rw = true },
  { source = "/dev/zero"   , target = "/dev/zero"     , rw = true },
]

[env]
LANG     = {{ os_env "LANG"     }}
LANGUAGE = {{ os_env "LANGUAGE" }}
LC_ALL   = {{ os_env "LC_ALL"   }}
TERM     = {{ os_env "TERM"     }}
    "#,
    )?;

    let mut sandbox = Sandbox::new();
    sandbox.with_policy(policy);

    let prog = std::env::var("SHELL").unwrap_or_else(|_| String::from("/bin/sh"));
    let argv = vec![&prog];
    let mut executor = sandbox.command(&prog, &argv);
    let result = executor
        // .ro_bind("/etc", "/myetc")? // --ro-bind /etc:/myetc
        // .rw_bind("/data", "/data")? // --rw-bind /data
        // .limit_cpu(Some(2)) // --limit-cpu 2
        // .limit_walltime(Some(5)) // --limit-walltime 5
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .stdin(Stdio::inherit())
        .run();

    dbg!(result);
    Ok(())
}

More examples can be found in hakoniwa/examples.

Running inside Docker

First, clone this repository and build the docker image:

$ make prodcontainer

Then, run hakoniwa command in the container:

$ docker run --privileged --rm -it hakoniwa-prodcontainer:latest hakoniwa run --verbose -- /bin/bash
[2023-11-04T09:24:27Z INFO  hakoniwa::cli::run] Configuration: "KISS-policy.toml"
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/tmp/hakoniwa-yBV2slf6", container_path: "/"
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "", container_path: "/proc", fstype: "proc"
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/bin", container_path: "/bin", fstype: "", rw: false
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/lib", container_path: "/lib", fstype: "", rw: false
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/lib64", container_path: "/lib64", fstype: "", rw: false
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/usr", container_path: "/usr", fstype: "", rw: false
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/dev/null", container_path: "/dev/null", fstype: "", rw: true
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/dev/random", container_path: "/dev/random", fstype: "", rw: true
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/dev/urandom", container_path: "/dev/urandom", fstype: "", rw: true
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Mount point: host_path: "/dev/zero", container_path: "/dev/zero", fstype: "", rw: true
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] UID map: host_id: 1000, container_id: 1000
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] GID map: host_id: 1000, container_id: 1000
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Seccomp: disabled
[2023-11-04T09:24:27Z INFO  hakoniwa::executor] Execve: /bin/bash ["/bin/bash"]
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
bash-5.1$ pwd
/
bash-5.1$ ls
bin  dev  lib  lib64  proc  usr
bash-5.1$ ls /dev
null  random  urandom  zero
bash-5.1$ ls /proc
1           bus        crypto         execdomains  ioports    kmsg           locks    mtrr          scsi      sys            uptime
4           cgroups    devices        fb           irq        kpagecgroup    meminfo  net           self      sysrq-trigger  version
acpi        cmdline    diskstats      filesystems  kallsyms   kpagecount     misc     pagetypeinfo  slabinfo  sysvipc        vmallocinfo
asound      config.gz  dma            fs           kcore      kpageflags     modules  partitions    softirqs  thread-self    vmstat
bootconfig  consoles   driver         interrupts   keys       latency_stats  mounts   pressure      stat      timer_list     zoneinfo
buddyinfo   cpuinfo    dynamic_debug  iomem        key-users  loadavg        mtd      schedstat     swaps     tty
bash-5.1$ exit
exit
[2023-11-04T09:24:40Z INFO  hakoniwa::executor] Result: {"status":"OK","reason":"","exit_code":0,"start_time":"2023-11-04T09:24:27.975208221Z","real_time":{"secs":12,"nanos":171313268},"system_time":{"secs":0,"nanos":2516000},"user_time":{"secs":0,"nanos":10995000},"max_rss":3584}

Howto

Acknowledgements

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~12–22MB
~299K SLoC