Skip to content

Commit

Permalink
Rewrite in Rust
Browse files Browse the repository at this point in the history
Finally, we are getting rid of C and libbpf here. This PR replaces
all the eBPF programs with Rust programs written in Aya.

The part of this PR is also:

* fetching recent, relevant changes in aya-template
* using LpmTrie maps for mount policies (TODO)
* detecting new processes only with tracepoints, the task LSM program
  was removed

Fixes: lockc-project#49
Fixes: lockc-project#134
Fixes: lockc-project#137
Fixes: lockc-project#138
Signed-off-by: Michal Rostecki <[email protected]>
  • Loading branch information
vadorovsky committed May 4, 2022
1 parent abd4967 commit 4e7662d
Show file tree
Hide file tree
Showing 41 changed files with 41,943 additions and 2,299 deletions.
5 changes: 1 addition & 4 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
[alias]
xtask = "run --package xtask --"

[target.x86_64-unknown-linux-gnu]
runner = "sudo -E"
xtask = "run --package xtask --"
22 changes: 14 additions & 8 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,34 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- name: Install rustc nightly
uses: actions-rs/toolchain@v1
with:
go-version: "1.17"
- name: Install dapper
run: go install github.com/rancher/dapper@latest
toolchain: nightly
components: rustfmt, clippy, rust-src
- name: Install bpf-linker
run: cargo install bpf-linker
- name: Build eBPF
run: cargo xtask build-ebpf
- name: Build
run: dapper cargo build
run: cargo build
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
- name: Test
run: dapper cargo test
run: cargo test
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
- name: Lint
run: dapper cargo clippy -- -D warnings
run: cargo clippy -- -D warnings
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
- name: Install udeps
run: cargo install udeps
- name: Check unused dependencies
run: dapper cargo +nightly udeps --all-targets
run: cargo udeps --all-targets
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
24 changes: 4 additions & 20 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,29 +1,13 @@
### https://raw.github.com/github/gitignore/master/Rust.gitignore

# Generated by Cargo
# will have compiled files and executables
**/debug/
**/target/
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# BTF headers
**/vmlinux.h

# Output (BPF)
**/.output/

# Misc
**/*~

# mdBook output
**/docs/book/

# IDE
.idea

