Skip to content

Commit

Permalink
seccomp: Update experiment seccomp program (#2946)
Browse files Browse the repository at this point in the history
Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>
  • Loading branch information
sat0ken authored Oct 13, 2024
1 parent dc2e09b commit eaaca64
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 39 deletions.
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 {
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> {
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
}
}

0 comments on commit eaaca64

Please sign in to comment.