Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
bafe684
update seccomp program of update method and add function
sat0ken Feb 3, 2025
411d5bc
implementation From trait
sat0ken Apr 13, 2025
189f9a2
implement seccomp flags if config.json define
sat0ken Apr 14, 2025
b6935ed
add BPF Instruction to validate
sat0ken Apr 30, 2025
c7f3bb0
add fn to get nr offset from seccomp_data
sat0ken Apr 30, 2025
e2ab133
modify generate BPF program order
sat0ken Apr 30, 2025
31b4379
implement check args of seccomp program and add test code
sat0ken Apr 30, 2025
89f21fc
move test json file to tests
sat0ken Jun 2, 2025
d2af7a3
change to return Result
sat0ken Jun 2, 2025
74b9b45
change fn seccomp_data_args_offset to return Result
sat0ken Jun 2, 2025
e90a95d
to change return Result, add unwrap
sat0ken Jun 2, 2025
2a603e6
run cargo fmt
sat0ken Jun 25, 2025
b6e6575
fix offset size
sat0ken Jun 25, 2025
8553674
add design pattern to rule
sat0ken Aug 3, 2025
7bc22e0
change method to return Result
sat0ken Aug 9, 2025
e08d3f6
change method name
sat0ken Aug 9, 2025
a78e141
improve multipul variable set to use is_none method
sat0ken Sep 5, 2025
c55e436
fix test code
sat0ken Sep 8, 2025
95e39db
insert BPF_JMP to new to omit code
sat0ken Sep 8, 2025
122f266
omit BPM_JMP from code
sat0ken Sep 8, 2025
3c02e29
add check argument count
sat0ken Sep 8, 2025
f305bed
fix if value is 0, set the value
sat0ken Sep 8, 2025
b32b1f0
fix for cargo clippy
sat0ken Sep 8, 2025
3a1f25c
change argument string to Path
sat0ken Dec 21, 2025
016e768
change to return Result and remove unwrap
sat0ken Dec 21, 2025
2ade7c2
change struct name InstructionData to SeccompProgramPlan
sat0ken Dec 21, 2025
415bae2
implement TryFrom to SeccompProgramPlan
sat0ken Dec 21, 2025
eaa47ca
update oci-spec-rs
sat0ken Mar 10, 2026
87cfb8e
errno correctly set to the value of action
sat0ken Mar 10, 2026
22e6347
refactoring testutils.rs to use oci-spec-rs to parse json
sat0ken Mar 11, 2026
22d4a2f
refactor fn try_from to separate logic
sat0ken Mar 12, 2026
690a922
fix test code and refactor
sat0ken Mar 12, 2026
29ea7a6
change type of syscall Vec<String> to Vec<u64> to sort
sat0ken Mar 16, 2026
15d0a31
add const to jump_num
sat0ken Mar 16, 2026
ada6110
cargo fmt
sat0ken Mar 16, 2026
03ac32b
minor update for test
sat0ken Mar 16, 2026
02ae9b3
create example dir and move main.rs
sat0ken Mar 17, 2026
400e59c
fix typo
sat0ken Mar 17, 2026
e81c9d0
update package and toolchain
sat0ken Mar 17, 2026
9a0dcbf
cargo fmt
sat0ken Mar 17, 2026
c1dc2bc
remove unused package
sat0ken Mar 17, 2026
8c0cc0c
organize tests dir
sat0ken Apr 1, 2026
66cd3b7
update Cargo.toml
sat0ken Apr 1, 2026
3d8a29d
add readjson file by libseccomp
sat0ken Apr 1, 2026
107f1f0
update README
sat0ken Apr 1, 2026
741354b
cargo fmt
sat0ken Apr 4, 2026
716a547
fix typo
sat0ken Apr 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
630 changes: 611 additions & 19 deletions experiment/seccomp/Cargo.lock

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions experiment/seccomp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ nix = { version = "0.29.0", features = [
thiserror = "1.0.57"
prctl = "1.0.0"
anyhow = "1.0"
tokio = { version = "1", features = ["full"] }
syscall-numbers = "3.1.1"
syscalls = { version = "0.6.18", features = ["std", "serde", "aarch64", "x86_64"]}
syscalls = { version = "0.6.18", features = ["std", "serde", "aarch64", "x86_64"]}
oci-spec = { version = "0.9.0", features = ["runtime"] }
serde_json = "1.0.138"
derive_builder = "0.20.2"

[dev-dependencies]
tokio = { version = "1", features = ["full"] }
libseccomp = "0.4.0"
tempfile = "3.27.0"
6 changes: 5 additions & 1 deletion experiment/seccomp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@ This is an experimental project in order to get away from libseccomp.
Ref: https://github.com/youki-dev/youki/issues/2724

```console
$ cargo run
# apply sample seccomp filter
$ cargo test --test filter -- --show-output

# output bpf instruction
$ cargo test --test readjson -- --show-output
```
2 changes: 1 addition & 1 deletion experiment/seccomp/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
profile="default"
channel="1.77.1"
channel="1.92.0"
107 changes: 87 additions & 20 deletions experiment/seccomp/src/instruction/arch.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,55 @@
use crate::instruction::Instruction;
use crate::instruction::*;
use std::os::raw::c_uchar;

#[derive(PartialEq, Debug)]
use nix::errno::Errno::ENOSYS;

use crate::instruction::{Instruction, *};

#[derive(PartialEq, Debug, Default)]
pub enum Arch {
X86,AArch64
#[default]
X86,
AArch64,
}

pub fn gen_validate(arc: &Arch) -> Vec<Instruction> {
pub fn gen_validate(arc: &Arch, def_action: u32, jump_num: usize) -> Vec<Instruction> {
let arch = match arc {
Arch::X86 => AUDIT_ARCH_X86_64,
Arch::AArch64 => AUDIT_ARCH_AARCH64
Arch::AArch64 => AUDIT_ARCH_AARCH64,
};

vec![
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_arch_offset() as u32),
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, arch),
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
]
if jump_num <= BPF_JMP_MAX {
vec![
// load offset architecture
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_arch_offset() as u32),
// if not match architecture, jump to default action
Instruction::jump(
BPF_JMP | BPF_JEQ | BPF_K,
0,
(jump_num + 3) as c_uchar,
arch,
),
// load offset system call number
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_nr_offset() as u32),
// check system call is not using 32bit ABI
// see https://github.com/elastic/go-seccomp-bpf/blob/main/filter.go#L231
Instruction::jump(BPF_JMP | BPF_JGE | BPF_K, 0, 1, X32_SYSCALL_BIT),
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ENOSYS as u32),
]
} else {
vec![
// load offset architecture
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_arch_offset() as u32),
// if not match architecture, jump to default action
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 1, 0 as c_uchar, arch),
Instruction::stmt(BPF_RET | BPF_K, def_action),
// load offset system call number
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_nr_offset() as u32),
// check system call is not using 32bit ABI
// see https://github.com/elastic/go-seccomp-bpf/blob/main/filter.go#L231
Instruction::jump(BPF_JMP | BPF_JGE | BPF_K, 0, 1, X32_SYSCALL_BIT),
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ENOSYS as u32),
]
}
}