# Dapper
Dockerfile.dapper*
3 changes: 3 additions & 0 deletions .vim/coc-settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.linkedProjects": ["Cargo.toml", "lockc-ebpf/Cargo.toml"]
}
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.linkedProjects": ["Cargo.toml", "lockc-ebpf/Cargo.toml"]
}
5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
[workspace]
members = [
"lockc",
"xtask",
]
members = ["lockc", "lockc-common", "xtask"]
48 changes: 19 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,28 @@
![lockc](https://raw.githubusercontent.com/lockc-project/assets/main/logo-horizontal-lockc.png)
# lockc

[![Crate](https://img.shields.io/crates/v/lockc)](https://crates.io/crates/lockc)
[![Book](https://img.shields.io/website?url=https%3A%2F%2Flockc-project.github.io%2Flockc%2F)](https://lockc-project.github.io/lockc/)
[![Discord](https://img.shields.io/discord/874314181191565453?label=discord&logo=discord)](https://discord.gg/799cmsYB4q)
[![Docs](https://docs.rs/lockc/badge.svg)](https://docs.rs/lockc/)
[![Build Status](https://github.com/lockc-project/lockc/actions/workflows/rust.yml/badge.svg)](https://github.com/lockc-project/lockc/actions/workflows/rust.yml)
## Prerequisites

**lockc** is open source sofware for providing MAC (Mandatory Access Control)
type of security audit for container workloads.
1. Install a rust stable toolchain: `rustup install stable`
1. Install a rust nightly toolchain: `rustup install nightly`
1. Install bpf-linker: `cargo install bpf-linker`

The main reason why **lockc** exists is that **containers do not contain**.
Containers are not as secure and isolated as VMs. By default, they expose
a lot of information about host OS and provide ways to "break out" from the
container. **lockc** aims to provide more isolation to containers and make them
more secure.
## Build eBPF

The [Containers do not contain](https://lockc-project.github.io/book/containers-do-not-contain.html)
documentation section explains what we mean by that phrase and what kind of
behavior we want to restrict with **lockc**.
```bash
cargo xtask build-ebpf
```

The main technology behind lockc is [eBPF](https://ebpf.io/) - to be more
precise, its ability to attach to [LSM hooks](https://www.kernel.org/doc/html/latest/bpf/bpf_lsm.html)
To perform a release build you can use the `--release` flag.
You may also change the target architecture with the `--target` flag

Please note that currently lockc is an experimental project, not meant for
production environment and without any official binaries or packages to use -
currently the only way to use it is building from sources.
## Build Userspace

See [the full documentation here](https://lockc-project.github.io/book/).
And [the code documentation here](https://docs.rs/lockc/).
```bash
cargo build
```

If you need help or want to talk with contributors, plese come chat with us
on `#lockc` channel on the [Rust Cloud Native Discord server](https://discord.gg/799cmsYB4q).
## Run

**lockc's** userspace part is licensed under [Apache License, version 2.0](https://github.com/lockc-project/lockc/blob/main/LICENSE).

eBPF programs inside [lockc/src/bpf directory](https://github.com/lockc-project/lockc/tree/main/lockc/src/bpf)
are licensed under [GNU General Public License, version 2](https://github.com/lockc-project/lockc/blob/main/lockc/src/bpf/LICENSE).
```bash
cargo xtask run
```
15 changes: 15 additions & 0 deletions lockc-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "lockc-common"
version = "0.1.0"
edition = "2021"

[features]
default = []
user = [ "aya", "thiserror" ]

[dependencies]
aya = { version = "0.10", optional = true }
thiserror = { version = "1.0", optional = true }

[lib]
path = "src/lib.rs"
97 changes: 97 additions & 0 deletions lockc-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#![cfg_attr(not(feature = "user"), no_std)]

/// Max configurable PID limit (for x86_64, for the other architectures it's
/// less or equal).
// TODO(vadorovsky): I need to teach aya to be able to resize maps before they
// are loaded into the kernel. So far aya doesn't differentiate between open()
// and load(), it opens the ELF object and loads it immediately in one step.
// I need to change it.
// After that, we will be able to set the limit again up to the upper possible
// limit. And resize according to the max PID limit in sysctl.
// Before it's done - let's stick to the default value to not use too much RAM.
// pub const PID_MAX_LIMIT: u32 = 4194304;
pub const PID_MAX_LIMIT: u32 = 32768;

pub const MOUNT_TYPE_LEN: usize = 5;

pub const PATH_LEN: usize = 64;

const CONTAINER_ID_LEN: usize = 64;

#[cfg_attr(feature = "user", derive(Debug))]
#[derive(Copy, Clone)]
#[repr(C)]
pub enum ContainerPolicyLevel {
NotFound = -1,

Lockc,

// Policy levels.
Restricted,
Baseline,
Privileged,
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct ContainerID {
pub id: [u8; CONTAINER_ID_LEN],
}

#[cfg(feature = "user")]
#[derive(thiserror::Error, Debug)]
pub enum NewContainerIDError {
#[error(transparent)]
NulError(#[from] std::ffi::NulError),

#[error("could not convert Vec<u8> to CString")]
VecU8CStringConv,
}

#[cfg(feature = "user")]
impl ContainerID {
/// Creates a new container_id instance and converts the given Rust string
/// into C fixed size char array.
pub fn new(id: &str) -> Result<Self, NewContainerIDError> {
let mut id_b = std::ffi::CString::new(id)?.into_bytes_with_nul();
id_b.resize(CONTAINER_ID_LEN, 0);
Ok(ContainerID {
id: id_b
.try_into()
.map_err(|_| NewContainerIDError::VecU8CStringConv)?,
})
}
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct Container {
pub policy_level: ContainerPolicyLevel,
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct Process {
pub container_id: ContainerID,
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct MountType {
pub mount_type: [u8; MOUNT_TYPE_LEN],
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct ContainerPath {
pub path: [u8; PATH_LEN],
}

#[cfg(feature = "user")]
mod user {
use super::*;

unsafe impl aya::Pod for ContainerID {}
unsafe impl aya::Pod for Container {}
unsafe impl aya::Pod for Process {}
}
6 changes: 6 additions & 0 deletions lockc-ebpf/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[build]
target-dir = "../target"
target = "bpfel-unknown-none"

[unstable]
build-std = ["core"]
4 changes: 4 additions & 0 deletions lockc-ebpf/.vim/coc-settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"rust-analyzer.cargo.target": "bpfel-unknown-none",
"rust-analyzer.checkOnSave.allTargets": false
}
4 changes: 4 additions & 0 deletions lockc-ebpf/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"rust-analyzer.cargo.target": "bpfel-unknown-none",
"rust-analyzer.checkOnSave.allTargets": false,
}
32 changes: 32 additions & 0 deletions lockc-ebpf/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "lockc-ebpf"
version = "0.1.0"
edition = "2021"

[dependencies]
aya-bpf = { git = "https://github.com/aya-rs/aya", branch = "main" }
aya-log-ebpf = { git = "https://github.com/aya-rs/aya-log", branch = "main" }
lockc-common = { path = "../lockc-common" }

[[bin]]
name = "lockc"
path = "src/main.rs"

[profile.dev]
opt-level = 3
debug = false
debug-assertions = false
overflow-checks = false
lto = true
panic = "abort"
incremental = false
codegen-units = 1
rpath = false

[profile.release]
lto = true
panic = "abort"
codegen-units = 1

[workspace]
members = []
2 changes: 2 additions & 0 deletions lockc-ebpf/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel="nightly"
Loading

0 comments on commit 4e7662d

Please sign in to comment.