1
0
mirror of https://github.com/containers/youki synced 2024-11-22 17:02:00 +01:00

seccomp: Update experiment seccomp program (#2946)

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>
This commit is contained in:
sat0ken 2024-10-13 13:53:29 +09:00 committed by GitHub
parent dc2e09b431
commit eaaca64fe4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 145 additions and 39 deletions

@ -266,10 +266,42 @@ dependencies = [
"nix 0.27.1",
"prctl",
"syscall-numbers",
"syscalls",
"thiserror",
"tokio",
]
[[package]]
name = "serde"
version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_repr"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
@ -312,6 +344,16 @@ version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "084e382bf467cd3381fdec080d883505792ee0d16a004b1b090abf2db5dc2a29"
[[package]]
name = "syscalls"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d0e35dc7d73976a53c7e6d7d177ef804a0c0ee774ec77bcc520c2216fd7cbe"
dependencies = [
"serde",
"serde_repr",
]
[[package]]
name = "thiserror"
version = "1.0.58"

@ -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"]}

@ -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![

@ -1,5 +1,5 @@
use seccomp::{
instruction::{self, *},
instruction::{*},
seccomp::{NotifyFd, Seccomp},
};
@ -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();
@ -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()

@ -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 {
@ -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
}
}