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 { ref mut 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 =
118 unsafe { format_context((*header).pid_tgid.into(), (*header).context.into()) };
119 let ktime = unsafe { Duration::from_nanos((*header).ktime.into()) };
120 let event = match unsafe { (*header).type_ } {
121 audit_event_type_t::AUDIT_EVENT_NEW_CONTEXT => {
122 let raw_new_context = bytes.as_ptr() as *mut audit_new_context_event_st;
123 let parent = unsafe {
124 format_context((*header).pid_tgid.into(), (*raw_new_context).parent.into())
125 };
126 let origin = unsafe {
127 (*raw_new_context).origin[..(*raw_new_context).origin_size as usize].to_vec()
128 };
129 EventGroup {
130 context,
131 start: ktime,
132 end: ktime,
133 events: vec![Event::NewContext { parent, origin }],
134 }
135 }
136 audit_event_type_t::AUDIT_EVENT_DATA => unsafe {
137 let data = bytes.as_ptr() as *mut audit_data_event_st;
138 match (*data).type_ {
139 audit_data_type_t::AUDIT_DATA_WORD => {
140 let raw_word_data = bytes.as_ptr() as *mut audit_word_data_event_st;
141 let key = CStr::from_ptr((*raw_word_data).base.key.as_ptr());
142 EventGroup {
143 context,
144 start: ktime,
145 end: ktime,
146 events: vec![Event::Data {
147 key: key.to_str()?.to_string(),
148 value: EventData::Word((*raw_word_data).value.into()),
149 }],
150 }
151 }
152 audit_data_type_t::AUDIT_DATA_STRING => {
153 let raw_string_data = bytes.as_ptr() as *mut audit_blob_data_event_st;
154 let key = CStr::from_ptr((*raw_string_data).base.key.as_ptr());
155 let len = (*raw_string_data).size as usize;
156 let string =
157 std::str::from_utf8(&(*raw_string_data).value[..len - 1])?.to_string();
158 EventGroup {
159 context,
160 start: ktime,
161 end: ktime,
162 events: vec![Event::Data {
163 key: key.to_str()?.to_string(),
164 value: EventData::String(string),
165 }],
166 }
167 }
168 audit_data_type_t::AUDIT_DATA_BLOB => {
169 let raw_blob_data = bytes.as_ptr() as *mut audit_blob_data_event_st;
170 let key = CStr::from_ptr((*raw_blob_data).base.key.as_ptr());
171 let len = (*raw_blob_data).size as usize;
172 let data = (*raw_blob_data).value[..len].to_vec();
173 EventGroup {
174 context,
175 start: ktime,
176 end: ktime,
177 events: vec![Event::Data {
178 key: key.to_str()?.to_string(),
179 value: EventData::Blob(data),
180 }],
181 }
182 }
183 _ => unreachable!(),
184 }
185 },
186 _ => unreachable!(),
187 };
188 Ok(event)
189 }
190}