Skip to content

Commit

Permalink
Merge pull request #25 from sai-lab/no-new-priv-runner
Browse files Browse the repository at this point in the history
Support `--security-opt=no-new-privileges` to PodmanRunner
  • Loading branch information
guni1192 authored Feb 22, 2022
2 parents 7243756 + 92a8a4e commit 7fc8aaf
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 80 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
uses: actions-rs/toolchain@v1
with:
toolchain: 1.58.1
override: true
components: rustfmt, clippy
- name: Install libraries
run: sudo apt-get install -y libelf-dev libgcc-s1 libbpf-dev clang linux-tools-common linux-tools-generic make pkg-config
Expand Down
2 changes: 1 addition & 1 deletion integration_test/sprofiler-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ tests:
shouldSuccess: true
- name: hello-go
image: ghcr.io/sai-lab/hello-go:latest
noNewPriv: true
noNewPriv: false
runtime: crun
shouldSuccess: true
- name: hello-go.no_new_priv
Expand Down
1 change: 1 addition & 0 deletions sprofiler-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod testing;
use testing::run_tests;

mod hooks;
mod podman;
mod seccomp;

#[derive(Parser, Debug)]
Expand Down
87 changes: 87 additions & 0 deletions sprofiler-test/src/podman.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use std::path::PathBuf;
use std::process::{Command, Stdio};

use anyhow::Result;
use derive_builder::Builder;
use tracing::{error, trace};

#[derive(Default, Debug, Clone, Builder)]
#[builder(pattern = "owned", setter(into, strip_option))]
pub struct PodmanRunner {
podman_path: PathBuf,
hooks_dir: PathBuf,
runtime: String,
image: String,
pub sprofiler_output: Option<PathBuf>,
debug: bool,
no_new_priv: bool,
}

impl PodmanRunner {
pub fn args(&self) -> Vec<String> {
let podman_path = format!("{}", self.podman_path.display());
let mut args = vec![podman_path];

if self.debug {
args.push(self.log_level_arg("debug"));
}

args.push(self.runtime_arg());
args.push("run".to_string());
args.push("--rm".to_string());

if self.no_new_priv {
args.push(self.no_new_priv_arg());
}

args.push(self.hooks_dir_arg());
args.push(self.sprofiler_annotation());
args.push(self.image.clone());
args
}

pub fn run(&self) -> Result<()> {
let args = self.args();
let output = Command::new(&args[0])
.args(&args[1..])
.stdout(Stdio::null())
.stderr(Stdio::null())
.output()?;

if output.status.success() {
trace!("Podman exit code: {}", output.status);
} else {
let stderr = String::from_utf8(output.stderr)?;
error!("Error: {}", stderr);
error!("Podman exit code: {}", output.status);
}
Ok(())
}

fn runtime_arg(&self) -> String {
format!("--runtime={}", self.runtime)
}

fn log_level_arg(&self, level: &str) -> String {
format!("--log-level={}", level)
}

fn hooks_dir_arg(&self) -> String {
format!("--hooks-dir={}", self.hooks_dir.display())
}

fn no_new_priv_arg(&self) -> String {
"--security-opt=no-new-privileges".to_string()
}

fn sprofiler_annotation(&self) -> String {
if let Some(sprofiler_output) = self.sprofiler_output.as_ref() {
format!(
"--annotation=\"io.sprofiler.output_seccomp_profile_path={}\"",
sprofiler_output.display()
)
} else {
"".to_string()
}
}
}
87 changes: 8 additions & 79 deletions sprofiler-test/src/testing.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::thread::sleep;
use std::time::Duration;

use anyhow::{bail, Result};
use derive_builder::Builder;
use oci_runtime_spec::{LinuxSeccomp, LinuxSeccompAction};
use serde::{Deserialize, Serialize};
use tracing::{error, info, trace};

use crate::hooks;
use crate::podman::PodmanRunnerBuilder;
use crate::seccomp;