#[cfg(test)]
Expand All @@ -25,17 +58,51 @@ mod tests {

#[test]
fn test_gen_validate_x86() {
let bpf_prog = gen_validate(&Arch::X86);
assert_eq!(bpf_prog[0], Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_arch_offset() as u32));
assert_eq!(bpf_prog[1], Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, AUDIT_ARCH_X86_64));
assert_eq!(bpf_prog[2], Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS));
let bpf_prog = gen_validate(&Arch::X86, SECCOMP_RET_KILL_PROCESS, 3);
assert_eq!(
bpf_prog[0],
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_arch_offset() as u32)
);
assert_eq!(
bpf_prog[1],
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 6, AUDIT_ARCH_X86_64)
);
assert_eq!(
bpf_prog[2],
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_nr_offset() as u32)
);
assert_eq!(
bpf_prog[3],
Instruction::jump(BPF_JMP | BPF_JGE | BPF_K, 0, 1, X32_SYSCALL_BIT)
);
assert_eq!(
bpf_prog[4],
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ENOSYS as u32)
);
}

#[test]
fn test_gen_validate_aarch64() {
let bpf_prog = gen_validate(&Arch::AArch64);
assert_eq!(bpf_prog[0], Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_arch_offset() as u32));
assert_eq!(bpf_prog[1], Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, AUDIT_ARCH_AARCH64));
assert_eq!(bpf_prog[2], Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS));
let bpf_prog = gen_validate(&Arch::AArch64, SECCOMP_RET_KILL_PROCESS, 3);
assert_eq!(
bpf_prog[0],
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_arch_offset() as u32)
);
assert_eq!(
bpf_prog[1],
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 6, AUDIT_ARCH_AARCH64)
);
assert_eq!(
bpf_prog[2],
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_nr_offset() as u32)
);
assert_eq!(
bpf_prog[3],
Instruction::jump(BPF_JMP | BPF_JGE | BPF_K, 0, 1, X32_SYSCALL_BIT)
);
assert_eq!(
bpf_prog[4],
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ENOSYS as u32)
);
}
}
}
44 changes: 40 additions & 4 deletions experiment/seccomp/src/instruction/consts.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::{mem::offset_of, os::raw::c_int};
use std::mem::offset_of;
use std::os::raw::c_int;

use crate::seccomp::SeccompError;

