use byteorder::{ByteOrder, NativeEndian};
use netlink_packet_utils::DecodeError;
use crate::constants::*;
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub struct RuleSyscalls(pub(crate) Vec<u32>);
const BITMASK_BYTE_LEN: usize = AUDIT_BITMASK_SIZE * 4;
const BITMASK_BIT_LEN: u32 = AUDIT_BITMASK_SIZE as u32 * 32;
impl RuleSyscalls {
pub fn from_slice(slice: &[u8]) -> Result<Self, DecodeError> {
if slice.len() != BITMASK_BYTE_LEN {
return Err(DecodeError::from(format!(
"invalid bitmask size: expected {} bytes got {}",
BITMASK_BYTE_LEN,
slice.len()
)));
}
let mut mask = RuleSyscalls::new_zeroed();
let mut word = 0;
while word < AUDIT_BITMASK_SIZE {
mask.0[word] =
NativeEndian::read_u32(&slice[word * 4..word * 4 + 4]);
word += 1;
}
Ok(mask)
}
pub fn new_zeroed() -> Self {
RuleSyscalls(vec![0; AUDIT_BITMASK_SIZE])
}
pub fn new_maxed() -> Self {
RuleSyscalls(vec![0xffff_ffff; AUDIT_BITMASK_SIZE])
}
pub fn unset_all(&mut self) -> &mut Self {
self.0 = vec![0; AUDIT_BITMASK_SIZE];
self
}
pub fn is_all(&self) -> bool {
for i in 0..AUDIT_BITMASK_SIZE {
if self.0[i] != 0xffff_ffff {
return false;
}
}
true
}
pub fn set_all(&mut self) -> &mut Self {
self.0 = vec![0xffff_ffff; AUDIT_BITMASK_SIZE];
self
}
pub fn unset(&mut self, syscall: u32) -> &mut Self {
let (word, mask) = Self::syscall_coordinates(syscall);
self.0[word] &= !mask;
self
}
pub fn set(&mut self, syscall: u32) -> &mut Self {
let (word, mask) = Self::syscall_coordinates(syscall);
self.0[word] |= mask;
self
}
pub fn has(&self, syscall: u32) -> bool {
let (word, mask) = Self::syscall_coordinates(syscall);
self.0[word] & mask == mask
}
fn syscall_coordinates(syscall: u32) -> (usize, u32) {
let word_index = syscall / 32;
let mask = 0x0000_0001 << (syscall - word_index * 32);
(word_index as usize, mask)
}
}
#[non_exhaustive]
pub struct RuleSyscallsIter<T> {
index: u32,
syscalls: T,
}
impl IntoIterator for RuleSyscalls {
type Item = u32;
type IntoIter = RuleSyscallsIter<RuleSyscalls>;
fn into_iter(self) -> Self::IntoIter {
RuleSyscallsIter {
index: 0,
syscalls: self,
}
}
}
impl Iterator for RuleSyscallsIter<RuleSyscalls> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
while self.index < BITMASK_BIT_LEN {
let index = self.index;
self.index += 1;
if self.syscalls.has(index) {
return Some(index);
}
}
None
}
}
impl<'a> IntoIterator for &'a RuleSyscalls {
type Item = u32;
type IntoIter = RuleSyscallsIter<&'a RuleSyscalls>;
fn into_iter(self) -> Self::IntoIter {
RuleSyscallsIter {
index: 0,
syscalls: self,
}
}
}
impl<'a> Iterator for RuleSyscallsIter<&'a RuleSyscalls> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
while self.index < BITMASK_BIT_LEN {
let index = self.index;
self.index += 1;
if self.syscalls.has(index) {
return Some(index);
}
}
None
}
}
impl<'a> IntoIterator for &'a mut RuleSyscalls {
type Item = u32;
type IntoIter = RuleSyscallsIter<&'a mut RuleSyscalls>;
fn into_iter(self) -> Self::IntoIter {
RuleSyscallsIter {
index: 0,
syscalls: self,
}
}
}
impl<'a> Iterator for RuleSyscallsIter<&'a mut RuleSyscalls> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
while self.index < BITMASK_BIT_LEN {
let index = self.index;
self.index += 1;
if self.syscalls.has(index) {
return Some(index);
}
}
None
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_from_slice() {
let s: Vec<u8> = vec![0xff; BITMASK_BYTE_LEN];
let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();
assert_eq!(syscalls.0, vec![0xffff_ffff; AUDIT_BITMASK_SIZE]);
let s: Vec<u8> = vec![0; BITMASK_BYTE_LEN];
let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();
assert_eq!(syscalls.0, vec![0; AUDIT_BITMASK_SIZE]);
}
#[test]
fn test_iter() {
let s: Vec<u8> = vec![0xff; BITMASK_BYTE_LEN];
let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();
let mut iter = syscalls.into_iter();
for i in 0..BITMASK_BIT_LEN {
assert_eq!(i, iter.next().unwrap());
}
assert!(iter.next().is_none());
let s: Vec<u8> = vec![0; BITMASK_BYTE_LEN];
let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();
let mut iter = syscalls.into_iter();
assert!(iter.next().is_none());
}
#[test]
fn test_set_unset() {
let mut syscalls = RuleSyscalls::new_zeroed();
for i in 0..BITMASK_BIT_LEN {
syscalls.set(i);
}
assert_eq!(syscalls.0, vec![0xffff_ffff; AUDIT_BITMASK_SIZE]);
for i in 0..BITMASK_BIT_LEN {
syscalls.unset(BITMASK_BIT_LEN - 1 - i);
}
assert_eq!(syscalls.0, vec![0; AUDIT_BITMASK_SIZE]);
}
}