netlink_packet_audit/rules/
buffer.rs1use anyhow::Context;
4use byteorder::{ByteOrder, NativeEndian};
5use netlink_packet_utils::{traits::Parseable, DecodeError};
6
7use crate::{constants::*, rules::*, Field};
8
9macro_rules! u32_array {
14 ($start:expr, $len:expr) => {
15 $start..($start + 4 * $len)
16 };
17}
18
19const FLAGS: Field = 0..4;
20const ACTION: Field = 4..8;
21const FIELD_COUNT: Field = 8..12;
22const SYSCALLS: Field = u32_array!(FIELD_COUNT.end, AUDIT_BITMASK_SIZE);
23const FIELDS: Field = u32_array!(SYSCALLS.end, AUDIT_MAX_FIELDS);
24const VALUES: Field = u32_array!(FIELDS.end, AUDIT_MAX_FIELDS);
25const FIELD_FLAGS: Field = u32_array!(VALUES.end, AUDIT_MAX_FIELDS);
26const BUFLEN: Field = FIELD_FLAGS.end..FIELD_FLAGS.end + 4;
27
28pub(crate) const RULE_BUF_MIN_LEN: usize = BUFLEN.end;
29
30#[allow(non_snake_case)]
31fn BUF(len: usize) -> Field {
32 BUFLEN.end..(BUFLEN.end + len)
33}
34
35#[derive(Debug, PartialEq, Eq, Clone)]
36#[non_exhaustive]
37pub struct RuleBuffer<T> {
38 buffer: T,
39}
40
41impl<T: AsRef<[u8]>> RuleBuffer<T> {
42 pub fn new(buffer: T) -> RuleBuffer<T> {
43 RuleBuffer { buffer }
44 }
45
46 pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {
47 let packet = Self::new(buffer);
48 packet.check_len()?;
49 Ok(packet)
50 }
51
52 pub(crate) fn check_len(&self) -> Result<(), DecodeError> {
53 let len = self.buffer.as_ref().len();
54 if len < BUFLEN.end {
55 Err(format!(
56 "buffer size is {}, whereas a rule buffer is at least {} long",
57 len, BUFLEN.end
58 )
59 .into())
60 } else if len < BUFLEN.end + self.buflen() as usize {
61 Err(format!(
62 "buffer length is {}, but it should be {} (header) + {} \
63 (length field)",
64 len,
65 BUFLEN.end,
66 self.buflen()
67 )
68 .into())
69 } else {
70 Ok(())
71 }
72 }
73
74 pub fn flags(&self) -> u32 {
75 NativeEndian::read_u32(&self.buffer.as_ref()[FLAGS])
76 }
77
78 pub fn action(&self) -> u32 {
79 NativeEndian::read_u32(&self.buffer.as_ref()[ACTION])
80 }
81
82 pub fn field_count(&self) -> u32 {
83 NativeEndian::read_u32(&self.buffer.as_ref()[FIELD_COUNT])
84 }
85
86 pub fn buflen(&self) -> u32 {
87 NativeEndian::read_u32(&self.buffer.as_ref()[BUFLEN])
88 }
89}
90
91impl<'a, T: AsRef<[u8]> + ?Sized> RuleBuffer<&'a T> {
92 pub fn syscalls(&self) -> &'a [u8] {
93 &self.buffer.as_ref()[SYSCALLS]
94 }
95
96 pub fn fields(&self) -> &'a [u8] {
97 &self.buffer.as_ref()[FIELDS]
98 }
99
100 pub fn values(&self) -> &'a [u8] {
101 &self.buffer.as_ref()[VALUES]
102 }
103
104 pub fn field_flags(&self) -> &'a [u8] {
105 &self.buffer.as_ref()[FIELD_FLAGS]
106 }
107
108 pub fn buf(&self) -> &'a [u8] {
109 let field = BUF(self.buflen() as usize);
110 &self.buffer.as_ref()[field.start..field.end]
111 }
112}
113
114impl<T: AsRef<[u8]> + AsMut<[u8]>> RuleBuffer<T> {
115 pub fn set_flags(&mut self, value: u32) {
116 NativeEndian::write_u32(&mut self.buffer.as_mut()[FLAGS], value)
117 }
118
119 pub fn set_action(&mut self, value: u32) {
120 NativeEndian::write_u32(&mut self.buffer.as_mut()[ACTION], value)
121 }
122
123 pub fn set_field_count(&mut self, value: u32) {
124 NativeEndian::write_u32(&mut self.buffer.as_mut()[FIELD_COUNT], value)
125 }
126
127 pub fn set_buflen(&mut self, value: u32) {
128 NativeEndian::write_u32(&mut self.buffer.as_mut()[BUFLEN], value)
129 }
130
131 pub fn syscalls_mut(&mut self) -> &mut [u8] {
132 &mut self.buffer.as_mut()[SYSCALLS]
133 }
134
135 pub fn fields_mut(&mut self) -> &mut [u8] {
136 &mut self.buffer.as_mut()[FIELDS]
137 }
138
139 pub fn set_field(&mut self, position: usize, value: u32) {
140 let offset = FIELDS.start + (position * 4);
141 assert!(position <= FIELDS.end - 4);
142 NativeEndian::write_u32(
143 &mut self.buffer.as_mut()[offset..offset + 4],
144 value,
145 )
146 }
147
148 pub fn values_mut(&mut self) -> &mut [u8] {
149 &mut self.buffer.as_mut()[VALUES]
150 }
151
152 pub fn set_value(&mut self, position: usize, value: u32) {
153 let offset = VALUES.start + (position * 4);
154 assert!(position <= VALUES.end - 4);
155 NativeEndian::write_u32(
156 &mut self.buffer.as_mut()[offset..offset + 4],
157 value,
158 )
159 }
160
161 pub fn field_flags_mut(&mut self) -> &mut [u8] {
162 &mut self.buffer.as_mut()[FIELD_FLAGS]
163 }
164
165 pub fn set_field_flags(&mut self, position: usize, value: u32) {
166 let offset = FIELD_FLAGS.start + (position * 4);
167 assert!(position <= FIELD_FLAGS.end - 4);
168 NativeEndian::write_u32(
169 &mut self.buffer.as_mut()[offset..offset + 4],
170 value,
171 )
172 }
173
174 pub fn buf_mut(&mut self) -> &mut [u8] {
175 let field = BUF(self.buflen() as usize);
176 &mut self.buffer.as_mut()[field.start..field.end]
177 }
178}
179
180impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RuleBuffer<&'a T>> for RuleMessage {
181 fn parse(buf: &RuleBuffer<&'a T>) -> Result<Self, DecodeError> {
182 use self::RuleField::*;
183
184 buf.check_len().context("invalid rule message buffer")?;
185 let mut rule = RuleMessage::new();
186 rule.flags = buf.flags().into();
187 rule.action = buf.action().into();
188 rule.syscalls = RuleSyscalls::from_slice(buf.syscalls())?;
189
190 let mut offset = 0;
191
192 let fields = buf.fields().chunks(4).map(NativeEndian::read_u32);
193 let values = buf.values().chunks(4).map(NativeEndian::read_u32);
194 let field_flags = buf
195 .field_flags()
196 .chunks(4)
197 .map(|chunk| RuleFieldFlags::from(NativeEndian::read_u32(chunk)));
198 for (field, value, flags) in fields
199 .zip(values.zip(field_flags))
200 .map(|(field, (value, flags))| (field, value, flags))
201 .take(buf.field_count() as usize)
202 {
203 let field = match field {
204 AUDIT_PID => Pid(value),
205 AUDIT_UID => Uid(value),
206 AUDIT_EUID => Euid(value),
207 AUDIT_SUID => Suid(value),
208 AUDIT_FSUID => Fsuid(value),
209 AUDIT_GID => Gid(value),
210 AUDIT_EGID => Egid(value),
211 AUDIT_SGID => Sgid(value),
212 AUDIT_FSGID => Fsgid(value),
213 AUDIT_LOGINUID => Loginuid(value),
214 AUDIT_PERS => Pers(value),
215 AUDIT_ARCH => Arch(value),
216 AUDIT_MSGTYPE => Msgtype(value),
217 AUDIT_PPID => Ppid(value),
218 AUDIT_LOGINUID_SET => LoginuidSet(value),
219 AUDIT_SESSIONID => Sessionid(value),
220 AUDIT_FSTYPE => Fstype(value),
221 AUDIT_DEVMAJOR => Devmajor(value),
222 AUDIT_DEVMINOR => Devminor(value),
223 AUDIT_INODE => Inode(value),
224 AUDIT_EXIT => Exit(value),
225 AUDIT_SUCCESS => Success(value),
226 AUDIT_PERM => Perm(value),
227 AUDIT_FILETYPE => Filetype(value),
228 AUDIT_OBJ_UID => ObjUid(value),
229 AUDIT_OBJ_GID => ObjGid(value),
230 AUDIT_FIELD_COMPARE => FieldCompare(value),
231 AUDIT_EXE => Exe(value),
232 AUDIT_ARG0 => Arg0(value),
233 AUDIT_ARG1 => Arg1(value),
234 AUDIT_ARG2 => Arg2(value),
235 AUDIT_ARG3 => Arg3(value),
236 _ => {
237 let str_end = offset + value as usize;
239 if str_end > buf.buf().len() {
240 return Err(format!(
241 "failed to decode field. type={field} \
242 (value should be a string?)"
243 )
244 .into());
245 }
246 let s: String =
247 String::from_utf8_lossy(&buf.buf()[offset..str_end])
248 .into();
249 offset = str_end;
250 match field {
251 AUDIT_WATCH => Watch(s),
252 AUDIT_DIR => Dir(s),
253 AUDIT_FILTERKEY => Filterkey(s),
254 AUDIT_SUBJ_USER => SubjUser(s),
255 AUDIT_SUBJ_ROLE => SubjRole(s),
256 AUDIT_SUBJ_TYPE => SubjType(s),
257 AUDIT_SUBJ_SEN => SubjSen(s),
258 AUDIT_SUBJ_CLR => SubjClr(s),
259 AUDIT_OBJ_USER => ObjUser(s),
260 AUDIT_OBJ_ROLE => ObjRole(s),
261 AUDIT_OBJ_TYPE => ObjType(s),
262 AUDIT_OBJ_LEV_LOW => ObjLevLow(s),
263 AUDIT_OBJ_LEV_HIGH => ObjLevHigh(s),
264 _ => {
265 return Err(format!(
266 "failed to decode field (unknown type) \
267 type={field}, value={s}"
268 )
269 .into());
270 }
271 }
272 }
273 };
274 rule.fields.push((field, flags));
275 }
276 Ok(rule)
277 }
278}