1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! 🅱️🧦 bandsocks
//! ================
//!
//! it's a lightweight sandbox for Linux, written in pure Rust!
//!
//! it runs docker images!
//!
//! it can run nested inside unprivileged containers!
//!
//! it's a library with minimal external dependencies!
//!
//! it's highly experimental!
//!
//! ```text
//! 🎶 🎹🧦 🎸🧦 🎸🧦 🎷🧦 🎺🧦 🥁🧦 🎶
//! ```
//!
//! Scope
//! =====
//!
//! Let's make it easy to run somewhat-untrusted computational workloads
//! like media codecs from inside an existing async rust app. There is
//! no networking or traditional storage support inside containers. The
//! container uses a virtual filesystem backed by read-only image contents and
//! mounted I/O channels.
//!
//! Getting Started
//! ===============
//!
//! The easiest way to start is via [Container::pull], which sets up a registry
//! client with default options, downloads an image to cache as necessary, and
//! provides a [ContainerBuilder] for further customization.
//!
//! ```
//! #[tokio::main]
//! async fn main() {
//!   let s = "busybox@sha256:cddb0e8f24f292e9b7baaba4d5f546db08f0a4b900be2048c6bd704bd90c13df";
//!   bandsocks::Container::pull(&s.parse().unwrap())
//!     .await.unwrap()
//!     .arg("busybox").arg("--help")
//!     .interact().await.unwrap();
//! }
//! ```
//!
//! Architecture
//! ============
//!
//! The isolation in bandsocks comes primarily from a seccomp system call
//! filter. A small set of system calls are allowed to pass through to the host
//! kernel, while many system calls are disallowed entirely and others are
//! emulated by our runtime.
//!
//! There is a 1:1 relationship between virtualized processes and host
//! processes, but virtual processes have their own ID namespace. File
//! descriptors are also mapped 1:1, so that read() and write() syscalls can be
//! a pass-through after files are opened via a slower emulated open() call.
//!
//! The emulated paths look a bit like User Mode Linux or gvisor. A ptrace-based
//! runtime we call `sand` is responsible for emulating operations like
//! open() and exec() using only allowed syscalls. For filesystem access, `sand`
//! uses an inter-process communication channel to request live file descriptors
//! from the virtual filesystem.
//!
//! The `sand` runtime is also written in Rust, but it uses a lower-level style
//! that bypasses the Rust and C standard libraries in order to have tight
//! control over its system call usage. It is a single process per container,
//! using asynchronous rust to respond to events from all processes/threads
//! within that particular container.

#[cfg(not(any(target_os = "linux", target_os = "android")))]
compile_error!("bandsocks only works on linux or android");

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate serde;
#[macro_use] extern crate hash32_derive;

mod container;
mod errors;
mod filesystem;
mod image;
mod ipcserver;
mod manifest;
mod process;
mod registry;
mod sand;
mod taskcall;

pub use crate::{
    container::*,
    errors::*,
    filesystem::{mount::*, socket::*},
    image::*,
    registry::*,
};