forked from oracle/railcar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathseccomp.rs
127 lines (117 loc) · 3.52 KB
/
seccomp.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use errors::*;
use oci::{Arch, LinuxSeccomp, LinuxSeccompOperator};
use seccomp_sys::*;
fn to_arch(arch: Arch) -> scmp_arch {
unsafe { ::std::mem::transmute(arch) }
}
fn to_cmp(cmp: LinuxSeccompOperator) -> scmp_compare {
unsafe { ::std::mem::transmute(cmp) }
}
fn syscall_resolve_name(name: &str) -> ::Result<i32> {
let s = ::std::ffi::CString::new(name)?;
let id = unsafe { seccomp_syscall_resolve_name(s.as_ptr()) };
if id == __NR_SCMP_ERROR {
let msg = format!("could not resolve {}", name);
Err(ErrorKind::SeccompError(msg).into())
} else {
Ok(id)
}
}
fn init(act: u32) -> Result<*mut scmp_filter_ctx> {
let filter_ctx = unsafe { seccomp_init(act) };
if filter_ctx.is_null() {
let msg = "initialization failed".to_string();
Err(ErrorKind::SeccompError(msg).into())
} else {
Ok(filter_ctx)
}
}
fn arch_add(ctx: *mut scmp_filter_ctx, arch: scmp_arch) -> ::Result<i32> {
let id = unsafe { seccomp_arch_add(ctx, arch as u32) };
if id == __NR_SCMP_ERROR {
let msg = format!("could not add arch {:?}", arch);
Err(ErrorKind::SeccompError(msg).into())
} else {
Ok(id)
}
}
fn rule_add(
ctx: *mut scmp_filter_ctx,
act: u32,
id: i32,
cmps: &[scmp_arg_cmp],
) -> Result<()> {
let res = unsafe {
let ptr = if cmps.is_empty() {
::std::ptr::null()
} else {
cmps.as_ptr()
};
seccomp_rule_add_array(ctx, act, id, cmps.len() as u32, ptr)
};
if res != 0 {
let msg = format!("failed to add rule for {}", id);
Err(ErrorKind::SeccompError(msg).into())
} else {
Ok(())
}
}
fn attr_set(
ctx: *mut scmp_filter_ctx,
attr: scmp_filter_attr,
value: u32,
) -> Result<()> {
let res = unsafe { seccomp_attr_set(ctx, attr, value) };
if res != 0 {
let msg = "failed to set_attr".to_string();
Err(ErrorKind::SeccompError(msg).into())
} else {
Ok(())
}
}
fn load(ctx: *mut scmp_filter_ctx) -> Result<()> {
let res = unsafe { seccomp_load(ctx) };
if res != 0 {
let msg = "failed to load filter".to_string();
Err(ErrorKind::SeccompError(msg).into())
} else {
Ok(())
}
}
pub fn initialize_seccomp(seccomp: &LinuxSeccomp) -> ::Result<()> {
let ctx = init(seccomp.default_action as u32)?;
// set control NoNewPrivs to false, as we deal with it separately
attr_set(ctx, scmp_filter_attr::SCMP_FLTATR_CTL_NNP, false as u32)?;
// set up architectures
for arch in &seccomp.architectures {
arch_add(ctx, to_arch(*arch))?;
}
// add actions for syscalls
for syscall in &seccomp.syscalls {
let mut names = syscall.names.clone();
if names.is_empty() {
names.push(syscall.name.clone())
};
for name in names {
let id = match syscall_resolve_name(&name) {
Ok(result) => result,
Err(e) => {
info!("Skipping unknown syscall: {}", e);
continue;
}
};
let mut cmps = Vec::new();
for arg in &syscall.args {
cmps.push(scmp_arg_cmp {
arg: arg.index as u32,
op: to_cmp(arg.op),
datum_a: arg.value as scmp_datum_t,
datum_b: arg.value_two as scmp_datum_t,
});
}
rule_add(ctx, syscall.action as u32, id, &cmps)?;
}
}
load(ctx)?;
Ok(())
}