1use chrono::{DateTime, Local};
2use enumflags2::BitFlags;
3use nix::{
4 errno::Errno,
5 libc::{SIGRTMIN, c_int},
6 unistd::User,
7};
8use tokio::sync::mpsc::UnboundedSender;
9
10use crate::{
11 cli::{
12 args::{LogModeArgs, ModifierArgs},
13 options::SeccompBpf,
14 },
15 event::{TracerEventDetailsKind, TracerMessage},
16 printer::{Printer, PrinterArgs},
17 proc::{BaselineInfo, Cred, CredInspectError},
18 pty::UnixSlavePty,
19};
20use std::{collections::BTreeMap, fmt::Display, sync::Arc};
21
22use crate::{
23 event::OutputMsg,
24 proc::{FileDescriptorInfoCollection, Interpreter},
25};
26
27pub type InspectError = Errno;
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum Signal {
31 Standard(nix::sys::signal::Signal),
32 Realtime(u8), }
34
35impl Signal {
36 pub fn from_raw(raw: c_int) -> Self {
37 match nix::sys::signal::Signal::try_from(raw) {
38 Ok(sig) => Self::Standard(sig),
39 Err(_) => Self::Realtime(raw as u8),
43 }
44 }
45
46 pub fn as_raw(self) -> i32 {
47 match self {
48 Self::Standard(signal) => signal as i32,
49 Self::Realtime(raw) => raw as i32,
50 }
51 }
52}
53
54impl From<nix::sys::signal::Signal> for Signal {
55 fn from(value: nix::sys::signal::Signal) -> Self {
56 Self::Standard(value)
57 }
58}
59
60impl Display for Signal {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 match self {
63 Self::Standard(signal) => signal.fmt(f),
64 Self::Realtime(sig) => {
65 let min = SIGRTMIN();
66 let delta = *sig as i32 - min;
67 match delta.signum() {
68 0 => write!(f, "SIGRTMIN"),
69 1 => write!(f, "SIGRTMIN+{delta}"),
70 -1 => write!(f, "SIGRTMIN{delta}"),
71 _ => unreachable!(),
72 }
73 }
74 }
75 }
76}
77
78#[derive(Default)]
79#[non_exhaustive]
80pub struct TracerBuilder {
81 pub user: Option<User>,
82 pub modifier: ModifierArgs,
83 pub mode: Option<TracerMode>,
84 pub filter: Option<BitFlags<TracerEventDetailsKind>>,
85 pub tx: Option<UnboundedSender<TracerMessage>>,
86 pub printer: Option<Printer>,
88 pub baseline: Option<Arc<BaselineInfo>>,
89 pub seccomp_bpf: SeccompBpf,
91 pub ptrace_polling_delay: Option<u64>,
92 pub ptrace_blocking: Option<bool>,
93}
94
95impl TracerBuilder {
96 pub fn new() -> Self {
98 Default::default()
99 }
100
101 pub fn ptrace_blocking(mut self, enable: bool) -> Self {
106 if self.ptrace_polling_delay.is_some() && enable {
107 panic!(
108 "Cannot enable blocking mode when ptrace polling delay implicitly specifys polling mode"
109 );
110 }
111 self.ptrace_blocking = Some(enable);
112 self
113 }
114
115 pub fn ptrace_polling_delay(mut self, ptrace_polling_delay: Option<u64>) -> Self {
120 if Some(true) == self.ptrace_blocking && ptrace_polling_delay.is_some() {
121 panic!("Cannot set ptrace_polling_delay when operating in blocking mode")
122 }
123 self.ptrace_polling_delay = ptrace_polling_delay;
124 self
125 }
126
127 pub fn seccomp_bpf(mut self, seccomp_bpf: SeccompBpf) -> Self {
132 self.seccomp_bpf = seccomp_bpf;
133 self
134 }
135
136 pub fn user(mut self, user: Option<User>) -> Self {
140 self.user = user;
141 self
142 }
143
144 pub fn modifier(mut self, modifier: ModifierArgs) -> Self {
145 self.modifier = modifier;
146 self
147 }
148
149 pub fn mode(mut self, mode: TracerMode) -> Self {
151 self.mode = Some(mode);
152 self
153 }
154
155 pub fn filter(mut self, filter: BitFlags<TracerEventDetailsKind>) -> Self {
157 self.filter = Some(filter);
158 self
159 }
160
161 pub fn tracer_tx(mut self, tx: UnboundedSender<TracerMessage>) -> Self {
165 self.tx = Some(tx);
166 self
167 }
168
169 pub fn printer(mut self, printer: Printer) -> Self {
170 self.printer = Some(printer);
171 self
172 }
173
174 pub fn printer_from_cli(mut self, tracing_args: &LogModeArgs) -> Self {
178 self.printer = Some(Printer::new(
179 PrinterArgs::from_cli(tracing_args, &self.modifier),
180 self.baseline.clone().unwrap(),
181 ));
182 self
183 }
184
185 pub fn baseline(mut self, baseline: Arc<BaselineInfo>) -> Self {
186 self.baseline = Some(baseline);
187 self
188 }
189}
190
191#[derive(Debug)]
192pub struct ExecData {
193 pub filename: OutputMsg,
194 pub argv: Arc<Result<Vec<OutputMsg>, InspectError>>,
195 pub envp: Arc<Result<BTreeMap<OutputMsg, OutputMsg>, InspectError>>,
196 pub has_dash_env: bool,
197 pub cred: Result<Cred, CredInspectError>,
198 pub cwd: OutputMsg,
199 pub interpreters: Option<Vec<Interpreter>>,
200 pub fdinfo: Arc<FileDescriptorInfoCollection>,
201 pub timestamp: DateTime<Local>,
202}
203
204impl ExecData {
205 #[allow(clippy::too_many_arguments)]
206 pub fn new(
207 filename: OutputMsg,
208 argv: Result<Vec<OutputMsg>, InspectError>,
209 envp: Result<BTreeMap<OutputMsg, OutputMsg>, InspectError>,
210 has_dash_env: bool,
211 cred: Result<Cred, CredInspectError>,
212 cwd: OutputMsg,
213 interpreters: Option<Vec<Interpreter>>,
214 fdinfo: FileDescriptorInfoCollection,
215 timestamp: DateTime<Local>,
216 ) -> Self {
217 Self {
218 filename,
219 argv: Arc::new(argv),
220 envp: Arc::new(envp),
221 has_dash_env,
222 cred,
223 cwd,
224 interpreters,
225 fdinfo: Arc::new(fdinfo),
226 timestamp,
227 }
228 }
229}
230
231pub enum TracerMode {
232 Tui(Option<UnixSlavePty>),
233 Log { foreground: bool },
234}
235
236impl PartialEq for TracerMode {
237 fn eq(&self, other: &Self) -> bool {
238 #[allow(clippy::match_like_matches_macro)]
240 match (self, other) {
241 (Self::Log { foreground: a }, Self::Log { foreground: b }) => a == b,
242 _ => false,
243 }
244 }
245}
246
247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
248pub enum ProcessExit {
249 Code(i32),
250 Signal(Signal),
251}