1use serde::{
5 Deserialize, Serialize,
6 ser::{SerializeSeq, Serializer},
7};
8use serde_with::{hex::Hex, serde_as};
9use std::cell::RefCell;
10use std::collections::BTreeMap;
11use std::ffi::CStr;
12use std::rc::Rc;
13use std::time::{Duration, SystemTime, UNIX_EPOCH};
14use sysinfo::System;
15
16include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
17
18pub type ContextId = [u8; 16];
19
20fn only_values<K, V, S>(source: &BTreeMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>
21where
22 S: Serializer,
23 V: Serialize,
24{
25 let mut seq = serializer.serialize_seq(Some(source.len()))?;
26 for value in source.values() {
27 seq.serialize_element(value)?;
28 }
29 seq.end()
30}
31
32#[serde_as]
33#[derive(Debug, Serialize)]
34pub struct Context {
35 #[serde_as(as = "Hex")]
36 #[serde(rename = "context")]
37 pub id: ContextId,
38 #[serde_as(as = "Hex")]
39 pub origin: Vec<u8>,
40 #[serde_as(as = "serde_with::TimestampSecondsWithFrac<f64>")]
41 pub start: SystemTime,
42 #[serde_as(as = "serde_with::TimestampSecondsWithFrac<f64>")]
43 pub end: SystemTime,
44 pub events: BTreeMap<String, EventData>,
45 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
46 #[serde(serialize_with = "only_values")]
47 pub spans: BTreeMap<ContextId, Rc<RefCell<Context>>>,
48}
49
50#[derive(Debug)]
51pub struct ContextTracker {
52 all_contexts: BTreeMap<ContextId, Rc<RefCell<Context>>>,
53 root_contexts: Vec<Rc<RefCell<Context>>>,
54 boot_time: SystemTime,
55}
56
57impl ContextTracker {
58 pub fn new(boot_time: Option<SystemTime>) -> Self {
59 Self {
60 all_contexts: BTreeMap::new(),
61 root_contexts: Vec::new(),
62 boot_time: boot_time.unwrap_or_else(|| {
63 UNIX_EPOCH
64 .checked_add(Duration::from_secs(System::boot_time()))
65 .unwrap()
66 }),
67 }
68 }
69
70 pub fn flush(&mut self, before: Option<SystemTime>) -> impl IntoIterator<Item = Context> {
71 let mut removed = Vec::new();
72 self.root_contexts.retain(|context| {
73 if let Some(before) = before
74 && context.borrow().start > before
75 {
76 true
77 } else {
78 self.all_contexts.remove(&context.borrow().id[..]);
79 removed.push(context.clone());
80 false
81 }
82 });
83 removed
84 .into_iter()
85 .map(|context| Rc::into_inner(context).unwrap().into_inner())
86 }
87
88 pub fn handle_event_group(&mut self, group: &EventGroup) -> usize {
89 let start = self
90 .boot_time
91 .checked_add(group.start())
92 .unwrap_or(UNIX_EPOCH);
93 let end = self
94 .boot_time
95 .checked_add(group.end())
96 .unwrap_or(UNIX_EPOCH);
97 let mut count = 0;
98 for event in group.events() {
99 match event {
100 Event::NewContext {
101 parent: parent_context,
102 origin,
103 } => {
104 let context = Rc::new(RefCell::new(Context {
105 id: *group.context(),
106 origin: origin.to_owned(),
107 start,
108 end,
109 events: Default::default(),
110 spans: Default::default(),
111 }));
112 if let Some(parent) = self.all_contexts.get(&parent_context[..]) {
113 parent
114 .borrow_mut()
115 .spans
116 .insert(*group.context(), context.clone());
117 } else {
118 self.root_contexts.push(context.clone());
119 count += 1;
120 }
121 self.all_contexts.insert(*group.context(), context);
122 }
123 Event::Data { key, value } => {
124 if !self.all_contexts.contains_key(group.context()) {
125 let context_obj = Rc::new(RefCell::new(Context {
130 id: *group.context(),
131 origin: Default::default(),
132 start,
133 end,
134 events: Default::default(),
135 spans: Default::default(),
136 }));
137 self.root_contexts.push(context_obj.clone());
138 self.all_contexts.insert(*group.context(), context_obj);
139 count += 1;
140 }
141 if let Some(parent) = self.all_contexts.get(group.context()) {
142 parent
143 .borrow_mut()
144 .events
145 .insert(key.to_string(), value.clone());
146 }
147 }
148 }
149 }
150 count
151 }
152}
153
154#[serde_as]
155#[derive(Serialize, Deserialize, Clone, Debug)]
156#[serde(untagged)]
157pub enum EventData {
158 Word(i64),
159 String(String),
160 Blob(
161 #[serde_as(as = "serde_with::Bytes")] Vec<u8>, ),
163}
164
165#[serde_as]
166#[derive(Serialize, Deserialize, Clone, Debug)]
167pub enum Event {
168 NewContext {
169 #[serde_as(as = "serde_with::Bytes")]
170 parent: ContextId,
171 #[serde_as(as = "serde_with::Bytes")]
172 origin: Vec<u8>,
173 },
174 Data {
175 key: String,
176 value: EventData,
177 },
178}
179
180#[serde_as]
181#[derive(Serialize, Deserialize, Clone, Debug)]
182pub struct EventGroup {
183 #[serde_as(as = "serde_with::Bytes")]
184 context: ContextId,
185 #[serde_as(as = "serde_with::DurationNanoSeconds<u64>")]
186 start: Duration,
187 #[serde_as(as = "serde_with::DurationNanoSeconds<u64>")]
188 end: Duration,
189 events: Vec<Event>,
190}
191
192fn format_context_id(pid_tgid: u64, context: i64) -> ContextId {
193 let mut result: ContextId = Default::default();
194 result[..8].copy_from_slice(&u64::to_le_bytes(pid_tgid));
195 result[8..].copy_from_slice(&i64::to_le_bytes(context));
196 result
197}
198
199impl EventGroup {
200 pub fn context(&self) -> &ContextId {
202 &self.context
203 }
204
205 pub fn start(&self) -> Duration {
207 self.start
208 }
209
210 pub fn end(&self) -> Duration {
212 self.end
213 }
214
215 pub fn events(&self) -> &Vec<Event> {
217 &self.events
218 }
219
220 pub fn matches_pid(&self, pid: libc::pid_t) -> bool {
222 (u64::from_le_bytes(self.context()[..8].try_into().unwrap()) & 0xffffffff)
223 == <i32 as TryInto<u64>>::try_into(pid).unwrap()
224 }
225
226 pub fn encrypt_context<F>(&mut self, f: F) -> Result<(), Box<dyn std::error::Error>>
228 where
229 F: Fn(&mut ContextId) -> Result<(), Box<dyn std::error::Error>>,
230 {
231 f(&mut self.context)?;
232
233 if let Some(Event::NewContext { parent, .. }) = self.events.last_mut() {
234 f(parent)?;
235 }
236 Ok(())
237 }
238
239 pub fn coalesce(&mut self, other: &mut Self) {
241 self.end = other.end;
242 self.events.append(&mut other.events);
243 }
244
245 pub fn events_filtered(&mut self, scopes: &[String]) {
247 self.events.retain(|event| match event {
248 Event::NewContext { .. } => true,
249 Event::Data { key, .. } => scopes
250 .iter()
251 .any(|scope| !key.contains("::") || key.starts_with(&format!("{}::", scope))),
252 });
253 }
254
255 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
257 let header = bytes.as_ptr() as *mut audit_event_header_st;
258 let context =
259 unsafe { format_context_id((*header).pid_tgid.into(), (*header).context.into()) };
260 let ktime = unsafe { Duration::from_nanos((*header).ktime.into()) };
261 let event = match unsafe { (*header).type_ } {
262 audit_event_type_t::AUDIT_EVENT_NEW_CONTEXT => {
263 let raw_new_context = bytes.as_ptr() as *mut audit_new_context_event_st;
264 let parent = unsafe {
265 format_context_id((*header).pid_tgid.into(), (*raw_new_context).parent.into())
266 };
267 let origin = unsafe {
268 (&(*raw_new_context).origin)[..(*raw_new_context).origin_size as usize].to_vec()
269 };
270 EventGroup {
271 context,
272 start: ktime,
273 end: ktime,
274 events: vec![Event::NewContext { parent, origin }],
275 }
276 }
277 audit_event_type_t::AUDIT_EVENT_DATA => unsafe {
278 let data = bytes.as_ptr() as *mut audit_data_event_st;
279 match (*data).type_ {
280 audit_data_type_t::AUDIT_DATA_WORD => {
281 let raw_word_data = bytes.as_ptr() as *mut audit_word_data_event_st;
282 let key = CStr::from_ptr((*raw_word_data).base.key.as_ptr());
283 EventGroup {
284 context,
285 start: ktime,
286 end: ktime,
287 events: vec![Event::Data {
288 key: key.to_str()?.to_string(),
289 value: EventData::Word((*raw_word_data).value.into()),
290 }],
291 }
292 }
293 audit_data_type_t::AUDIT_DATA_STRING => {
294 let raw_string_data = bytes.as_ptr() as *mut audit_blob_data_event_st;
295 let key = CStr::from_ptr((*raw_string_data).base.key.as_ptr());
296 let len = (*raw_string_data).size as usize;
297 let string = std::str::from_utf8(&(&(*raw_string_data).value)[..len - 1])?
298 .to_string();
299 EventGroup {
300 context,
301 start: ktime,
302 end: ktime,
303 events: vec![Event::Data {
304 key: key.to_str()?.to_string(),
305 value: EventData::String(string),
306 }],
307 }
308 }
309 audit_data_type_t::AUDIT_DATA_BLOB => {
310 let raw_blob_data = bytes.as_ptr() as *mut audit_blob_data_event_st;
311 let key = CStr::from_ptr((*raw_blob_data).base.key.as_ptr());
312 let len = (*raw_blob_data).size as usize;
313 let data = (&(*raw_blob_data).value)[..len].to_vec();
314 EventGroup {
315 context,
316 start: ktime,
317 end: ktime,
318 events: vec![Event::Data {
319 key: key.to_str()?.to_string(),
320 value: EventData::Blob(data),
321 }],
322 }
323 }
324 _ => unreachable!(),
325 }
326 },
327 _ => unreachable!(),
328 };
329 Ok(event)
330 }
331}