1
0
mirror of https://github.com/containers/youki synced 2024-11-23 09:21:57 +01:00

Merge branch 'main' of github.com:containers/youki into improvement/refactor-dir-structure

This commit is contained in:
Yashodhan Joshi 2022-02-23 18:10:39 +05:30
commit 40e7b74a65
15 changed files with 450 additions and 166 deletions

@ -109,12 +109,6 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Cache runtime-tools
id: cache-runtime-tools
uses: actions/cache@v2
with:
path: integration_test
key: ${{ runner.os }}-${{ matrix.rust }}-primes
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}

4
.gitpod.Dockerfile vendored

@ -6,4 +6,6 @@ RUN sudo apt-get update && sudo apt-get install -y \
libdbus-1-dev \
build-essential \
libelf-dev \
libseccomp-dev
libseccomp-dev
RUN rustup component add clippy rls rust-analysis rust-src rust-docs rustfmt

@ -6,4 +6,7 @@ tasks:
github:
prebuilds:
pullRequestsFromForks: true
addBadge: true
addBadge: true
vscode:
extensions:
- matklad.rust-analyzer

163
crates/Cargo.lock generated

@ -39,9 +39,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.54"
version = "1.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a99269dff3bc004caa411f38845c20303f1e393ca2bd6581576fa3a7f59577d"
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
[[package]]
name = "ascii"
@ -174,9 +174,9 @@ dependencies = [
[[package]]
name = "clap"
version = "3.1.0"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5f1fea81f183005ced9e59cdb01737ef2423956dac5a6d731b06b2ecfaa3467"
checksum = "6d76c22c9b9b215eeb8d016ad3a90417bd13cb24cf8142756e6472445876cab7"
dependencies = [
"atty",
"bitflags",
@ -468,12 +468,24 @@ dependencies = [
"syn",
]
[[package]]
name = "difflib"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "discard"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "downcast"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
[[package]]
name = "either"
version = "1.6.1"
@ -598,6 +610,15 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "float-cmp"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
dependencies = [
"num-traits",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -614,6 +635,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fragile"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da1b8f89c5b5a5b7e59405cfcf0bb9588e5ed19f0b57a4cd542bbba3f164a6d"
[[package]]
name = "futures"
version = "0.3.21"
@ -715,9 +742,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.4"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if 1.0.0",
"libc",
@ -845,6 +872,15 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.1"
@ -910,6 +946,7 @@ dependencies = [
"libbpf-sys",
"libc",
"log",
"mockall",
"nix",
"oci-spec",
"procfs",
@ -917,6 +954,7 @@ dependencies = [
"rbpf",
"serde",
"serde_json",
"serial_test 0.5.1",
]
[[package]]
@ -944,7 +982,7 @@ dependencies = [
"rand",
"serde",
"serde_json",
"serial_test",
"serial_test 0.6.0",
"wasmer",
"wasmer-wasi",
]
@ -1117,6 +1155,33 @@ dependencies = [
"winapi",
]
[[package]]
name = "mockall"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d4d70639a72f972725db16350db56da68266ca368b2a1fe26724a903ad3d6b8"
dependencies = [
"cfg-if 1.0.0",
"downcast",
"fragile",
"lazy_static",
"mockall_derive",
"predicates",
"predicates-tree",
]
[[package]]
name = "mockall_derive"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79ef208208a0dea3f72221e26e904cdc6db2e481d9ade89081ddd494f1dbaa6b"
dependencies = [
"cfg-if 1.0.0",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "more-asserts"
version = "0.2.2"
@ -1136,6 +1201,12 @@ dependencies = [
"memoffset",
]
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "ntapi"
version = "0.3.7"
@ -1295,6 +1366,36 @@ dependencies = [
"nix",
]
[[package]]
name = "predicates"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
dependencies = [
"difflib",
"float-cmp",
"itertools",
"normalize-line-endings",
"predicates-core",
"regex",
]
[[package]]
name = "predicates-core"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
[[package]]
name = "predicates-tree"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
dependencies = [
"predicates-core",
"termtree",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@ -1525,9 +1626,9 @@ dependencies = [
[[package]]
name = "rkyv"
version = "0.7.32"
version = "0.7.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e3791595bf1ee951356964271bea7dafd1e1730e8be812f44a31afc38fa7bba"
checksum = "bf98e3e6c7ed44e474b454b1ebded3193ee5aba3428e29c55d59b1d65e49945e"
dependencies = [
"bytecheck",
"hashbrown 0.12.0",
@ -1539,9 +1640,9 @@ dependencies = [
[[package]]
name = "rkyv_derive"
version = "0.7.32"
version = "0.7.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca655472e721430bfb5c995a5602278e089c329cde96a0a53e1f711e3ba39c55"
checksum = "cc9940ec6a7c62b1d1f476f607c6caf0d7fbf74e43f77bc022143b878fcd3266"
dependencies = [
"proc-macro2",
"quote",
@ -1575,7 +1676,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.5",
"semver 1.0.6",
]
[[package]]
@ -1613,9 +1714,9 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7"
checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
[[package]]
name = "semver-parser"
@ -1671,7 +1772,18 @@ checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
dependencies = [
"lazy_static",
"parking_lot",
"serial_test_derive",
"serial_test_derive 0.5.1",
]
[[package]]
name = "serial_test"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5bcc41d18f7a1d50525d080fd3e953be87c4f9f1a974f3c21798ca00d54ec15"
dependencies = [
"lazy_static",
"parking_lot",
"serial_test_derive 0.6.0",
]
[[package]]
@ -1685,6 +1797,19 @@ dependencies = [
"syn",
]
[[package]]
name = "serial_test_derive"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2881bccd7d60fb32dfa3d7b3136385312f8ad75e2674aab2852867a09790cae8"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "sha1"
version = "0.6.1"
@ -1845,6 +1970,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "termtree"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
[[package]]
name = "textwrap"
version = "0.14.2"
@ -2413,7 +2544,7 @@ dependencies = [
"procfs",
"serde",
"serde_json",
"serial_test",
"serial_test 0.6.0",
"tabwriter",
"vergen",
]

@ -24,12 +24,14 @@ serde = { version = "1.0", features = ["derive"] }
rbpf = {version = "0.1.0", optional = true }
libbpf-sys = { version = "0.6.1-2", optional = true }
errno = { version = "0.2.8", optional = true }
libc = { version = "0.2.118", optional = true }
libc = { version = "0.2.119", optional = true }
[dev-dependencies]
oci-spec = { version = "0.5.3", features = ["proptests"] }
quickcheck = "1"
mockall = { version = "0.11.0", features = [] }
clap = "3.0.0-beta.5"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
env_logger = "0.9"
serial_test = "0.5.1"

@ -4,6 +4,11 @@
#[cfg(test)]
#[macro_use]
extern crate quickcheck;
#[cfg(test)]
#[macro_use]
extern crate mockall;
mod test;
pub mod common;

@ -1,117 +1,124 @@
use anyhow::{bail, Result};
use std::os::unix::io::RawFd;
use std::ptr;
// FIXME: add tests
pub fn prog_load(license: &str, insns: &[u8]) -> Result<RawFd> {
let insns_cnt = insns.len() / std::mem::size_of::<libbpf_sys::bpf_insn>();
let insns = insns as *const _ as *const libbpf_sys::bpf_insn;
let prog_fd = unsafe {
libbpf_sys::bpf_load_program(
libbpf_sys::BPF_PROG_TYPE_CGROUP_DEVICE,
insns,
insns_cnt as u64,
license as *const _ as *const i8,
0,
ptr::null_mut::<i8>(),
0,
)
};
if prog_fd < 0 {
return Err(errno::errno().into());
}
Ok(prog_fd)
}
#[derive(Clone)]
pub struct ProgramInfo {
pub id: u32,
pub fd: i32,
}
pub fn prog_query(cgroup_fd: RawFd) -> Result<Vec<ProgramInfo>> {
let mut prog_ids: Vec<u32> = vec![0_u32; 64];
let mut attach_flags = 0_u32;
for _ in 0..10 {
let mut prog_cnt = prog_ids.len() as u32;
let ret = unsafe {
libbpf_sys::bpf_prog_query(
cgroup_fd,
libbpf_sys::BPF_CGROUP_DEVICE,
#[cfg_attr(test, automock)]
pub mod prog {
use super::ProgramInfo;
use anyhow::{bail, Result};
use std::os::unix::io::RawFd;
use std::ptr;
pub fn load(license: &str, insns: &[u8]) -> Result<RawFd> {
let insns_cnt = insns.len() / std::mem::size_of::<libbpf_sys::bpf_insn>();
let insns = insns as *const _ as *const libbpf_sys::bpf_insn;
let prog_fd = unsafe {
libbpf_sys::bpf_load_program(
libbpf_sys::BPF_PROG_TYPE_CGROUP_DEVICE,
insns,
insns_cnt as u64,
license as *const _ as *const i8,
0,
ptr::null_mut::<i8>(),
0,
&mut attach_flags,
&prog_ids[0] as *const u32 as *mut u32,
&mut prog_cnt,
)
};
if ret != 0 {
let err = errno::errno();
if err.0 == libc::ENOSPC {
assert!(prog_cnt as usize > prog_ids.len());
// allocate more space and try again
prog_ids.resize(prog_cnt as usize, 0);
continue;
if prog_fd < 0 {
return Err(errno::errno().into());
}
Ok(prog_fd)
}
/// Given a fd for a cgroup, collect the programs associated with it
pub fn query(cgroup_fd: RawFd) -> Result<Vec<ProgramInfo>> {
let mut prog_ids: Vec<u32> = vec![0_u32; 64];
let mut attach_flags = 0_u32;
for _ in 0..10 {
let mut prog_cnt = prog_ids.len() as u32;
let ret = unsafe {
// collect ids for bpf programs
libbpf_sys::bpf_prog_query(
cgroup_fd,
libbpf_sys::BPF_CGROUP_DEVICE,
0,
&mut attach_flags,
&prog_ids[0] as *const u32 as *mut u32,
&mut prog_cnt,
)
};
if ret != 0 {
let err = errno::errno();
if err.0 == libc::ENOSPC {
assert!(prog_cnt as usize > prog_ids.len());
// allocate more space and try again
prog_ids.resize(prog_cnt as usize, 0);
continue;
}
return Err(err.into());
}
return Err(err.into());
prog_ids.resize(prog_cnt as usize, 0);
break;
}
prog_ids.resize(prog_cnt as usize, 0);
break;
}
let mut prog_fds = Vec::with_capacity(prog_ids.len());
for prog_id in &prog_ids {
let prog_fd = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(*prog_id) };
if prog_fd < 0 {
log::debug!("bpf_prog_get_fd_by_id failed: {}", errno::errno());
continue;
let mut prog_fds = Vec::with_capacity(prog_ids.len());
for prog_id in &prog_ids {
// collect fds for programs by getting their ids
let prog_fd = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(*prog_id) };
if prog_fd < 0 {
log::debug!("bpf_prog_get_fd_by_id failed: {}", errno::errno());
continue;
}
prog_fds.push(ProgramInfo {
id: *prog_id,
fd: prog_fd,
});
}
prog_fds.push(ProgramInfo {
id: *prog_id,
fd: prog_fd,
});
}
Ok(prog_fds)
}
pub fn prog_detach2(prog_fd: RawFd, cgroup_fd: RawFd) -> Result<()> {
let ret =
unsafe { libbpf_sys::bpf_prog_detach2(prog_fd, cgroup_fd, libbpf_sys::BPF_CGROUP_DEVICE) };
if ret != 0 {
return Err(errno::errno().into());
}
Ok(())
}
pub fn prog_attach(prog_fd: RawFd, cgroup_fd: RawFd) -> Result<()> {
let ret = unsafe {
libbpf_sys::bpf_prog_attach(
prog_fd,
cgroup_fd,
libbpf_sys::BPF_CGROUP_DEVICE,
libbpf_sys::BPF_F_ALLOW_MULTI,
)
};
if ret != 0 {
return Err(errno::errno().into());
}
Ok(())
}
pub fn bump_memlock_rlimit() -> Result<()> {
let rlimit = libc::rlimit {
rlim_cur: 128 << 20,
rlim_max: 128 << 20,
};
if unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlimit) } != 0 {
bail!("Failed to increase rlimit");
Ok(prog_fds)
}
Ok(())
pub fn detach2(prog_fd: RawFd, cgroup_fd: RawFd) -> Result<()> {
let ret = unsafe {
libbpf_sys::bpf_prog_detach2(prog_fd, cgroup_fd, libbpf_sys::BPF_CGROUP_DEVICE)
};
if ret != 0 {
return Err(errno::errno().into());
}
Ok(())
}
pub fn attach(prog_fd: RawFd, cgroup_fd: RawFd) -> Result<()> {
let ret = unsafe {
libbpf_sys::bpf_prog_attach(
prog_fd,
cgroup_fd,
libbpf_sys::BPF_CGROUP_DEVICE,
libbpf_sys::BPF_F_ALLOW_MULTI,
)
};
if ret != 0 {
return Err(errno::errno().into());
}
Ok(())
}
pub fn bump_memlock_rlimit() -> Result<()> {
let rlimit = libc::rlimit {
rlim_cur: 128 << 20,
rlim_max: 128 << 20,
};
if unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlimit) } != 0 {
bail!("Failed to increase rlimit");
}
Ok(())
}
}

@ -11,6 +11,12 @@ use oci_spec::runtime::LinuxDeviceCgroup;
use crate::common::{default_allow_devices, default_devices, ControllerOpt};
use crate::v2::controller::Controller;
#[cfg(test)]
use bpf::mock_prog as bpf_prog;
#[cfg(not(test))]
use bpf::prog as bpf_prog;
const LICENSE: &str = "Apache";
pub struct Devices {}
@ -57,8 +63,8 @@ impl Devices {
// Increase `ulimit -l` limit to avoid BPF_PROG_LOAD error (#2167).
// This limit is not inherited into the container.
bpf::bump_memlock_rlimit()?;
let prog_fd = bpf::prog_load(LICENSE, prog.bytecodes())?;
bpf_prog::bump_memlock_rlimit()?;
let prog_fd = bpf_prog::load(LICENSE, prog.bytecodes())?;
// FIXME: simple way to attach BPF program
// 1. get list of existing attached programs
@ -73,20 +79,99 @@ impl Devices {
// IMHO, this is too complicated, and in most cases, we just attach program once without
// already attached programs.
// get the fd of the cgroup root
let fd = nix::dir::Dir::open(
cgroup_root.as_os_str(),
OFlag::O_RDONLY | OFlag::O_DIRECTORY,
Mode::from_bits(0o600).unwrap(),
)?;
let old_progs = bpf::prog_query(fd.as_raw_fd())?;
bpf::prog_attach(prog_fd, fd.as_raw_fd())?;
// collect the programs attached to this cgroup
let old_progs = bpf_prog::query(fd.as_raw_fd())?;
// attach our new program
bpf_prog::attach(prog_fd, fd.as_raw_fd())?;
// detach all previous programs
for old_prog in old_progs {
bpf::prog_detach2(old_prog.fd, fd.as_raw_fd())?;
bpf_prog::detach2(old_prog.fd, fd.as_raw_fd())?;
}
Ok(())
}
}
// FIXME: add tests, but how to?
#[cfg(test)]
mod tests {
use super::*;
use crate::test::setup;
use serial_test::serial;
use oci_spec::runtime::{LinuxDeviceCgroupBuilder, LinuxDeviceType};
use std::os::unix::io::RawFd;
use bpf::mock_prog;
#[test]
#[serial(bpf)] // mock contexts are shared
fn test_apply_devices() {
// arrange
let (tmp, _) = setup("test_apply_devices", "some.value");
let a_type = LinuxDeviceCgroupBuilder::default()
.typ(LinuxDeviceType::A)
.build()
.unwrap();
let file_descriptor: RawFd = 6;
// expect
let bump_memlock_rlimit = mock_prog::bump_memlock_rlimit_context();
let load = mock_prog::load_context();
let query = mock_prog::query_context();
let attach = mock_prog::attach_context();
let detach2 = mock_prog::detach2_context();
bump_memlock_rlimit.expect().once().returning(|| Ok(()));
load.expect()
.once()
.returning(move |_, _| Ok(file_descriptor));
query.expect().once().returning(|_| Ok(vec![]));
attach.expect().once().returning(|_, _| Ok(()));
detach2.expect().never();
// act
Devices::apply_devices(&tmp, &Some(vec![a_type])).expect("Could not apply devices");
}
#[test]
#[serial(bpf)] // mock contexts are shared
fn test_existing_programs() {
// arrange
let (tmp, _) = setup("test_existing_programs", "some.value");
let a_type = LinuxDeviceCgroupBuilder::default()
.typ(LinuxDeviceType::A)
.build()
.unwrap();
let file_descriptor: RawFd = 6;
let existing_program_1 = bpf::ProgramInfo {
id: u32::default(),
fd: i32::default(),
};
// expect
let bump_memlock_rlimit = mock_prog::bump_memlock_rlimit_context();
let load = mock_prog::load_context();
let query = mock_prog::query_context();
let attach = mock_prog::attach_context();
let detach2 = mock_prog::detach2_context();
bump_memlock_rlimit.expect().once().returning(|| Ok(()));
load.expect()
.once()
.returning(move |_, _| Ok(file_descriptor));
query
.expect()
.once()
.returning(move |_| Ok(vec![existing_program_1.clone()]));
attach.expect().once().returning(|_, _| Ok(()));
detach2.expect().once().returning(|_, _| Ok(()));
// act
Devices::apply_devices(&tmp, &Some(vec![a_type])).expect("Could not apply devices");
}
}

@ -5,7 +5,7 @@ use std::{
time::Duration,
};
use anyhow::Result;
use anyhow::{Context, Result};
use nix::unistd::Pid;
@ -30,6 +30,9 @@ use crate::{
common::{self, CgroupManager, ControllerOpt, FreezerState, PathBufExt, CGROUP_PROCS},
stats::{Stats, StatsProvider},
};
pub const CGROUP_KILL: &str = "cgroup.kill";
pub struct Manager {
root_path: PathBuf,
cgroup_path: PathBuf,
@ -127,12 +130,17 @@ impl CgroupManager for Manager {
fn remove(&self) -> Result<()> {
if self.full_path.exists() {
log::debug!("remove cgroup {:?}", self.full_path);
let procs_path = self.full_path.join(CGROUP_PROCS);
let procs = fs::read_to_string(&procs_path)?;
let kill_file = self.full_path.join(CGROUP_KILL);
if kill_file.exists() {
fs::write(kill_file, "1").context("failed to kill cgroup")?;
} else {
let procs_path = self.full_path.join(CGROUP_PROCS);
let procs = fs::read_to_string(&procs_path)?;
for line in procs.lines() {
let pid: i32 = line.parse()?;
let _ = nix::sys::signal::kill(Pid::from_raw(pid), nix::sys::signal::SIGKILL);
for line in procs.lines() {
let pid: i32 = line.parse()?;
let _ = nix::sys::signal::kill(Pid::from_raw(pid), nix::sys::signal::SIGKILL);
}
}
common::delete_with_retry(&self.full_path, 4, Duration::from_millis(100))?;

@ -19,7 +19,7 @@ crossbeam-channel = "0.5"
dbus = "0.9.5"
fastrand = "1.7.0"
futures = { version = "0.3", features = ["thread-pool"] }
libc = "0.2.118"
libc = "0.2.119"
log = "0.4"
mio = { version = "0.8.0", features = ["os-ext", "os-poll"] }
nix = "0.23.1"
@ -37,5 +37,5 @@ wasmer-wasi = { version = "2.1.1", optional = true }
[dev-dependencies]
oci-spec = { version = "0.5.3", features = ["proptests"] }
quickcheck = "1"
serial_test = "0.5.1"
serial_test = "0.6.0"
rand = "0.8.5"

@ -170,6 +170,42 @@ impl FilterContext {
}
};
}
/// Enable or disable the no new privileges attribute bit.
pub fn set_nnp_bit(&self, to: bool) -> Result<()> {
self.set_attr(scmp_filter_attr::SCMP_FLTATR_CTL_NNP, to as u32)
.context("set no new privileges bit")
}
/// Enable or disable the log attribute bit.
pub fn set_log_bit(&self, to: bool) -> Result<()> {
self.set_attr(scmp_filter_attr::SCMP_FLTATR_CTL_LOG, to as u32)
.context("set log bit")
}
/// Enable or disable the tsync attribute bit.
pub fn set_tsync_bit(&self, to: bool) -> Result<()> {
self.set_attr(scmp_filter_attr::SCMP_FLTATR_CTL_TSYNC, to as u32)
.context("set tsync bit")
}
/// Enable or disable the SSB (Speculative Store Bypass) attribute bit.
pub fn set_ssb_bit(&self, to: bool) -> Result<()> {
self.set_attr(scmp_filter_attr::SCMP_FLTATR_CTL_SSB, to as u32)
.context("set SSB bit")
}
/// Can be used to set any arbitrary seccomp filter attribute.
pub fn set_attr(&self, attr: scmp_filter_attr, value: u32) -> Result<()> {
let res = unsafe { seccomp_attr_set(self.ctx, attr, value) };
if res != 0 {
bail!(
"unable to set attribute on seccomp filter: {}",
nix::errno::from_i32(res)
)
}
Ok(())
}
}
fn translate_syscall(syscall_name: &str) -> Result<i32> {
@ -261,17 +297,42 @@ fn check_seccomp(seccomp: &LinuxSeccomp) -> Result<()> {
Ok(())
}
pub fn initialize_seccomp(seccomp: &LinuxSeccomp) -> Result<Option<io::RawFd>> {
if seccomp.flags().is_some() {
// runc did not support this, so let's skip it for now.
bail!("seccomp flags are not yet supported");
}
/// All filter return actions except SECCOMP_RET_ALLOW should be logged. An administrator may
/// override this filter flag by preventing specific actions from being logged via the
/// /proc/sys/kernel/seccomp/actions_logged file. (since Linux 4.14)
const SECCOMP_FILTER_FLAG_LOG: &str = "SECCOMP_FILTER_FLAG_LOG";
/// When adding a new filter, synchronize all other threads of the calling process to the same
/// seccomp filter tree. A "filter tree" is the ordered list of filters attached to a thread.
/// (Attaching identical filters in separate seccomp() calls results in different filters from this
/// perspective.)
///
/// If any thread cannot synchronize to the same filter tree, the call will not attach the new
/// seccomp filter, and will fail, returning the first thread ID found that cannot synchronize.
/// Synchronization will fail if another thread in the same process is in SECCOMP_MODE_STRICT or if
/// it has attached new seccomp filters to itself, diverging from the calling thread's filter tree.
const SECCOMP_FILTER_FLAG_TSYNC: &str = "SECCOMP_FILTER_FLAG_TSYNC";
/// Disable Speculative Store Bypass mitigation. (since Linux 4.17)
const SECCOMP_FILTER_FLAG_SPEC_ALLOW: &str = "SECCOMP_FILTER_FLAG_SPEC_ALLOW";
pub fn initialize_seccomp(seccomp: &LinuxSeccomp) -> Result<Option<io::RawFd>> {
check_seccomp(seccomp)?;
let default_action = translate_action(seccomp.default_action(), seccomp.default_errno_ret());
let mut ctx = FilterContext::default(default_action)?;
if let Some(flags) = seccomp.flags() {
for flag in flags {
match flag.as_ref() {
SECCOMP_FILTER_FLAG_LOG => ctx.set_log_bit(true)?,
SECCOMP_FILTER_FLAG_TSYNC => ctx.set_tsync_bit(true)?,
SECCOMP_FILTER_FLAG_SPEC_ALLOW => ctx.set_ssb_bit(true)?,
f => bail!("seccomp flag {} is not supported", f),
}
}
}
if let Some(architectures) = seccomp.architectures() {
for &arch in architectures {
let arch_token = translate_arch(arch);
@ -287,13 +348,7 @@ pub fn initialize_seccomp(seccomp: &LinuxSeccomp) -> Result<Option<io::RawFd>> {
// set it here. If the seccomp load operation fails without enough
// privilege, so be it. To prevent this automatic behavior, we unset the
// value here.
let ret = unsafe { seccomp_attr_set(ctx.ctx, scmp_filter_attr::SCMP_FLTATR_CTL_NNP, 0) };
if ret != 0 {
bail!(
"failed to unset the no new privileges bit for seccomp: {}",
ret
);
}
ctx.set_nnp_bit(false)?;
if let Some(syscalls) = seccomp.syscalls() {
for syscall in syscalls {

@ -7,7 +7,7 @@ use std::sync::Arc;
use std::{any::Any, mem, path::Path, ptr};
use anyhow::{anyhow, bail, Result};
use caps::{CapSet, Capability, CapsHashSet};
use caps::{CapSet, CapsHashSet};
use libc::{c_char, uid_t};
use nix::{
errno::Errno,
@ -132,15 +132,7 @@ impl Syscall for LinuxSyscall {
// for each such =, drop that capability
// after this, only those which are to be set will remain set
for c in all.difference(value) {
match c {
Capability::CAP_PERFMON
| Capability::CAP_CHECKPOINT_RESTORE
| Capability::CAP_BPF => {
log::warn!("{:?} is not supported.", c);
continue;
}
_ => caps::drop(None, CapSet::Bounding, *c)?,
}
caps::drop(None, CapSet::Bounding, *c)?
}
}
_ => {

@ -6,7 +6,7 @@ edition = "2021"
build = "build.rs"
[dependencies]
libc = "0.2.118"
libc = "0.2.119"
[build-dependencies]
pkg-config = "0.3.24"

@ -13,7 +13,7 @@ features = ["std", "suggestions", "derive", "cargo"]
[dependencies]
anyhow = "1.0.53"
anyhow = "1.0.55"
chrono = { version="0.4", features = ["serde"] }
libcgroups = { version = "0.0.2", path = "../libcgroups" }
libcontainer = { version = "0.0.2", path = "../libcontainer" }
@ -30,8 +30,8 @@ tabwriter = "1"
clap_generate = { version = "3.0.0-beta.5" }
[dev-dependencies]
serial_test = "0.5.1"
serial_test = "0.6.0"
[build-dependencies]
anyhow = "1.0.53"
anyhow = "1.0.55"
vergen = "6.0"

@ -6,5 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.53"
anyhow = "1.0.55"
crossbeam = "0.8.1"