selinux/policy/
parser.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::fmt::Debug;
6use std::sync::Arc;
7use zerocopy::{FromBytes, Immutable, KnownLayout, Unaligned};
8
9pub type PolicyData = Arc<Vec<u8>>;
10pub type PolicyOffset = u32;
11
12#[derive(Clone, Debug, PartialEq)]
13pub struct PolicyCursor {
14    data: PolicyData,
15    offset: PolicyOffset,
16}
17
18impl PolicyCursor {
19    /// Returns a new [`PolicyCursor`] that wraps `data` in a [`Cursor`] for parsing.
20    pub fn new(data: PolicyData) -> Self {
21        Self { data, offset: 0 }
22    }
23
24    /// Returns a new [`PolicyCursor`] that wraps `data` in a [`Cursor`] for parsing at `offset`.
25    pub fn new_at(data: PolicyData, offset: PolicyOffset) -> Self {
26        Self { data, offset }
27    }
28
29    /// Returns an `P` as the parsed output of the next bytes in the underlying [`Cursor`] data.
30    pub fn parse<P: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned>(
31        mut self,
32    ) -> Option<(P, Self)> {
33        let (output, _) = P::read_from_prefix(self.remaining_slice()).ok()?;
34        self.seek_forward(std::mem::size_of_val(&output)).ok()?;
35        Some((output, self))
36    }
37
38    pub fn offset(&self) -> PolicyOffset {
39        self.offset
40    }
41
42    pub fn len(&self) -> usize {
43        self.data.len() - self.offset as usize
44    }
45
46    /// Seeks forward by `num_bytes`, returning a `std::io::Error` if seeking fails.
47    fn seek_forward(&mut self, num_bytes: usize) -> Result<(), std::io::Error> {
48        if num_bytes > self.len() {
49            return Err(std::io::Error::from(std::io::ErrorKind::UnexpectedEof));
50        }
51        self.offset += num_bytes as PolicyOffset;
52        Ok(())
53    }
54
55    pub fn data(&self) -> &PolicyData {
56        &self.data
57    }
58
59    /// Returns a slice of remaining data.
60    fn remaining_slice(&self) -> &[u8] {
61        let s: &[u8] = self.data.as_ref();
62        let p = self.offset as usize;
63        &s[p..]
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use zerocopy::little_endian as le;
71
72    #[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
73    #[repr(C, packed)]
74    struct SomeNumbers {
75        a: u8,
76        b: le::U32,
77        c: le::U16,
78        d: u8,
79    }
80
81    #[test]
82    fn entire_vector() {
83        let bytes: Vec<u8> = (0..8).collect();
84        let data = Arc::new(bytes);
85
86        let tail = PolicyCursor::new(data);
87        let (some_numbers, tail) = tail.parse::<SomeNumbers>().expect("some numbers");
88
89        assert_eq!(0, some_numbers.a);
90        assert_eq!((1 << 0) + (2 << 8) + (3 << 16) + (4 << 24), some_numbers.b.get());
91        assert_eq!((5 << 0) + (6 << 8), some_numbers.c.get());
92        assert_eq!(7, some_numbers.d);
93        assert_eq!(8, tail.offset());
94        assert_eq!(0, tail.len());
95        assert_eq!(8, tail.data().len());
96    }
97
98    #[test]
99    fn range_within_vector() {
100        let bytes: Vec<u8> = (0..40).collect();
101        let data = Arc::new(bytes);
102
103        let tail = PolicyCursor::new_at(data, 8);
104        let (first_some_numbers, tail) = tail.parse::<SomeNumbers>().expect("some numbers");
105        let (second_some_numbers, tail) = tail.parse::<SomeNumbers>().expect("some numbers");
106        let (third_some_numbers, tail) = tail.parse::<SomeNumbers>().expect("some numbers");
107
108        assert_eq!(8, first_some_numbers.a);
109        assert_eq!((9 << 0) + (10 << 8) + (11 << 16) + (12 << 24), first_some_numbers.b.get());
110        assert_eq!((13 << 0) + (14 << 8), first_some_numbers.c.get());
111        assert_eq!(15, first_some_numbers.d);
112        assert_eq!(16, second_some_numbers.a);
113        assert_eq!((17 << 0) + (18 << 8) + (19 << 16) + (20 << 24), second_some_numbers.b.get());
114        assert_eq!((21 << 0) + (22 << 8), second_some_numbers.c.get());
115        assert_eq!(23, second_some_numbers.d);
116        assert_eq!(24, third_some_numbers.a);
117        assert_eq!((25 << 0) + (26 << 8) + (27 << 16) + (28 << 24), third_some_numbers.b.get());
118        assert_eq!((29 << 0) + (30 << 8), third_some_numbers.c.get());
119        assert_eq!(31, third_some_numbers.d);
120        assert_eq!(32, tail.offset());
121        assert_eq!(8, tail.len());
122        assert_eq!(40, tail.data().len());
123    }
124}