Skip to content

Commit ea5e310

Browse files
committed
Add support for seccomp_unotify
This allows users to install rules which notify a supervisory process. See https://man7.org/linux/man-pages/man2/seccomp_unotify.2.html. Signed-off-by: Colin Marc <hi@colinmarc.com>
1 parent c3cf77d commit ea5e310

File tree

4 files changed

+41
-10
lines changed

4 files changed

+41
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
## Added
66
- [[#72]](https://github.com/rust-vmm/seccompiler/pull/72): Introduce RISC-V
77
64-bit architecture support.
8+
- [[#75]](https://github.com/rust-vmm/seccompiler/pull/75): Support for `seccomp_unotify`.
89

910
## Changed
1011
- [[#78]](https://github.com/rust-vmm/seccompiler/pull/78): Update

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ edition = "2021"
1111

1212
[features]
1313
json = ["serde", "serde_json"]
14+
seccomp_unotify = []
1415

1516
[dependencies]
1617
libc = "^0.2.153"

src/backend/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ use libc::{
2525
SECCOMP_RET_KILL_THREAD, SECCOMP_RET_LOG, SECCOMP_RET_TRACE, SECCOMP_RET_TRAP,
2626
};
2727

28+
// Not available in the libc crate yet.
29+
#[cfg(feature = "seccomp_unotify")]
30+
const SECCOMP_RET_USER_NOTIF: libc::c_uint = 0x7fc00000;
31+
2832
use bpf::{ARG_NUMBER_MAX, AUDIT_ARCH_AARCH64, AUDIT_ARCH_RISCV64, AUDIT_ARCH_X86_64, BPF_MAX_LEN};
2933

3034
pub use bpf::{sock_filter, BpfProgram, BpfProgramRef};
@@ -166,6 +170,9 @@ pub enum SeccompAction {
166170
Trace(u32),
167171
/// Sends `SIGSYS` to the calling process.
168172
Trap,
173+
/// Sends a notification to a supervisory process.
174+
#[cfg(feature = "seccomp_unotify")]
175+
Notify,
169176
}
170177

171178
impl From<SeccompAction> for u32 {
@@ -185,6 +192,8 @@ impl From<SeccompAction> for u32 {
185192
SeccompAction::Log => SECCOMP_RET_LOG,
186193
SeccompAction::Trace(x) => SECCOMP_RET_TRACE | (x & SECCOMP_RET_DATA),
187194
SeccompAction::Trap => SECCOMP_RET_TRAP,
195+
#[cfg(feature = "seccomp_unotify")]
196+
SeccompAction::Notify => SECCOMP_RET_USER_NOTIF,
188197
}
189198
}
190199
}

src/lib.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ use std::convert::TryInto;
196196
#[cfg(feature = "json")]
197197
use std::io::Read;
198198

199+
#[cfg(feature = "seccomp_unotify")]
200+
use std::os::fd::{FromRawFd as _, OwnedFd};
201+
199202
use std::collections::HashMap;
200203
use std::fmt::{Display, Formatter};
201204
use std::io;
@@ -310,7 +313,8 @@ impl From<JsonFrontendError> for Error {
310313
///
311314
/// [`BpfProgram`]: type.BpfProgram.html
312315
pub fn apply_filter(bpf_filter: BpfProgramRef) -> Result<()> {
313-
apply_filter_with_flags(bpf_filter, 0)
316+
apply_filter_with_flags(bpf_filter, 0)?;
317+
Ok(())
314318
}
315319

316320
/// Apply a BPF filter to the all threads in the process via the TSYNC feature. Please read the
@@ -322,7 +326,28 @@ pub fn apply_filter(bpf_filter: BpfProgramRef) -> Result<()> {
322326
///
323327
/// [`BpfProgram`]: type.BpfProgram.html
324328
pub fn apply_filter_all_threads(bpf_filter: BpfProgramRef) -> Result<()> {
325-
apply_filter_with_flags(bpf_filter, libc::SECCOMP_FILTER_FLAG_TSYNC)
329+
let rc = apply_filter_with_flags(bpf_filter, libc::SECCOMP_FILTER_FLAG_TSYNC)?;
330+
331+
if rc > 0 {
332+
return Err(Error::ThreadSync(rc));
333+
}
334+
335+
Ok(())
336+
}
337+
338+
/// Apply a filter with the SECCOMP_FILTER_FLAG_NEW_LISTENER flag.
339+
///
340+
/// The returned FD can be polled for notifications generated by a rule with the
341+
/// action [SeccompAction::Notify]. See `man 2 seccomp_unotify` for more
342+
/// information.
343+
#[cfg(feature = "seccomp_unotify")]
344+
pub fn apply_filter_with_notify_fd(bpf_filter: BpfProgramRef) -> Result<OwnedFd> {
345+
let rc = apply_filter_with_flags(bpf_filter, libc::SECCOMP_FILTER_FLAG_NEW_LISTENER)?;
346+
347+
// SAFETY: seccomp_unotify documents that it returns a valid FD if the
348+
// syscall is a success.
349+
let fd = unsafe { OwnedFd::from_raw_fd(rc as _) };
350+
Ok(fd)
326351
}
327352

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

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

376-
Ok(())
396+
Ok(rc)
377397
}
378398

379399
/// Compile [`BpfProgram`]s from JSON.

0 commit comments

Comments
 (0)