#![allow(unsafe_code)]
use std::io;
const PR_SET_NO_NEW_PRIVS: i32 = 38;
const PR_SET_SECCOMP: i32 = 22;
const SECCOMP_MODE_FILTER: u64 = 2;
unsafe extern "C" {
fn prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> i32;
}
#[repr(C)]
#[derive(Clone, Copy)]
struct SockFilter {
code: u16,
jt: u8,
jf: u8,
k: u32,
}
#[repr(C)]
struct SockFprog {
len: u16,
filter: *const SockFilter,
}
pub fn restrict() -> io::Result<()> {
#[cfg(target_arch = "x86_64")]
{
const LD_W_ABS: u16 = 0x20; const JEQ_K: u16 = 0x15; const RET_K: u16 = 0x06; const OFF_NR: u32 = 0;
const OFF_ARCH: u32 = 4;
const AUDIT_ARCH_X86_64: u32 = 0xC000_003E;
const RET_ALLOW: u32 = 0x7FFF_0000;
const RET_ERRNO_EPERM: u32 = 0x0005_0000 | 1; const RET_KILL_PROCESS: u32 = 0x8000_0000;
const NR_SOCKET: u32 = 41;
const NR_CONNECT: u32 = 42;
const NR_EXECVE: u32 = 59;
const NR_PTRACE: u32 = 101;
const NR_EXECVEAT: u32 = 322;
let jeq = |nr: u32| SockFilter {
code: JEQ_K,
jt: 0,
jf: 1,
k: nr,
};
let deny = SockFilter {
code: RET_K,
jt: 0,
jf: 0,
k: RET_ERRNO_EPERM,
};
let prog = [
SockFilter {
code: LD_W_ABS,
jt: 0,
jf: 0,
k: OFF_ARCH,
},
SockFilter {
code: JEQ_K,
jt: 1,
jf: 0,
k: AUDIT_ARCH_X86_64,
},
SockFilter {
code: RET_K,
jt: 0,
jf: 0,
k: RET_KILL_PROCESS,
},
SockFilter {
code: LD_W_ABS,
jt: 0,
jf: 0,
k: OFF_NR,
},
jeq(NR_SOCKET),
deny,
jeq(NR_CONNECT),
deny,
jeq(NR_EXECVE),
deny,
jeq(NR_EXECVEAT),
deny,
jeq(NR_PTRACE),
deny,
SockFilter {
code: RET_K,
jt: 0,
jf: 0,
k: RET_ALLOW,
},
];
unsafe {
if prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0 {
return Err(io::Error::last_os_error());
}
let fprog = SockFprog {
len: prog.len() as u16,
filter: prog.as_ptr(),
};
if prctl(
PR_SET_SECCOMP,
SECCOMP_MODE_FILTER,
&fprog as *const SockFprog as u64,
0,
0,
) != 0
{
return Err(io::Error::last_os_error());
}
}
Ok(())
}
#[cfg(not(target_arch = "x86_64"))]
{
Err(io::Error::new(
io::ErrorKind::Unsupported,
"seccomp content sandbox is implemented for x86-64 only",
))
}
}