generated from rust-vmm/crate-template
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for seccomp thread sync feature
- Adds SeccompFlag and SeccompFlagset with initial support for just SyncThreads/SECCOMP_FILTER_FLAG_TSYNC - Adds public functions `seccompiler::apply_filter_all_threads` and `apply_filter_with_flags` - Moves the body of apply_filter into apply_filter_with_flags Resolves #57 Signed-off-by: Harry Stern <[email protected]>
- Loading branch information
1 parent
83dcac7
commit c63ac88
Showing
5 changed files
with
193 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
use std::ops::{BitOr, BitOrAssign}; | ||
|
||
#[derive(Copy, Clone, Debug)] | ||
/// A flag accepted by the `seccomp` syscall. | ||
pub enum SeccompFlag { | ||
/// Synchronize the current filter across all threads in the process. | ||
ThreadSync, | ||
// TODO: other flags | ||
} | ||
|
||
impl SeccompFlag { | ||
fn as_u64(&self) -> u64 { | ||
// Values given in linux/seccomp.h | ||
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/seccomp.h | ||
match self { | ||
SeccompFlag::ThreadSync => 1, | ||
} | ||
} | ||
|
||
/// Convert this flag to a new [`SeccompFlagset`] containing it. | ||
pub fn to_flagset(self) -> SeccompFlagset { | ||
SeccompFlagset(self.as_u64()) | ||
} | ||
} | ||
|
||
#[derive(Copy, Clone, Debug, Default)] | ||
/// A set of [`SeccompFlag`]s to be passed to the `seccomp` syscall. | ||
pub struct SeccompFlagset(u64); | ||
|
||
impl SeccompFlagset { | ||
/// Create a new, empty SeccompFlagset. | ||
pub fn new() -> SeccompFlagset { | ||
SeccompFlagset(0) | ||
} | ||
|
||
/// Return a u64 representing the flags to be passed to the seccomp syscall. | ||
pub fn as_u64(&self) -> u64 { | ||
self.0 | ||
} | ||
} | ||
|
||
impl BitOr for SeccompFlag { | ||
type Output = SeccompFlagset; | ||
|
||
fn bitor(self, rhs: Self) -> Self::Output { | ||
SeccompFlagset(self.as_u64() | rhs.as_u64()) | ||
} | ||
} | ||
|
||
impl BitOr for SeccompFlagset { | ||
type Output = SeccompFlagset; | ||
|
||
fn bitor(self, rhs: SeccompFlagset) -> Self::Output { | ||
SeccompFlagset(self.0 | rhs.0) | ||
} | ||
} | ||
|
||
impl BitOrAssign for SeccompFlagset { | ||
fn bitor_assign(&mut self, rhs: SeccompFlagset) { | ||
self.0 |= rhs.0; | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
/// Test all the bitwise or options for SeccompFlag and SeccompFlagset | ||
fn test_bitwise() { | ||
let mut flagset = SeccompFlag::ThreadSync | SeccompFlag::ThreadSync; | ||
assert_eq!(flagset.as_u64(), 1); | ||
flagset |= SeccompFlag::ThreadSync.to_flagset() | SeccompFlag::ThreadSync.to_flagset(); | ||
assert_eq!(flagset.as_u64(), 1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#![allow(clippy::undocumented_unsafe_blocks)] | ||
|
||
/// This test is in a separate top-level test file so that it is isolated from the other tests - | ||
/// each file in the tests/ directory gets compiled to a separate binary and is run as a separate | ||
/// process. | ||
use std::collections::BTreeMap; | ||
|
||
use std::sync::mpsc::sync_channel; | ||
use std::thread; | ||
|
||
use seccompiler::{ | ||
apply_filter_all_threads, BpfProgram, SeccompAction, SeccompFilter, SeccompRule, | ||
}; | ||
use std::env::consts::ARCH; | ||
|
||
#[test] | ||
/// Test seccomp's TSYNC functionality, which syncs the current filter to all threads in the | ||
/// process. | ||
fn test_tsync() { | ||
// These channels will block on send until the receiver has called recv. | ||
let (setup_tx, setup_rx) = sync_channel::<()>(0); | ||
let (finish_tx, finish_rx) = sync_channel::<()>(0); | ||
|
||
let seccomp_thread = thread::spawn(move || { | ||
let rules = vec![(libc::SYS_getpid, vec![])]; | ||
|
||
let rule_map: BTreeMap<i64, Vec<SeccompRule>> = rules.into_iter().collect(); | ||
|
||
// Build seccomp filter only disallowing getpid | ||
let filter = SeccompFilter::new( | ||
rule_map, | ||
SeccompAction::Allow, | ||
SeccompAction::Errno(1u32), | ||
ARCH.try_into().unwrap(), | ||
) | ||
.unwrap(); | ||
|
||
let filter: BpfProgram = filter.try_into().unwrap(); | ||
apply_filter_all_threads(&filter).unwrap(); | ||
|
||
// seccomp setup done, let the other thread start | ||
setup_tx.send(()).unwrap(); | ||
|
||
// don't close this thread until the other thread is done asserting. This way we can be | ||
// sure the thread that loaded the filter is definitely active when the other thread runs. | ||
finish_rx.recv().unwrap(); | ||
println!("exit seccomp thread"); | ||
}); | ||
|
||
let test_thread = thread::spawn(move || { | ||
// wait until seccomp setup is done | ||
setup_rx.recv().unwrap(); | ||
|
||
// try to use getpid, which we have disallowed on another thread | ||
let pid = unsafe { libc::getpid() }; | ||
let errno = std::io::Error::last_os_error().raw_os_error().unwrap(); | ||
|
||
assert_eq!(pid, -1, "getpid should return -1 as set in SeccompFilter"); | ||
assert_eq!(errno, 0, "there should be no errors"); | ||
|
||
// let other thread know we've passed | ||
finish_tx.send(()).unwrap(); | ||
println!("exit io thread"); | ||
}); | ||
|
||
let seccomp_res = seccomp_thread.join(); | ||
assert!( | ||
seccomp_res.is_ok(), | ||
"seccomp thread failed: {:?}", | ||
seccomp_res.unwrap_err() | ||
); | ||
let test_res = test_thread.join(); | ||
assert!( | ||
test_res.is_ok(), | ||
"test thread failed: {:?}", | ||
test_res.unwrap_err() | ||
); | ||
} |