1#![cfg(feature = "notify")]
2use super::{action::Action, attribute::Attribute, raw, syscall::Syscall};
5use crate::notify::Notifier;
6use nix::errno::Errno;
7use std::{
8 fs::File,
9 io,
10 os::fd::{IntoRawFd, OwnedFd},
11 path::Path,
12};
13use thiserror::Error;
14
15#[cfg(feature = "notify")]
16use std::os::fd::FromRawFd;
17
18#[derive(Debug, Error)]
20pub enum Error {
21 #[error("Failed to initialization the Filter context")]
23 Initialization,
24
25 #[error("Failed to set attribute {0}: {1}")]
27 SetAttribute(Attribute, Errno),
28
29 #[error("Failed to add rule {0} for {1}: {2}")]
31 AddRule(Action, Syscall, Errno),
32
33 #[error("Failed to write BPF: {0}")]
35 Io(#[from] io::Error),
36
37 #[error("Failed to export to BPF: {0}")]
39 Export(Errno),
40
41 #[error("Failed to load policy: {0}")]
43 Load(Errno),
44
45 #[cfg(feature = "notify")]
47 #[error("Failed to send FD to notifier")]
48 Send,
49
50 #[cfg(feature = "notify")]
52 #[error("Failed to prepare notifier: {0}")]
53 Prepare(String),
54}
55
56pub struct Filter {
77 ctx: raw::scmp_filter_ctx,
78
79 #[cfg(feature = "notify")]
80 notifier: Option<Box<dyn Notifier>>,
81}
82impl Filter {
83 pub fn new(def_action: Action) -> Result<Self, Error> {
85 let ctx = unsafe { raw::seccomp_init(def_action.into()) };
86 if ctx.is_null() {
87 Err(Error::Initialization)
88 } else {
89 #[cfg(feature = "notify")]
90 return Ok(Self {
91 ctx,
92 notifier: None,
93 });
94
95 #[cfg(not(feature = "notify"))]
96 return Ok(Self { ctx });
97 }
98 }
99
100 #[cfg(feature = "notify")]
101 pub fn set_notifier(&mut self, f: impl Notifier) {
103 self.notifier = Some(Box::new(f))
104 }
105
106 pub fn set_attribute(&mut self, attr: Attribute) -> Result<(), Error> {
108 match unsafe { raw::seccomp_attr_set(self.ctx, attr.name(), attr.value()) } {
109 0 => Ok(()),
110 e => Err(Error::SetAttribute(attr, Errno::from_raw(e))),
111 }
112 }
113
114 pub fn add_rule(&mut self, action: Action, syscall: Syscall) -> Result<(), Error> {
116 match unsafe { raw::seccomp_rule_add(self.ctx, action.into(), syscall.into(), 0) } {
117 0 => Ok(()),
118 e => Err(Error::AddRule(action, syscall, Errno::from_raw(e))),
119 }
120 }
121
122 pub fn write(&self, path: &Path) -> Result<OwnedFd, Error> {
124 let file = File::create(path)?;
125 match unsafe { raw::seccomp_export_bpf(self.ctx, file.into_raw_fd()) } {
126 0 => Ok(File::open(path)?.into()),
127 e => Err(Error::Export(Errno::from_raw(e))),
128 }
129 }
130
131 #[cfg(feature = "notify")]
134 pub fn setup(&mut self) -> Result<(), Error> {
135 if let Some(notifier) = &mut self.notifier {
136 for (action, call) in notifier.exempt() {
137 self.add_rule(action, call)?
138 }
139 }
140
141 if let Some(notifier) = &mut self.notifier {
142 notifier.prepare().map_err(Error::Prepare)?;
143 }
144 Ok(())
145 }
146
147 #[cfg(feature = "notify")]
148 pub fn load(mut self) {
153 if let Some(mut notifier) = self.notifier.take() {
154 match unsafe { raw::seccomp_load(self.ctx) } {
155 0 => {
156 let fd = unsafe { OwnedFd::from_raw_fd(raw::seccomp_notify_fd(self.ctx)) };
157 notifier.handle(fd);
158 }
159 errno => panic!("Failed to set filter: {errno}"),
160 };
161 }
162 }
163
164 #[cfg(not(feature = "notify"))]
165 pub fn load(self) {
170 let errno = unsafe { raw::seccomp_load(self.ctx) };
171 if errno != 0 {
172 panic!("Failed to set filter: {errno}");
173 }
174 }
175}
176impl Drop for Filter {
177 fn drop(&mut self) {
178 unsafe { raw::seccomp_release(self.ctx) }
179 }
180}
181
182unsafe impl Sync for Filter {}
185unsafe impl Send for Filter {}