forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
2.3 KiB
1//! The container's executor. It installs the seccomp filter, then execs the job.
2//!
3//! This replaces libcontainer's `DefaultExecutor::exec`, which does the same exec without a
4//! filter. libcontainer runs the executor in the init process after the namespaces, mounts and
5//! `no_new_privileges` are set up, and right before the job starts. `seccompiler::apply_filter`
6//! also sets `PR_SET_NO_NEW_PRIVS` itself, so an unprivileged install works.
7
8use std::ffi::CString;
9
10use libcontainer::workload::default::DefaultExecutor;
11use libcontainer::workload::{Executor, ExecutorError, ExecutorValidationError};
12use nix::unistd;
13use oci_spec::runtime::Spec;
14use seccompiler::BpfProgram;
15
16/// Installs `filter` and execs the spec's process. The filter is built by the helper before the
17/// container forks, so this only installs it.
18#[derive(Clone)]
19pub struct FilteredExecutor {
20 filter: BpfProgram,
21}
22
23impl FilteredExecutor {
24 pub fn new(filter: BpfProgram) -> Self {
25 Self { filter }
26 }
27}
28
29impl Executor for FilteredExecutor {
30 fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> {
31 seccompiler::apply_filter(&self.filter)
32 .map_err(|e| ExecutorError::Other(format!("cannot install seccomp filter: {e}")))?;
33 exec_process(spec)
34 }
35
36 fn validate(&self, spec: &Spec) -> Result<(), ExecutorValidationError> {
37 // The same checks as libcontainer's default executor: the process exists in PATH.
38 DefaultExecutor {}.validate(spec)
39 }
40}
41
42/// Replaces the process with `args[0]`, as libcontainer's default executor does. It returns only
43/// on failure.
44fn exec_process(spec: &Spec) -> Result<(), ExecutorError> {
45 let args = spec
46 .process()
47 .as_ref()
48 .and_then(|p| p.args().as_ref())
49 .ok_or(ExecutorError::InvalidArg)?;
50 let path = args.first().ok_or(ExecutorError::InvalidArg)?;
51 let path = CString::new(path.as_bytes()).map_err(|_| ExecutorError::InvalidArg)?;
52 let argv = args
53 .iter()
54 .map(|s| CString::new(s.as_bytes()).map_err(|_| ExecutorError::InvalidArg))
55 .collect::<Result<Vec<CString>, ExecutorError>>()?;
56 match unistd::execvp(&path, &argv) {
57 Ok(never) => match never {},
58 Err(err) => Err(ExecutorError::Other(format!(
59 "cannot exec {}: {err}",
60 path.to_string_lossy()
61 ))),
62 }
63}