#[derive(Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -38,77 +37,6 @@ pub struct Test {
pub image: String,
}

#[derive(Default, Debug, Clone, Builder)]
#[builder(pattern = "owned", setter(into, strip_option))]
pub struct PodmanRunner {
podman_path: PathBuf,
hooks_dir: PathBuf,
runtime: String,
image: String,
sprofiler_output: Option<PathBuf>,
debug: bool,
}

impl PodmanRunner {
fn args(&self) -> Vec<String> {
let podman_path = format!("{}", self.podman_path.display());
let mut args = vec![podman_path.to_string()];

if self.debug {
args.push(self.log_level_arg("debug"));
}

args.push(self.runtime_arg());
args.push("run".to_string());
args.push("--rm".to_string());
args.push(self.hooks_dir_arg());
args.push(self.sprofiler_annotation());
args.push(self.image.clone());
args
}

fn run(&self) -> Result<()> {
let args = self.args();
let output = Command::new(&args[0])
.args(&args[1..])
.stdout(Stdio::null())
.stderr(Stdio::null())
.output()?;

if output.status.success() {
trace!("Podman exit code: {}", output.status);
} else {
let stderr = String::from_utf8(output.stderr)?;
error!("Error: {}", stderr);
error!("Podman exit code: {}", output.status);
}
Ok(())
}

fn runtime_arg(&self) -> String {
format!("--runtime={}", self.runtime)
}

fn log_level_arg(&self, level: &str) -> String {
format!("--log-level={}", level)
}

fn hooks_dir_arg(&self) -> String {
format!("--hooks-dir={}", self.hooks_dir.display())
}

fn sprofiler_annotation(&self) -> String {
if let Some(sprofiler_output) = self.sprofiler_output.as_ref() {
format!(
"--annotation=\"io.sprofiler.output_seccomp_profile_path={}\"",
sprofiler_output.display()
)
} else {
"".to_string()
}
}
}

pub fn execute_test_case<P: AsRef<Path>>(
testcase: &Test,
podman_path: P,
Expand All @@ -126,6 +54,7 @@ where
.hooks_dir(hooks_dir)
.image(&testcase.image)
.sprofiler_output(&seccomp_profile_path)
.no_new_priv(testcase.no_new_priv)
.debug(false)
.build()?;

Expand Down Expand Up @@ -167,16 +96,17 @@ pub fn assert_seccomp_profile(testname: &str, seccomp: LinuxSeccomp) {
assert!(seccomp.syscalls.is_some());
info!("[{}] OK seccomp.syscalls.is_some()", testname);
if let Some(syscalls) = seccomp.syscalls {
assert!(syscalls.len() > 0);
info!("[{}] OK seccomp.syscalls.len() > 0", testname);
assert!(!syscalls.is_empty());
info!("[{}] OK !seccomp.syscalls.is_empty()", testname);

for syscall in syscalls {
assert!(syscall.names.len() > 0);
info!("[{}] OK seccomp.syscalls.names.len() > 0", testname);
assert!(!syscall.names.is_empty());

info!("[{}] OK !seccomp.syscalls[i].names.is_empty()", testname);

assert_eq!(syscall.action, LinuxSeccompAction::SCMP_ACT_ALLOW);
info!(
"[{}] OK seccomp.syscalls.action == SCMP_ACT_ALLOW",
"[{}] OK seccomp.syscalls[i].action == SCMP_ACT_ALLOW",
testname
);
}
Expand All @@ -197,7 +127,6 @@ pub fn run_tests(testing: Testing) -> Result<()> {
trace!("Podman Path: {}", testing.config.podman.display());

let base_dir = tempdir::TempDir::new("sprofiler-test")?;
// let base_dir = PathBuf::from("/tmp/sprofiler-test");
let hooks_dir =
hooks::create_hook_config(base_dir.path().to_path_buf(), testing.config.sprofiler)?;

Expand Down

0 comments on commit 7fc8aaf

Please sign in to comment.