Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update seccomp program #536

Closed
wants to merge 14 commits into from
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/libcgroups/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ serde = { version = "1.0", features = ["derive"] }
rbpf = { version = "0.2.0", optional = true }
libbpf-sys = { version = "1.4.3", optional = true }
errno = { version = "0.3.9", optional = true }
libc = { version = "0.2.155", optional = true }
libc = { version = "0.2.156", optional = true }
thiserror = "1.0.63"
tracing = { version = "0.1.40", features = ["attributes"] }

Expand Down
2 changes: 1 addition & 1 deletion crates/libcontainer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ chrono = { version = "0.4", default-features = false, features = [
] }
fastrand = "^2.1.0"
futures = { version = "0.3", features = ["thread-pool"] }
libc = "0.2.155"
libc = "0.2.156"
nix = { version = "0.28.0", features = [
"socket",
"sched",
Expand Down
42 changes: 42 additions & 0 deletions experiment/seccomp/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions experiment/seccomp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ 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"]}
4 changes: 3 additions & 1 deletion experiment/seccomp/src/instruction/arch.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use crate::instruction::Instruction;
use crate::instruction::*;

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

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

vec![
Expand Down
57 changes: 21 additions & 36 deletions experiment/seccomp/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use seccomp::{
instruction::{self, *},
instruction::{*},
seccomp::{NotifyFd, Seccomp},
};

Expand All @@ -9,19 +9,18 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::slice;

use anyhow::Result;
use nix::{
libc,
sys::{
signal::Signal,
socket::{
self, ControlMessage, ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixAddr,
},
stat::Mode,
wait::{self, WaitStatus},
use nix::{libc, sys::{
signal::Signal,
socket::{
self, ControlMessage, ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixAddr,
},
unistd::{close, mkdir},
};
stat::Mode,
wait::{self, WaitStatus},
}, unistd::{close, mkdir}};

use syscall_numbers::x86_64;
use syscalls::syscall_args;
use seccomp::seccomp::{InstructionData, Rule};

fn send_fd<F: AsRawFd>(sock: OwnedFd, fd: &F) -> nix::Result<()> {
let fd = fd.as_raw_fd();
Expand Down Expand Up @@ -90,30 +89,16 @@ async fn main() -> Result<()> {
)?;

let _ = prctl::set_no_new_privileges(true);

let mut bpf_prog = instruction::gen_validate(&Arch::X86);
bpf_prog.append(&mut vec![
// A: Check if syscall is getcwd
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, 0),
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, libc::SYS_getcwd as u32), // If false, go to B
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
// B: Check if syscall is write and it is writing to stderr(fd=2)
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, 0),
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 3, libc::SYS_write as u32), // If false, go to C
// Load the file descriptor
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_args_offset().into()),
// Check if args is stderr
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, libc::STDERR_FILENO as u32), // If false, go to C
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
// C: Check if syscall is mkdir and if so, return seccomp notify
Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, 0),
Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, libc::SYS_mkdir as u32), // If false, go to D
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF),
// D: Pass
Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
]);

let seccomp = Seccomp { filters: bpf_prog };
let inst_data = InstructionData{
arc: Arch::X86,
def_action: SECCOMP_RET_KILL_PROCESS,
rule_arr: vec![
Rule::new("getcwd".parse()?, 0, syscall_args!(),false),
Rule::new("write".parse()?,1, syscall_args!(libc::STDERR_FILENO as usize), false),
Rule::new("mkdir".parse()?,0, syscall_args!(), true)
]
};
let seccomp = Seccomp {filters: Vec::from(inst_data)};

