netlink_packet_audit/rules/
syscalls.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{parse_u32, DecodeError};
4
5use crate::constants::*;
6
7#[derive(Debug, PartialEq, Eq, Clone)]
8#[non_exhaustive]
9pub struct RuleSyscalls(pub(crate) Vec<u32>);
10
11const BITMASK_BYTE_LEN: usize = AUDIT_BITMASK_SIZE * 4;
12const BITMASK_BIT_LEN: u32 = AUDIT_BITMASK_SIZE as u32 * 32;
13
14// FIXME: I'm not 100% sure this implementation is correct wrt to endianness.
15impl RuleSyscalls {
16    // FIXME: this should be a TryFrom when it stabilized...
17    pub fn from_slice(slice: &[u8]) -> Result<Self, DecodeError> {
18        if slice.len() != BITMASK_BYTE_LEN {
19            return Err(DecodeError::from(format!(
20                "invalid bitmask size: expected {} bytes got {}",
21                BITMASK_BYTE_LEN,
22                slice.len()
23            )));
24        }
25        let mut mask = RuleSyscalls::new_zeroed();
26        let mut word = 0;
27        while word < AUDIT_BITMASK_SIZE {
28            mask.0[word] = parse_u32(&slice[word * 4..word * 4 + 4]).unwrap();
29            word += 1;
30        }
31        Ok(mask)
32    }
33
34    pub fn new_zeroed() -> Self {
35        RuleSyscalls(vec![0; AUDIT_BITMASK_SIZE])
36    }
37
38    pub fn new_maxed() -> Self {
39        RuleSyscalls(vec![0xffff_ffff; AUDIT_BITMASK_SIZE])
40    }
41
42    /// Unset all the bits
43    pub fn unset_all(&mut self) -> &mut Self {
44        self.0 = vec![0; AUDIT_BITMASK_SIZE];
45        self
46    }
47
48    /// Return `true` if all the syscalls are set, `false` otherwise
49    pub fn is_all(&self) -> bool {
50        for i in 0..AUDIT_BITMASK_SIZE {
51            if self.0[i] != 0xffff_ffff {
52                return false;
53            }
54        }
55        true
56    }
57
58    /// Set all the bits
59    pub fn set_all(&mut self) -> &mut Self {
60        self.0 = vec![0xffff_ffff; AUDIT_BITMASK_SIZE];
61        self
62    }
63
64    /// Unset the bit corresponding to the given syscall
65    pub fn unset(&mut self, syscall: u32) -> &mut Self {
66        let (word, mask) = Self::syscall_coordinates(syscall);
67        self.0[word] &= !mask;
68        self
69    }
70
71    /// Set the bit corresponding to the given syscall
72    pub fn set(&mut self, syscall: u32) -> &mut Self {
73        let (word, mask) = Self::syscall_coordinates(syscall);
74        self.0[word] |= mask;
75        self
76    }
77
78    /// Check if the bit corresponding to the given syscall is set
79    pub fn has(&self, syscall: u32) -> bool {
80        let (word, mask) = Self::syscall_coordinates(syscall);
81        self.0[word] & mask == mask
82    }
83
84    fn syscall_coordinates(syscall: u32) -> (usize, u32) {
85        let word_index = syscall / 32;
86        let mask = 0x0000_0001 << (syscall - word_index * 32);
87        (word_index as usize, mask)
88    }
89}
90
91// FIXME: There is a LOT of copy paste for those iterator implementations...
92// This feels wrong but I could not figure out how to avoid it :(
93
94#[non_exhaustive]
95pub struct RuleSyscallsIter<T> {
96    index: u32,
97    syscalls: T,
98}
99
100impl IntoIterator for RuleSyscalls {
101    type Item = u32;
102    type IntoIter = RuleSyscallsIter<RuleSyscalls>;
103
104    fn into_iter(self) -> Self::IntoIter {
105        RuleSyscallsIter {
106            index: 0,
107            syscalls: self,
108        }
109    }
110}
111
112impl Iterator for RuleSyscallsIter<RuleSyscalls> {
113    type Item = u32;
114    fn next(&mut self) -> Option<Self::Item> {
115        while self.index < BITMASK_BIT_LEN {
116            let index = self.index;
117            self.index += 1;
118            if self.syscalls.has(index) {
119                return Some(index);
120            }
121        }
122        None
123    }
124}
125
126impl<'a> IntoIterator for &'a RuleSyscalls {
127    type Item = u32;
128    type IntoIter = RuleSyscallsIter<&'a RuleSyscalls>;
129
130    fn into_iter(self) -> Self::IntoIter {
131        RuleSyscallsIter {
132            index: 0,
133            syscalls: self,
134        }
135    }
136}
137
138impl Iterator for RuleSyscallsIter<&RuleSyscalls> {
139    type Item = u32;
140    fn next(&mut self) -> Option<Self::Item> {
141        while self.index < BITMASK_BIT_LEN {
142            let index = self.index;
143            self.index += 1;
144            if self.syscalls.has(index) {
145                return Some(index);
146            }
147        }
148        None
149    }
150}
151
152impl<'a> IntoIterator for &'a mut RuleSyscalls {
153    type Item = u32;
154    type IntoIter = RuleSyscallsIter<&'a mut RuleSyscalls>;
155
156    fn into_iter(self) -> Self::IntoIter {
157        RuleSyscallsIter {
158            index: 0,
159            syscalls: self,
160        }
161    }
162}
163
164impl Iterator for RuleSyscallsIter<&mut RuleSyscalls> {
165    type Item = u32;
166    fn next(&mut self) -> Option<Self::Item> {
167        while self.index < BITMASK_BIT_LEN {
168            let index = self.index;
169            self.index += 1;
170            if self.syscalls.has(index) {
171                return Some(index);
172            }
173        }
174        None
175    }
176}
177
178#[cfg(test)]
179mod test {
180    use super::*;
181    #[test]
182    fn test_from_slice() {
183        let s: Vec<u8> = vec![0xff; BITMASK_BYTE_LEN];
184        let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();
185        assert_eq!(syscalls.0, vec![0xffff_ffff; AUDIT_BITMASK_SIZE]);
186
187        let s: Vec<u8> = vec![0; BITMASK_BYTE_LEN];
188        let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();
189        assert_eq!(syscalls.0, vec![0; AUDIT_BITMASK_SIZE]);
190    }
191
192    #[test]
193    fn test_iter() {
194        let s: Vec<u8> = vec![0xff; BITMASK_BYTE_LEN];
195        let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();
196        let mut iter = syscalls.into_iter();
197        for i in 0..BITMASK_BIT_LEN {
198            assert_eq!(i, iter.next().unwrap());
199        }
200        assert!(iter.next().is_none());
201
202        let s: Vec<u8> = vec![0; BITMASK_BYTE_LEN];
203        let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();
204        let mut iter = syscalls.into_iter();
205        assert!(iter.next().is_none());
206    }
207
208    #[test]
209    fn test_set_unset() {
210        let mut syscalls = RuleSyscalls::new_zeroed();
211        for i in 0..BITMASK_BIT_LEN {
212            syscalls.set(i);
213        }
214        assert_eq!(syscalls.0, vec![0xffff_ffff; AUDIT_BITMASK_SIZE]);
215        for i in 0..BITMASK_BIT_LEN {
216            syscalls.unset(BITMASK_BIT_LEN - 1 - i);
217        }
218        assert_eq!(syscalls.0, vec![0; AUDIT_BITMASK_SIZE]);
219    }
220}