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    /// Returns a `Vec<T>` of `count` items as the parsed output of the next bytes in the underlying
39    /// [`Cursor`] data.
40    pub fn parse_slice<PS: Clone + Debug + FromBytes + Immutable + PartialEq + Unaligned>(
41        mut self,
42        count: usize,
43    ) -> Option<(Vec<PS>, Self)> {
44        let (slice, _) = <[PS]>::ref_from_prefix_with_elems(self.remaining_slice(), count).ok()?;
45        let size = std::mem::size_of_val(&slice);
46        let slice = slice.to_owned();
47        self.seek_forward(size).ok()?;
48        Some((slice, self))
49    }
50
51    pub fn offset(&self) -> PolicyOffset {
52        self.offset
53    }
54
55    pub fn len(&self) -> usize {
56        self.data.len() - self.offset as usize
57    }
58
59    /// Seeks forward by `num_bytes`, returning a `std::io::Error` if seeking fails.
60    pub fn seek_forward(&mut self, num_bytes: usize) -> Result<(), std::io::Error> {
61        if num_bytes > self.len() {
62            return Err(std::io::Error::from(std::io::ErrorKind::UnexpectedEof));
63        }
64        self.offset += num_bytes as PolicyOffset;
65        Ok(())
66    }
67
68    pub fn data(&self) -> &PolicyData {
69        &self.data
70    }
71
72    /// Returns a slice of remaining data.
73    fn remaining_slice(&self) -> &[u8] {
74        let s: &[u8] = self.data.as_ref();
75        let p = self.offset as usize;
76        &s[p..]
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use zerocopy::little_endian as le;
84
85    #[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
86    #[repr(C, packed)]
87    struct SomeNumbers {
88        a: u8,
89        b: le::U32,
90        c: le::U16,
91        d: u8,
92    }
93
94    // Ensure that "return parser + parsed output" pattern works on `PolicyCursor`.
95    fn do_by_value<
96        T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned,
97    >(
98        data: Vec<u8>,
99    ) -> (T, PolicyCursor) {
100        let parser = PolicyCursor::new(Arc::new(data));
101        parser.parse::<T>().expect("some numbers")
102    }
103    fn do_slice_by_value<T: Clone + Debug + FromBytes + Immutable + PartialEq + Unaligned>(
104        data: Vec<u8>,
105        count: usize,
106    ) -> (Vec<T>, PolicyCursor) {
107        let parser = PolicyCursor::new(Arc::new(data));
108        parser.parse_slice::<T>(count).expect("some numbers")
109    }
110
111    #[test]
112    fn by_value_cursor_vec_u8() {
113        let bytes: Vec<u8> = (0..8).collect();
114        let (some_numbers, parser) = do_by_value::<SomeNumbers>(bytes);
115        assert_eq!(0, some_numbers.a);
116        assert_eq!(7, some_numbers.d);
117        assert_eq!(8, parser.offset);
118        assert_eq!(8, parser.data.len());
119    }
120
121    #[test]
122    fn by_value_slice_u8_parse_slice() {
123        let bytes: Vec<u8> = (0..24).collect();
124        let (some_numbers, parser) = do_slice_by_value::<SomeNumbers>(bytes, 3);
125        assert_eq!(3, some_numbers.len());
126        assert_eq!(0, some_numbers[0].a);
127        assert_eq!(7, some_numbers[0].d);
128        assert_eq!(8, some_numbers[1].a);
129        assert_eq!(15, some_numbers[1].d);
130        assert_eq!(16, some_numbers[2].a);
131        assert_eq!(23, some_numbers[2].d);
132        assert_eq!(24, parser.data.len());
133    }
134}