tokio::spawn(async move {
tokio::signal::ctrl_c()
Expand Down
80 changes: 78 additions & 2 deletions experiment/seccomp/src/seccomp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ use std::{
},
};

use std::str::FromStr;
use nix::{
errno::Errno,
ioctl_readwrite, ioctl_write_ptr, libc,
libc::{SECCOMP_FILTER_FLAG_NEW_LISTENER, SECCOMP_SET_MODE_FILTER},
unistd,
};

use crate::instruction::{Instruction, SECCOMP_IOC_MAGIC};
use syscalls::{SyscallArgs};
use crate::instruction::{*};
use crate::instruction::{Arch, Instruction, SECCOMP_IOC_MAGIC};

#[derive(Debug, thiserror::Error)]
pub enum SeccompError {
Expand Down Expand Up @@ -198,3 +200,77 @@ struct Filters {
pub len: c_ushort,
pub filter: *const Instruction,
}

fn get_syscall_number(arc: &Arch, name: &str) -> Option<u64> {
match arc {
Arch::X86 => {
match syscalls::x86_64::Sysno::from_str(name) {
Ok(syscall) => Some(syscall as u64),
Err(_) => None,
}
},
Arch::AArch64 => {
match syscalls::aarch64::Sysno::from_str(name) {
Ok(syscall) => Some(syscall as u64),
Err(_) => None,
}
}
}
}

#[derive(Debug)]
pub struct InstructionData {
pub arc: Arch,
pub def_action: u32,
pub rule_arr: Vec<Rule>
}

impl From<InstructionData> for Vec<Instruction> {
fn from(inst_data: InstructionData) -> Self {
let mut bpf_prog = gen_validate(&inst_data.arc);

for rule in &inst_data.rule_arr {
bpf_prog.append(&mut Rule::to_instruction(&inst_data.arc, inst_data.def_action, rule));
}

bpf_prog.append(&mut vec![Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)]);
bpf_prog
}
}

#[derive(Debug)]
pub struct Rule {
pub syscall: String,
pub arg_cnt: u8,
pub args: SyscallArgs,
pub is_notify: bool
}

impl Rule {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

もし可能だったら別PRでもいいですし、他の方でもいいんですが unit テスト足したいですね。

Copy link
Author

@sat0ken sat0ken Oct 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unit テストの書き方がまだわからないので、別PRで対応致しますm(- -)m

pub fn new(syscall: String, arg_cnt: u8, args: SyscallArgs, is_notify: bool) -> Self {
Self {
syscall,
arg_cnt,
args,
is_notify,
}
}

pub fn to_instruction(arch: &Arch, action: u32, rule: &Rule) -> Vec<Instruction> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 Fromを提案しておいてなんですが、無理せずこれでも十分使いやすいインタフェースだと思います。ありがとうございます。

let mut bpf_prog = gen_validate(arch);
bpf_prog.append(&mut vec![Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, 0)]);
bpf_prog.append(&mut vec![Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 1,
get_syscall_number(arch, &rule.syscall).unwrap() as c_uint)]);
if rule.arg_cnt != 0 {
bpf_prog.append(&mut vec![Instruction::stmt(BPF_LD | BPF_W | BPF_ABS, seccomp_data_args_offset().into())]);
bpf_prog.append(&mut vec![Instruction::jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, rule.args.arg0 as c_uint)]);
}

if rule.is_notify {
bpf_prog.append(&mut vec![Instruction::stmt(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF)]);
} else {
bpf_prog.append(&mut vec![Instruction::stmt(BPF_RET | BPF_K, action)]);
}
bpf_prog
}
}
23 changes: 23 additions & 0 deletions experiment/selinux/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion experiment/selinux/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ autoexamples = true
keywords = ["youki", "container", "selinux"]

[dependencies]
nix = { version = "0.29.0", features = ["process", "fs"] }
anyhow = "1.0.86"
nix = { version = "0.29.0", features = ["process", "fs", "socket"] }
rustix = { version = "0.38.34", features = ["fs"] }
tempfile = "3.10.1"
thiserror = "1.0.61"
5 changes: 5 additions & 0 deletions experiment/selinux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@ Ref: https://github.com/containers/youki/issues/2718.
Reimplementation of [opencontainers/selinux](https://github.com/opencontainers/selinux) in Rust.
Also selinux depends on xattr, but nix doesn't cover xattr function.
Therefore, this PR will implement xattr in Rust.
Referenced the implementation of xattr in [unix](golang.org/x/sys/unix) repo.

Please import and use this project.

```console
$ cargo run
```
Loading