Skip to main content

selinux/policy/
metadata.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
5#[cfg(test)]
6use super::Parse;
7#[cfg(test)]
8use super::error::ParseError;
9#[cfg(test)]
10use super::error::ValidateError;
11#[cfg(test)]
12use super::parser::PolicyCursor;
13#[cfg(test)]
14use super::{
15    Array, Counted, PolicyValidationContext, Validate, ValidateArray, array_type,
16    array_type_validate_deref_both,
17};
18
19#[cfg(test)]
20use zerocopy::{FromBytes, Immutable, KnownLayout, Unaligned, little_endian as le};
21
22#[cfg(test)]
23use crate::new_policy::HandleUnknown;
24
25pub(super) const SELINUX_MAGIC: u32 = 0xf97cff8c;
26
27pub(super) const POLICYDB_STRING_MAX_LENGTH: u32 = 32;
28pub(super) const POLICYDB_SIGNATURE: &[u8] = b"SE Linux";
29
30pub(super) const POLICYDB_VERSION_MIN: u32 = 30;
31pub const POLICYDB_VERSION_MAX: u32 = 33;
32
33pub(super) const CONFIG_MLS_FLAG: u32 = 1;
34pub(super) const CONFIG_HANDLE_UNKNOWN_REJECT_FLAG: u32 = 1 << 1;
35pub(super) const CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG: u32 = 1 << 2;
36pub(super) const CONFIG_HANDLE_UNKNOWN_MASK: u32 =
37    CONFIG_HANDLE_UNKNOWN_REJECT_FLAG | CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG;
38
39#[cfg(test)]
40#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
41#[repr(C, packed)]
42pub(super) struct Magic(le::U32);
43
44#[cfg(test)]
45impl Validate for Magic {
46    type Error = ValidateError;
47
48    fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
49        let found_magic = self.0.get();
50        if found_magic != SELINUX_MAGIC {
51            Err(ValidateError::InvalidMagic { found_magic })
52        } else {
53            Ok(())
54        }
55    }
56}
57
58#[cfg(test)]
59array_type!(Signature, SignatureMetadata, u8);
60
61#[cfg(test)]
62array_type_validate_deref_both!(Signature);
63
64#[cfg(test)]
65impl ValidateArray<SignatureMetadata, u8> for Signature {
66    type Error = ValidateError;
67
68    fn validate_array(
69        _context: &PolicyValidationContext,
70        _metadata: &SignatureMetadata,
71        items: &[u8],
72    ) -> Result<(), Self::Error> {
73        if items != POLICYDB_SIGNATURE {
74            Err(ValidateError::InvalidSignature { found_signature: items.to_owned() })
75        } else {
76            Ok(())
77        }
78    }
79}
80
81#[cfg(test)]
82#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
83#[repr(C, packed)]
84pub(super) struct SignatureMetadata(le::U32);
85
86#[cfg(test)]
87impl Validate for SignatureMetadata {
88    type Error = ValidateError;
89
90    /// [`SignatureMetadata`] has no constraints.
91    fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
92        let found_length = self.0.get();
93        if found_length > POLICYDB_STRING_MAX_LENGTH {
94            Err(ValidateError::InvalidSignatureLength { found_length })
95        } else {
96            Ok(())
97        }
98    }
99}
100
101#[cfg(test)]
102impl Counted for SignatureMetadata {
103    fn count(&self) -> u32 {
104        self.0.get()
105    }
106}
107
108#[cfg(test)]
109#[derive(Debug)]
110pub(super) struct Config {
111    #[allow(dead_code)]
112    config: le::U32,
113}
114
115#[cfg(test)]
116impl Parse for Config {
117    type Error = ParseError;
118
119    fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
120        let (config, tail) = PolicyCursor::parse::<le::U32>(bytes)?;
121
122        let found_config = config.get();
123        if found_config & CONFIG_MLS_FLAG == 0 {
124            return Err(ParseError::ConfigMissingMlsFlag { found_config });
125        }
126        let _ = try_handle_unknown_fom_config(found_config)?;
127
128        Ok((Self { config }, tail))
129    }
130}
131
132#[cfg(test)]
133impl Validate for Config {
134    type Error = anyhow::Error;
135
136    /// All validation for [`Config`] is necessary to parse it correctly. No additional validation
137    /// required.
138    fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
139        Ok(())
140    }
141}
142
143#[cfg(test)]
144fn try_handle_unknown_fom_config(config: u32) -> Result<HandleUnknown, ParseError> {
145    match config & CONFIG_HANDLE_UNKNOWN_MASK {
146        CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG => Ok(HandleUnknown::Allow),
147        CONFIG_HANDLE_UNKNOWN_REJECT_FLAG => Ok(HandleUnknown::Reject),
148        0 => Ok(HandleUnknown::Deny),
149        _ => Err(ParseError::InvalidHandleUnknownConfigurationBits {
150            masked_bits: (config & CONFIG_HANDLE_UNKNOWN_MASK),
151        }),
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::super::parser::{PolicyCursor, PolicyData};
158    use super::super::testing::as_parse_error;
159
160    use super::*;
161
162    // TODO: Run this test over `validate()`.
163    #[test]
164    fn no_magic() {
165        let mut bytes = [SELINUX_MAGIC.to_le_bytes().as_slice()].concat();
166        // One byte short of magic.
167        bytes.pop();
168        let data = PolicyData::from(bytes);
169        assert_eq!(
170            Err(ParseError::MissingData {
171                type_name: "selinux_lib_test::policy::metadata::Magic",
172                type_size: 4,
173                num_bytes: 3
174            }),
175            PolicyCursor::parse::<Magic>(PolicyCursor::new(&data)),
176        );
177    }
178
179    #[test]
180    fn missing_signature() {
181        let bytes = [(1 as u32).to_le_bytes().as_slice()].concat();
182        let data = PolicyData::from(bytes);
183        match Signature::parse(PolicyCursor::new(&data)).err().map(as_parse_error) {
184            Some(ParseError::MissingData { type_name: "u8", type_size: 1, num_bytes: 0 }) => {}
185            parse_err => {
186                assert!(false, "Expected Some(MissingData...), but got {:?}", parse_err);
187            }
188        }
189    }
190
191    #[test]
192    fn config_missing_mls_flag() {
193        let bytes = [(!CONFIG_MLS_FLAG).to_le_bytes().as_slice()].concat();
194        let data = PolicyData::from(bytes);
195        match Config::parse(PolicyCursor::new(&data)).err() {
196            Some(ParseError::ConfigMissingMlsFlag { .. }) => {}
197            parse_err => {
198                assert!(false, "Expected Some(ConfigMissingMlsFlag...), but got {:?}", parse_err);
199            }
200        }
201    }
202
203    #[test]
204    fn invalid_handle_unknown() {
205        let bytes = [(CONFIG_MLS_FLAG
206            | CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG
207            | CONFIG_HANDLE_UNKNOWN_REJECT_FLAG)
208            .to_le_bytes()
209            .as_slice()]
210        .concat();
211        let data = PolicyData::from(bytes);
212        assert_eq!(
213            Some(ParseError::InvalidHandleUnknownConfigurationBits {
214                masked_bits: CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG | CONFIG_HANDLE_UNKNOWN_REJECT_FLAG
215            }),
216            Config::parse(PolicyCursor::new(&data)).err()
217        );
218    }
219}