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::io::{Cursor, Seek as _, SeekFrom};
7use std::ops::Deref;
8use zerocopy::{FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned};
9
10/// Trait for a cursor that can emit a slice of "remaining" data, and advance forward.
11trait ParseCursor: Sized {
12    /// The inner representation that owns the underlying data.
13    type Inner;
14
15    /// The error returned when seeking forward fails on this cursor.
16    type Error;
17
18    /// Returns a slice of remaining data.
19    fn remaining_slice(&self) -> &[u8];
20
21    /// Returns the number of bytes remaining to be parsed by this [`ParseCursor`].
22    fn len(&self) -> usize;
23
24    /// Seeks forward by `num_bytes`, returning a `Self::Error` if seeking fails.
25    fn seek_forward(&mut self, num_bytes: usize) -> Result<(), Self::Error>;
26
27    /// Consumes self and returns the inner representation of the complete parse input.
28    #[allow(dead_code)]
29    fn into_inner(self) -> Self::Inner;
30}
31
32impl<T: AsRef<[u8]>> ParseCursor for Cursor<T> {
33    type Inner = T;
34    type Error = std::io::Error;
35
36    fn remaining_slice(&self) -> &[u8] {
37        let s: &[u8] = self.get_ref().as_ref();
38        let p = self.position() as usize;
39        &s[p..]
40    }
41
42    fn len(&self) -> usize {
43        let position = self.position() as usize;
44        self.get_ref().as_ref().len() - position
45    }
46
47    fn seek_forward(&mut self, num_bytes: usize) -> Result<(), Self::Error> {
48        self.seek(SeekFrom::Current(num_bytes as i64)).map(|_| ())
49    }
50
51    #[allow(dead_code)]
52    fn into_inner(self) -> Self::Inner {
53        self.into_inner()
54    }
55}
56
57/// A strategy for parsing data. Parsed structures that may contain references to parsed data are
58/// generally of the form:
59///
60/// ```rust,ignore
61/// type ParserOutput<PS: ParseStrategy> {
62///     ref_or_value_t: PS::Output<T>,
63///     // ...
64/// }
65/// ```
66///
67/// The above pattern allows [`ParseStrategy`] implementations to dictate how values are stored (by
68/// copied value, or reference to parser input data).
69pub trait ParseStrategy: Debug + PartialEq + Sized {
70    /// Type of input supported by this [`ParseStrategy`].
71    type Input;
72
73    /// Type of successfully parsed output from `Self::parse()`.
74    type Output<T: Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned>: Debug
75        + PartialEq;
76
77    /// Type of successfully parsed output from `Self::parse_slice()`.
78    type Slice<T: Debug + FromBytes + Immutable + PartialEq + Unaligned>: Debug + PartialEq;
79
80    /// Parses a `Self::Output<T>` from the next bytes underlying `self`. If the parse succeeds,
81    /// then return `(Some(output), self)` after advancing past the parsed bytes. Otherwise, return
82    /// `None` without advancing past the parsed bytes.
83    fn parse<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned>(
84        self,
85    ) -> Option<(Self::Output<T>, Self)>;
86
87    /// Parses a `Self::Slice<T>` of `count` elements from the next bytes underlying `self`. If the
88    /// parse succeeds, then return `(Some(slice), self)` after advancing past the parsed bytes.
89    /// Otherwise, return `None` without advancing past the parsed bytes.
90    fn parse_slice<T: Clone + Debug + FromBytes + Immutable + PartialEq + Unaligned>(
91        self,
92        count: usize,
93    ) -> Option<(Self::Slice<T>, Self)>;
94
95    /// Dereferences borrow of `Self::Output<T>` as borrow of `T`.
96    fn deref<'a, T: Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned>(
97        output: &'a Self::Output<T>,
98    ) -> &'a T;
99
100    /// Dereferences borrow of `Self::Slice<T>` as borrow of `[T]`.
101    fn deref_slice<'a, T: Debug + FromBytes + Immutable + PartialEq + Unaligned>(
102        slice: &'a Self::Slice<T>,
103    ) -> &'a [T];
104
105    /// Returns the number of bytes remaining to be parsed by this [`ParseStrategy`].
106    fn len(&self) -> usize;
107
108    /// Returns the complete parse input being consumed by this strategy.
109    fn into_inner(self) -> Self::Input;
110}
111
112/// A [`ParseStrategy`] that produces [`Ref<B, T>`].
113///
114/// This strategy is zero-copy, but one consequence is that the parser input and output cannot be
115/// retained outside the lexical scope from which the parser input was borrowed. For example, the
116/// following will not compile:
117///
118/// ```rust,ignore
119/// fn do_by_ref<'a, T: zerocopy::FromBytes + zerocopy::Unaligned>() -> (
120///     zerocopy::Ref<&'a [u8], T>, ByRef<&'a [u8]>,
121/// ) {
122///     let bytes: Vec<u8> = // ...
123///     let parser = ByRef::new(bytes.as_slice());
124///     parser.parse::<T>().unwrap()
125/// }
126/// ```
127///
128/// The above code induces the following error:
129///
130/// ```rust,ignore
131/// error[E0515]: cannot return value referencing local variable `bytes`
132/// ```
133#[derive(Clone, Debug, PartialEq)]
134pub struct ByRef<B: SplitByteSlice> {
135    input: B,
136    tail: B,
137}
138
139impl<B: SplitByteSlice + Clone> ByRef<B> {
140    /// Returns a new [`ByRef`] that wraps `bytes_slice`.
141    pub fn new(byte_slice: B) -> Self {
142        Self { input: byte_slice.clone(), tail: byte_slice }
143    }
144}
145
146impl<B: Debug + SplitByteSlice + PartialEq> ParseStrategy for ByRef<B> {
147    type Input = B;
148    type Output<T: Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> = Ref<B, T>;
149    type Slice<T: Debug + FromBytes + Immutable + PartialEq + Unaligned> = Ref<B, [T]>;
150
151    /// Returns a [`Ref<B, T>`] as the parsed output of the next bytes in the underlying
152    /// [`ByteSlice`].
153    fn parse<T: Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned>(
154        self,
155    ) -> Option<(Self::Output<T>, Self)> {
156        let (output, tail) = Ref::from_prefix(self.tail).ok()?;
157        Some((output, Self { input: self.input, tail }))
158    }
159
160    /// Returns a `Ref<B, [T]>` as the parsed output of the next bytes in the underlying
161    /// [`ByteSlice`].
162    fn parse_slice<T: Clone + Debug + FromBytes + Immutable + PartialEq + Unaligned>(
163        self,
164        num: usize,
165    ) -> Option<(Self::Slice<T>, Self)> {
166        let (slice, tail) = Ref::from_prefix_with_elems(self.tail, num).ok()?;
167        Some((slice, Self { input: self.input, tail }))
168    }
169
170    fn deref<'a, T: Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned>(
171        output: &'a Self::Output<T>,
172    ) -> &'a T {
173        output.deref() as &T
174    }
175
176    fn deref_slice<'a, T: Debug + FromBytes + Immutable + PartialEq + Unaligned>(
177        slice: &'a Self::Slice<T>,
178    ) -> &'a [T] {
179        slice.deref() as &[T]
180    }
181
182    fn len(&self) -> usize {
183        self.tail.len()
184    }
185
186    fn into_inner(self) -> Self::Input {
187        self.input
188    }
189}
190
191/// A [`ParseStrategy`] that produces (copied/cloned) `T`.
192///
193/// This strategy makes up to one copy of the parser input (in addition to parser output data
194/// structures). It is intended to support use cases where the parser input and parser output must
195/// be retained outside the lexical from which parsing is invoked. For example:
196///
197/// ```rust,ignore
198/// fn do_by_value<
199///     D: AsRef<[u8]> + Debug + PartialEq,
200///     T: zerocopy::FromBytes + zerocopy::Unaligned,
201/// >(
202///     data: D,
203/// ) -> (T, ByValue<D>) {
204///     let parser = ByValue::new(data);
205///     parser.parse::<T>().unwrap()
206/// }
207/// ```
208#[derive(Clone, Debug, PartialEq)]
209pub struct ByValue<T: AsRef<[u8]>>(Cursor<T>);
210
211impl<T: AsRef<[u8]>> ByValue<T> {
212    /// Returns a new [`ByValue`] that wraps `data` in a [`Cursor`] for parsing.
213    pub fn new(data: T) -> Self {
214        Self(Cursor::new(data))
215    }
216}
217
218impl<T: AsRef<[u8]> + Debug + PartialEq> ParseStrategy for ByValue<T>
219where
220    Cursor<T>: Debug + ParseCursor + PartialEq,
221{
222    type Input = T;
223    type Output<O: Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> = O;
224    type Slice<S: Debug + FromBytes + Immutable + PartialEq + Unaligned> = Vec<S>;
225
226    /// Returns an `P` as the parsed output of the next bytes in the underlying [`Cursor`] data.
227    fn parse<P: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned>(
228        mut self,
229    ) -> Option<(Self::Output<P>, Self)> {
230        let (output, _) = P::read_from_prefix(ParseCursor::remaining_slice(&self.0)).ok()?;
231        if self.0.seek_forward(std::mem::size_of_val(&output)).is_err() {
232            return None;
233        }
234        Some((output, self))
235    }
236
237    /// Returns a `Vec<T>` of `count` items as the parsed output of the next bytes in the underlying
238    /// [`Cursor`] data.
239    fn parse_slice<PS: Clone + Debug + FromBytes + Immutable + PartialEq + Unaligned>(
240        mut self,
241        count: usize,
242    ) -> Option<(Self::Slice<PS>, Self)> {
243        let (slice, _) =
244            <[PS]>::ref_from_prefix_with_elems(ParseCursor::remaining_slice(&self.0), count)
245                .ok()?;
246        let size = std::mem::size_of_val(&slice);
247        let slice = slice.to_owned();
248        if self.0.seek_forward(size).is_err() {
249            return None;
250        }
251        Some((slice, self))
252    }
253
254    fn deref<'a, D: Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned>(
255        output: &'a Self::Output<D>,
256    ) -> &'a D {
257        output
258    }
259
260    fn deref_slice<'a, DS: Debug + FromBytes + Immutable + PartialEq + Unaligned>(
261        slice: &'a Self::Slice<DS>,
262    ) -> &'a [DS] {
263        slice
264    }
265
266    fn len(&self) -> usize {
267        self.0.len()
268    }
269
270    fn into_inner(self) -> Self::Input {
271        self.0.into_inner()
272    }
273}
274
275#[cfg(test)]
276mod tests {
277    use super::*;
278    use zerocopy::little_endian as le;
279
280    #[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
281    #[repr(C, packed)]
282    struct SomeNumbers {
283        a: u8,
284        b: le::U32,
285        c: le::U16,
286        d: u8,
287    }
288
289    // Ensure that "return parser + parsed output" pattern works on `ByValue`.
290    fn do_by_value<
291        D: AsRef<[u8]> + Debug + PartialEq,
292        T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned,
293    >(
294        data: D,
295    ) -> (T, ByValue<D>) {
296        let parser = ByValue::new(data);
297        parser.parse::<T>().expect("some numbers")
298    }
299    fn do_slice_by_value<
300        D: AsRef<[u8]> + Debug + PartialEq,
301        T: Clone + Debug + FromBytes + Immutable + PartialEq + Unaligned,
302    >(
303        data: D,
304        count: usize,
305    ) -> (Vec<T>, ByValue<D>) {
306        let parser = ByValue::new(data);
307        parser.parse_slice::<T>(count).expect("some numbers")
308    }
309
310    #[test]
311    fn by_ref_slice_u8_parse() {
312        let bytes: Vec<u8> = (0..8).collect();
313        let parser = ByRef::new(bytes.as_slice());
314        let (some_numbers, parser) = parser.parse::<SomeNumbers>().expect("some numbers");
315        assert_eq!(0, some_numbers.a);
316        assert_eq!(7, some_numbers.d);
317        assert_eq!(0, parser.tail.len());
318    }
319
320    #[test]
321    fn by_ref_slice_u8_parse_slice() {
322        let bytes: Vec<u8> = (0..24).collect();
323        let parser = ByRef::new(bytes.as_slice());
324        let (some_numbers, parser) = parser.parse_slice::<SomeNumbers>(3).expect("some numbers");
325        assert_eq!(3, some_numbers.len());
326        assert_eq!(0, some_numbers[0].a);
327        assert_eq!(7, some_numbers[0].d);
328        assert_eq!(8, some_numbers[1].a);
329        assert_eq!(15, some_numbers[1].d);
330        assert_eq!(16, some_numbers[2].a);
331        assert_eq!(23, some_numbers[2].d);
332        assert_eq!(0, parser.tail.len());
333    }
334
335    #[test]
336    fn by_value_cursor_vec_u8() {
337        let bytes: Vec<u8> = (0..8).collect();
338        let (some_numbers, parser) = do_by_value::<_, SomeNumbers>(bytes);
339        assert_eq!(0, some_numbers.a);
340        assert_eq!(7, some_numbers.d);
341        assert_eq!(8, parser.0.position());
342        assert_eq!(8, parser.into_inner().len());
343    }
344
345    #[test]
346    fn by_value_slice_u8_parse_slice() {
347        let bytes: Vec<u8> = (0..24).collect();
348        let (some_numbers, parser) = do_slice_by_value::<_, SomeNumbers>(bytes.as_slice(), 3);
349        assert_eq!(3, some_numbers.len());
350        assert_eq!(0, some_numbers[0].a);
351        assert_eq!(7, some_numbers[0].d);
352        assert_eq!(8, some_numbers[1].a);
353        assert_eq!(15, some_numbers[1].d);
354        assert_eq!(16, some_numbers[2].a);
355        assert_eq!(23, some_numbers[2].d);
356        assert_eq!(24, parser.into_inner().len());
357    }
358}