1use serde::{Deserialize, Serialize};
5use serde_with::serde_as;
6use std::ffi::CStr;
7use std::time::Duration;
8
9include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
10
11pub type ContextID = [u8; 16];
12
13#[serde_as]
14#[derive(Serialize, Deserialize, Clone, Debug)]
15#[serde(untagged)]
16pub enum EventData {
17 Word(i64),
18 String(String),
19 Blob(
20 #[serde_as(as = "serde_with::Bytes")] Vec<u8>, ),
22}
23
24#[serde_as]
25#[derive(Serialize, Deserialize, Clone, Debug)]
26pub enum Event {
27 NewContext {
28 #[serde_as(as = "serde_with::Bytes")]
29 parent: ContextID,
30 #[serde_as(as = "serde_with::Bytes")]
31 origin: Vec<u8>,
32 },
33 Data {
34 key: String,
35 value: EventData,
36 },
37}
38
39#[serde_as]
40#[derive(Serialize, Deserialize, Clone, Debug)]
41pub struct EventGroup {
42 #[serde_as(as = "serde_with::Bytes")]
43 context: ContextID,
44 #[serde_as(as = "serde_with::DurationNanoSeconds<u64>")]
45 start: Duration,
46 #[serde_as(as = "serde_with::DurationNanoSeconds<u64>")]
47 end: Duration,
48 events: Vec<Event>,
49}
50
51fn format_context(pid_tgid: u64, context: i64) -> ContextID {
52 let mut result: ContextID = Default::default();
53 result[..8].copy_from_slice(&u64::to_le_bytes(pid_tgid));
54 result[8..].copy_from_slice(&i64::to_le_bytes(context));
55 result
56}
57
58impl EventGroup {
59 pub fn context(&self) -> &ContextID {
61 &self.context
62 }
63
64 pub fn start(&self) -> Duration {
66 self.start
67 }
68
69 pub fn end(&self) -> Duration {
71 self.end
72 }
73
74 pub fn events(&self) -> &Vec<Event> {
76 &self.events
77 }
78
79 pub fn matches_pid(&self, pid: libc::pid_t) -> bool {
81 (u64::from_le_bytes(self.context()[..8].try_into().unwrap()) & 0xffffffff)
82 == <i32 as TryInto<u64>>::try_into(pid).unwrap()
83 }
84
85 pub fn encrypt_context<F>(&mut self, f: F) -> Result<(), Box<dyn std::error::Error>>
87 where
88 F: Fn(&mut ContextID) -> Result<(), Box<dyn std::error::Error>>,
89 {
90 f(&mut self.context)?;
91
92 if let Some(Event::NewContext { parent, .. }) = self.events.last_mut() {
93 f(parent)?;
94 }
95 Ok(())
96 }
97
98 pub fn coalesce(&mut self, other: &mut Self) {
100 self.end = other.end;
101 self.events.append(&mut other.events);
102 }
103
104 pub fn events_filtered(&mut self, scopes: &[String]) {
106 self.events.retain(|event| match event {
107 Event::NewContext { .. } => true,
108 Event::Data { key, .. } => scopes
109 .iter()
110 .any(|scope| !key.contains("::") || key.starts_with(&format!("{}::", scope))),
111 });
112 }
113
114 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
116 let header = bytes.as_ptr() as *mut audit_event_header_st;
117 let context = unsafe { format_context((*header).pid_tgid, (*header).context) };
118 let ktime = unsafe { Duration::from_nanos((*header).ktime) };
119 let event = match unsafe { (*header).type_ } {
120 audit_event_type_t::AUDIT_EVENT_NEW_CONTEXT => {
121 let raw_new_context = bytes.as_ptr() as *mut audit_new_context_event_st;
122 let parent =
123 unsafe { format_context((*header).pid_tgid, (*raw_new_context).parent) };
124 let origin = unsafe {
125 (&(*raw_new_context).origin)[..(*raw_new_context).origin_size as usize].to_vec()
126 };
127 EventGroup {
128 context,
129 start: ktime,
130 end: ktime,
131 events: vec![Event::NewContext { parent, origin }],
132 }
133 }
134 audit_event_type_t::AUDIT_EVENT_DATA => unsafe {
135 let data = bytes.as_ptr() as *mut audit_data_event_st;
136 match (*data).type_ {
137 audit_data_type_t::AUDIT_DATA_WORD => {
138 let raw_word_data = bytes.as_ptr() as *mut audit_word_data_event_st;
139 let key = CStr::from_ptr((*raw_word_data).base.key.as_ptr());
140 EventGroup {
141 context,
142 start: ktime,
143 end: ktime,
144 events: vec![Event::Data {
145 key: key.to_str()?.to_string(),
146 value: EventData::Word((*raw_word_data).value),
147 }],
148 }
149 }
150 audit_data_type_t::AUDIT_DATA_STRING => {
151 let raw_string_data = bytes.as_ptr() as *mut audit_blob_data_event_st;
152 let key = CStr::from_ptr((*raw_string_data).base.key.as_ptr());
153 let len = (*raw_string_data).size as usize;
154 let string = std::str::from_utf8(&(&(*raw_string_data).value)[..len - 1])?
155 .to_string();
156 EventGroup {
157 context,
158 start: ktime,
159 end: ktime,
160 events: vec![Event::Data {
161 key: key.to_str()?.to_string(),
162 value: EventData::String(string),
163 }],
164 }
165 }
166 audit_data_type_t::AUDIT_DATA_BLOB => {
167 let raw_blob_data = bytes.as_ptr() as *mut audit_blob_data_event_st;
168 let key = CStr::from_ptr((*raw_blob_data).base.key.as_ptr());
169 let len = (*raw_blob_data).size as usize;
170 let data = (&(*raw_blob_data).value)[..len].to_vec();
171 EventGroup {
172 context,
173 start: ktime,
174 end: ktime,
175 events: vec![Event::Data {
176 key: key.to_str()?.to_string(),
177 value: EventData::Blob(data),
178 }],
179 }
180 }
181 _ => unreachable!(),
182 }
183 },
184 _ => unreachable!(),
185 };
186 Ok(event)
187 }
188}