Skip to content

Add support for seccomp_unotify #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
## Added
- [[#72]](https://github.com/rust-vmm/seccompiler/pull/72): Introduce RISC-V
64-bit architecture support.
- [[#75]](https://github.com/rust-vmm/seccompiler/pull/75): Support for `seccomp_unotify`.

## Changed
- [[#78]](https://github.com/rust-vmm/seccompiler/pull/78): Update
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ edition = "2021"

[features]
json = ["serde", "serde_json"]
seccomp_unotify = []

[dependencies]
libc = "^0.2.153"
Expand Down
9 changes: 9 additions & 0 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ use libc::{
SECCOMP_RET_KILL_THREAD, SECCOMP_RET_LOG, SECCOMP_RET_TRACE, SECCOMP_RET_TRAP,
};

// Not available in the libc crate yet.
#[cfg(feature = "seccomp_unotify")]
const SECCOMP_RET_USER_NOTIF: libc::c_uint = 0x7fc00000;

use bpf::{ARG_NUMBER_MAX, AUDIT_ARCH_AARCH64, AUDIT_ARCH_RISCV64, AUDIT_ARCH_X86_64, BPF_MAX_LEN};

pub use bpf::{sock_filter, BpfProgram, BpfProgramRef};
Expand Down Expand Up @@ -166,6 +170,9 @@ pub enum SeccompAction {
Trace(u32),
/// Sends `SIGSYS` to the calling process.
Trap,
/// Sends a notification to a supervisory process.
#[cfg(feature = "seccomp_unotify")]
Notify,
}

impl From<SeccompAction> for u32 {
Expand All @@ -185,6 +192,8 @@ impl From<SeccompAction> for u32 {
SeccompAction::Log => SECCOMP_RET_LOG,
SeccompAction::Trace(x) => SECCOMP_RET_TRACE | (x & SECCOMP_RET_DATA),
SeccompAction::Trap => SECCOMP_RET_TRAP,
#[cfg(feature = "seccomp_unotify")]
SeccompAction::Notify => SECCOMP_RET_USER_NOTIF,
}
}
}
Expand Down
40 changes: 30 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ use std::convert::TryInto;
#[cfg(feature = "json")]
use std::io::Read;

#[cfg(feature = "seccomp_unotify")]
use std::os::fd::{FromRawFd as _, OwnedFd};

use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::io;
Expand Down Expand Up @@ -310,7 +313,8 @@ impl From<JsonFrontendError> for Error {
///
/// [`BpfProgram`]: type.BpfProgram.html
pub fn apply_filter(bpf_filter: BpfProgramRef) -> Result<()> {
apply_filter_with_flags(bpf_filter, 0)
apply_filter_with_flags(bpf_filter, 0)?;
Ok(())
}

/// Apply a BPF filter to the all threads in the process via the TSYNC feature. Please read the
Expand All @@ -322,7 +326,28 @@ pub fn apply_filter(bpf_filter: BpfProgramRef) -> Result<()> {
///
/// [`BpfProgram`]: type.BpfProgram.html
pub fn apply_filter_all_threads(bpf_filter: BpfProgramRef) -> Result<()> {
apply_filter_with_flags(bpf_filter, libc::SECCOMP_FILTER_FLAG_TSYNC)
let rc = apply_filter_with_flags(bpf_filter, libc::SECCOMP_FILTER_FLAG_TSYNC)?;

if rc > 0 {
return Err(Error::ThreadSync(rc));
}

Ok(())
}

/// Apply a filter with the SECCOMP_FILTER_FLAG_NEW_LISTENER flag.
///
/// The returned FD can be polled for notifications generated by a rule with the
/// action [SeccompAction::Notify]. See `man 2 seccomp_unotify` for more
/// information.
#[cfg(feature = "seccomp_unotify")]
pub fn apply_filter_with_notify_fd(bpf_filter: BpfProgramRef) -> Result<OwnedFd> {
let rc = apply_filter_with_flags(bpf_filter, libc::SECCOMP_FILTER_FLAG_NEW_LISTENER)?;

// SAFETY: seccomp_unotify documents that it returns a valid FD if the
// syscall is a success.
let fd = unsafe { OwnedFd::from_raw_fd(rc as _) };
Ok(fd)
}

/// Apply a BPF filter to the calling thread.
Expand All @@ -333,7 +358,7 @@ pub fn apply_filter_all_threads(bpf_filter: BpfProgramRef) -> Result<()> {
/// * `flags` - A u64 representing a bitset of seccomp's flags parameter.
///
/// [`BpfProgram`]: type.BpfProgram.html
fn apply_filter_with_flags(bpf_filter: BpfProgramRef, flags: libc::c_ulong) -> Result<()> {
fn apply_filter_with_flags(bpf_filter: BpfProgramRef, flags: libc::c_ulong) -> Result<i64> {
// If the program is empty, don't install the filter.
if bpf_filter.is_empty() {
return Err(Error::EmptyFilter);
Expand Down Expand Up @@ -364,16 +389,11 @@ fn apply_filter_with_flags(bpf_filter: BpfProgramRef, flags: libc::c_ulong) -> R
)
};

#[allow(clippy::comparison_chain)]
// Per manpage, if TSYNC fails, retcode is >0 and equals the pid of the thread that caused the
// failure. Otherwise, error code is -1 and errno is set.
if rc < 0 {
return Err(Error::Seccomp(io::Error::last_os_error()));
} else if rc > 0 {
return Err(Error::ThreadSync(rc));
return Err(Error::Seccomp(std::io::Error::last_os_error()));
}

Ok(())
Ok(rc)
}

/// Compile [`BpfProgram`]s from JSON.
Expand Down