// BPF Instruction classes.
// See /usr/include/linux/bpf_common.h .
Expand Down Expand Up @@ -30,9 +33,14 @@ pub const BPF_JA: u16 = 0x00;
pub const BPF_JEQ: u16 = 0x10;
pub const BPF_JGT: u16 = 0x20;
pub const BPF_JGE: u16 = 0x30;
pub const BPF_JSET: u16 = 0x40;
// Test against the value in the K register.
pub const BPF_K: u16 = 0x00;

// Limitation on the number of jumps for the bpf instruction
// https://github.com/seccomp/libseccomp/blob/main/src/gen_bpf.c#L104
pub const BPF_JMP_MAX: usize = 255;

// Return codes for BPF programs.
// See /usr/include/linux/seccomp.h .
pub const SECCOMP_RET_ALLOW: u32 = 0x7fff_0000;
Expand All @@ -50,6 +58,22 @@ pub const SECCOMP_RET_USER_NOTIF: u32 = 0x7fc00000;
pub const AUDIT_ARCH_X86_64: u32 = 62 | 0x8000_0000 | 0x4000_0000;
pub const AUDIT_ARCH_AARCH64: u32 = 183 | 0x8000_0000 | 0x4000_0000;

// See /arch/x86/include/uapi/asm/unistd.h
pub const X32_SYSCALL_BIT: u32 = 0x4000_0000;

// Comparison operators
// See libseccomp/include/seccomp.h.in
#[derive(Debug, PartialEq, Clone)]
pub enum SeccompCompareOp {
NotEqual = 1,
LessThan,
LessOrEqual,
Equal,
GreaterOrEqual,
GreaterThan,
MaskedEqual,
}

// ```c
// struct seccomp_data {
// int nr;
Expand All @@ -67,6 +91,10 @@ struct SeccompData {
args: [u64; 6],
}

pub const fn seccomp_data_nr_offset() -> u8 {
offset_of!(SeccompData, nr) as u8
}

pub const fn seccomp_data_arch_offset() -> u8 {
offset_of!(SeccompData, arch) as u8
}
Expand All @@ -75,8 +103,11 @@ pub const fn seccomp_data_arg_size() -> u8 {
8
}

pub const fn seccomp_data_args_offset() -> u8 {
offset_of!(SeccompData, args) as u8
pub const fn seccomp_data_args_offset(index: u8) -> Result<u8, SeccompError> {
match index {
0..=5 => Ok((offset_of!(SeccompData, args) as u8) + (index * 8)),
_ => Err(SeccompError::InvalidArgumentSize),
}
}

pub const SECCOMP_IOC_MAGIC: u8 = b'!';
Expand All @@ -102,7 +133,12 @@ mod tests {
#[test]
fn test_seccomp_data_args_offset() {
if cfg!(target_arch = "x86_64") {
assert_eq!(seccomp_data_args_offset(), 16);
assert_eq!(seccomp_data_args_offset(0).unwrap(), 16);
assert_eq!(seccomp_data_args_offset(1).unwrap(), 16 + 8);
assert_eq!(seccomp_data_args_offset(2).unwrap(), 16 + 16);
assert_eq!(seccomp_data_args_offset(3).unwrap(), 16 + 24);
assert_eq!(seccomp_data_args_offset(4).unwrap(), 16 + 32);
assert_eq!(seccomp_data_args_offset(5).unwrap(), 16 + 40);
}
}
}
12 changes: 7 additions & 5 deletions experiment/seccomp/src/instruction/inst.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::os::raw::{c_uchar, c_uint, c_ushort};

use crate::instruction::BPF_JMP;

// https://docs.kernel.org/networking/filter.html#structure
// <linux/filter.h>: sock_filter
#[repr(C)]
Expand Down Expand Up @@ -32,7 +34,7 @@ impl Instruction {
jump_false: c_uchar,
multiuse_field: c_uint,
) -> Self {
Self::new(code, jump_true, jump_false, multiuse_field)
Self::new(BPF_JMP | code, jump_true, jump_false, multiuse_field)
}

pub fn stmt(code: c_ushort, k: c_uint) -> Self {
Expand All @@ -57,12 +59,12 @@ mod tests {
}
);
assert_eq!(
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 10, 2, 5),
Instruction::jump(BPF_JEQ | BPF_K, 10, 2, 5),
Instruction {
code: 0x15,
offset_jump_true: 2,
offset_jump_false: 5,
multiuse_field: 10,
offset_jump_true: 10,
offset_jump_false: 2,
multiuse_field: 5,
}
);
}
Expand Down
2 changes: 1 addition & 1 deletion experiment/seccomp/src/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ mod arch;
mod consts;
mod inst;

pub use arch::{gen_validate, Arch};
pub use arch::{Arch, gen_validate};
pub use consts::*;
pub use inst::Instruction;
Loading
Loading