1use super::parser::PolicyCursor;
6use super::{
7 Array, Counted, Parse, PolicyValidationContext, Validate, ValidateArray, array_type,
8 array_type_validate_deref_both,
9};
10use crate::policy::error::{ParseError, ValidateError};
11
12use zerocopy::{FromBytes, Immutable, KnownLayout, Unaligned, little_endian as le};
13
14pub(super) const SELINUX_MAGIC: u32 = 0xf97cff8c;
15
16pub(super) const POLICYDB_STRING_MAX_LENGTH: u32 = 32;
17pub(super) const POLICYDB_SIGNATURE: &[u8] = b"SE Linux";
18
19pub(super) const POLICYDB_VERSION_MIN: u32 = 30;
20pub const POLICYDB_VERSION_MAX: u32 = 33;
21
22pub(super) const CONFIG_MLS_FLAG: u32 = 1;
23pub(super) const CONFIG_HANDLE_UNKNOWN_REJECT_FLAG: u32 = 1 << 1;
24pub(super) const CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG: u32 = 1 << 2;
25pub(super) const CONFIG_HANDLE_UNKNOWN_MASK: u32 =
26 CONFIG_HANDLE_UNKNOWN_REJECT_FLAG | CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG;
27
28#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
29#[repr(C, packed)]
30pub(super) struct Magic(le::U32);
31
32impl Validate for Magic {
33 type Error = ValidateError;
34
35 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
36 let found_magic = self.0.get();
37 if found_magic != SELINUX_MAGIC {
38 Err(ValidateError::InvalidMagic { found_magic })
39 } else {
40 Ok(())
41 }
42 }
43}
44
45array_type!(Signature, SignatureMetadata, Vec<u8>);
46
47array_type_validate_deref_both!(Signature);
48
49impl ValidateArray<SignatureMetadata, u8> for Signature {
50 type Error = ValidateError;
51
52 fn validate_array(
53 _context: &mut PolicyValidationContext,
54 _metadata: &SignatureMetadata,
55 items: &[u8],
56 ) -> Result<(), Self::Error> {
57 if items != POLICYDB_SIGNATURE {
58 Err(ValidateError::InvalidSignature { found_signature: items.to_owned() })
59 } else {
60 Ok(())
61 }
62 }
63}
64
65#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
66#[repr(C, packed)]
67pub(super) struct SignatureMetadata(le::U32);
68
69impl Validate for SignatureMetadata {
70 type Error = ValidateError;
71
72 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
74 let found_length = self.0.get();
75 if found_length > POLICYDB_STRING_MAX_LENGTH {
76 Err(ValidateError::InvalidSignatureLength { found_length })
77 } else {
78 Ok(())
79 }
80 }
81}
82
83impl Counted for SignatureMetadata {
84 fn count(&self) -> u32 {
85 self.0.get()
86 }
87}
88
89#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
90#[repr(C, packed)]
91pub(super) struct PolicyVersion(le::U32);
92
93impl PolicyVersion {
94 pub fn policy_version(&self) -> u32 {
95 self.0.get()
96 }
97}
98
99impl Validate for PolicyVersion {
100 type Error = ValidateError;
101
102 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
103 let found_policy_version = self.0.get();
104 if found_policy_version < POLICYDB_VERSION_MIN
105 || found_policy_version > POLICYDB_VERSION_MAX
106 {
107 Err(ValidateError::InvalidPolicyVersion { found_policy_version })
108 } else {
109 Ok(())
110 }
111 }
112}
113
114#[derive(Debug)]
115pub(super) struct Config {
116 handle_unknown: HandleUnknown,
117
118 #[allow(dead_code)]
119 config: le::U32,
120}
121
122impl Config {
123 pub fn handle_unknown(&self) -> HandleUnknown {
124 self.handle_unknown
125 }
126}
127
128impl Parse for Config {
129 type Error = ParseError;
130
131 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
132 let (config, tail) = PolicyCursor::parse::<le::U32>(bytes)?;
133
134 let found_config = config.get();
135 if found_config & CONFIG_MLS_FLAG == 0 {
136 return Err(ParseError::ConfigMissingMlsFlag { found_config });
137 }
138 let handle_unknown = try_handle_unknown_fom_config(found_config)?;
139
140 Ok((Self { handle_unknown, config }, tail))
141 }
142}
143
144impl Validate for Config {
145 type Error = anyhow::Error;
146
147 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
150 Ok(())
151 }
152}
153
154#[derive(Copy, Clone, Debug, PartialEq)]
155pub enum HandleUnknown {
156 Deny,
157 Reject,
158 Allow,
159}
160
161fn try_handle_unknown_fom_config(config: u32) -> Result<HandleUnknown, ParseError> {
162 match config & CONFIG_HANDLE_UNKNOWN_MASK {
163 CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG => Ok(HandleUnknown::Allow),
164 CONFIG_HANDLE_UNKNOWN_REJECT_FLAG => Ok(HandleUnknown::Reject),
165 0 => Ok(HandleUnknown::Deny),
166 _ => Err(ParseError::InvalidHandleUnknownConfigurationBits {
167 masked_bits: (config & CONFIG_HANDLE_UNKNOWN_MASK),
168 }),
169 }
170}
171
172#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
173#[repr(C, packed)]
174pub(super) struct Counts {
175 symbols_count: le::U32,
176 object_context_count: le::U32,
177}
178
179impl Validate for Counts {
180 type Error = anyhow::Error;
181
182 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
184 Ok(())
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 use crate::policy::parser::PolicyCursor;
193 use crate::policy::testing::{as_parse_error, as_validate_error};
194 use std::sync::Arc;
195
196 macro_rules! validate_test {
197 ($parse_output:ident, $data:expr, $result:tt, $check_impl:block) => {{
198 let data = Arc::new($data);
199 let mut context = crate::policy::PolicyValidationContext { data: data.clone() };
200 fn check_by_value(
201 $result: Result<(), <$parse_output as crate::policy::Validate>::Error>,
202 ) {
203 $check_impl
204 }
205
206 let (by_value_parsed, _tail) = $parse_output::parse(PolicyCursor::new(data.clone()))
207 .expect("successful parse for validate test");
208 let by_value_result = by_value_parsed.validate(&mut context);
209 check_by_value(by_value_result);
210 }};
211 }
212
213 #[test]
215 fn no_magic() {
216 let mut bytes = [SELINUX_MAGIC.to_le_bytes().as_slice()].concat();
217 bytes.pop();
219 let data = Arc::new(bytes);
220 assert_eq!(
221 Err(ParseError::MissingData {
222 type_name: "selinux_lib_test::policy::metadata::Magic",
223 type_size: 4,
224 num_bytes: 3
225 }),
226 PolicyCursor::parse::<Magic>(PolicyCursor::new(data)),
227 );
228 }
229
230 #[test]
231 fn invalid_magic() {
232 let mut bytes = [SELINUX_MAGIC.to_le_bytes().as_slice()].concat();
233 bytes[0] = bytes[0] + 1;
235 let bytes = bytes;
236 let expected_invalid_magic =
237 u32::from_le_bytes(bytes.clone().as_slice().try_into().unwrap());
238
239 let data = Arc::new(bytes);
240 let mut context = crate::policy::PolicyValidationContext { data: data.clone() };
241 let (magic, tail) =
242 PolicyCursor::parse::<Magic>(PolicyCursor::new(data.clone())).expect("magic");
243 assert_eq!(data.len(), tail.offset() as usize);
244 assert_eq!(
245 Err(ValidateError::InvalidMagic { found_magic: expected_invalid_magic }),
246 magic.validate(&mut context)
247 );
248 }
249
250 #[test]
251 fn invalid_signature_length() {
252 const INVALID_SIGNATURE_LENGTH: u32 = POLICYDB_STRING_MAX_LENGTH + 1;
253 let bytes: Vec<u8> = [
254 INVALID_SIGNATURE_LENGTH.to_le_bytes().as_slice(),
255 [42u8; INVALID_SIGNATURE_LENGTH as usize].as_slice(),
256 ]
257 .concat();
258
259 validate_test!(Signature, bytes, result, {
260 assert_eq!(
261 Some(ValidateError::InvalidSignatureLength {
262 found_length: INVALID_SIGNATURE_LENGTH
263 }),
264 result.err().map(as_validate_error),
265 );
266 });
267 }
268
269 #[test]
270 fn missing_signature() {
271 let bytes = [(1 as u32).to_le_bytes().as_slice()].concat();
272 match Signature::parse(PolicyCursor::new(Arc::new(bytes))).err().map(as_parse_error) {
273 Some(ParseError::MissingData { type_name: "u8", type_size: 1, num_bytes: 0 }) => {}
274 parse_err => {
275 assert!(false, "Expected Some(MissingData...), but got {:?}", parse_err);
276 }
277 }
278 }
279
280 #[test]
281 fn invalid_signature() {
282 const INVALID_SIGNATURE: &[u8] = b"TE Linux";
284
285 let bytes =
286 [(INVALID_SIGNATURE.len() as u32).to_le_bytes().as_slice(), INVALID_SIGNATURE].concat();
287
288 validate_test!(Signature, bytes, result, {
289 assert_eq!(
290 Some(ValidateError::InvalidSignature {
291 found_signature: INVALID_SIGNATURE.to_owned()
292 }),
293 result.err().map(as_validate_error),
294 );
295 });
296 }
297
298 #[test]
299 fn invalid_policy_version() {
300 let bytes = [(POLICYDB_VERSION_MIN - 1).to_le_bytes().as_slice()].concat();
301 let data = Arc::new(bytes);
302 let mut context = crate::policy::PolicyValidationContext { data: data.clone() };
303 let (policy_version, tail) =
304 PolicyCursor::parse::<PolicyVersion>(PolicyCursor::new(data.clone())).expect("magic");
305 assert_eq!(data.len(), tail.offset() as usize);
306 assert_eq!(
307 Err(ValidateError::InvalidPolicyVersion {
308 found_policy_version: POLICYDB_VERSION_MIN - 1
309 }),
310 policy_version.validate(&mut context)
311 );
312
313 let bytes = [(POLICYDB_VERSION_MAX + 1).to_le_bytes().as_slice()].concat();
314 let data = Arc::new(bytes);
315 let mut context = crate::policy::PolicyValidationContext { data: data.clone() };
316 let (policy_version, tail) =
317 PolicyCursor::parse::<PolicyVersion>(PolicyCursor::new(data.clone())).expect("magic");
318 assert_eq!(data.len(), tail.offset() as usize);
319 assert_eq!(
320 Err(ValidateError::InvalidPolicyVersion {
321 found_policy_version: POLICYDB_VERSION_MAX + 1
322 }),
323 policy_version.validate(&mut context)
324 );
325 }
326
327 #[test]
328 fn config_missing_mls_flag() {
329 let bytes = [(!CONFIG_MLS_FLAG).to_le_bytes().as_slice()].concat();
330 match Config::parse(PolicyCursor::new(Arc::new(bytes))).err() {
331 Some(ParseError::ConfigMissingMlsFlag { .. }) => {}
332 parse_err => {
333 assert!(false, "Expected Some(ConfigMissingMlsFlag...), but got {:?}", parse_err);
334 }
335 }
336 }
337
338 #[test]
339 fn invalid_handle_unknown() {
340 let bytes = [(CONFIG_MLS_FLAG
341 | CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG
342 | CONFIG_HANDLE_UNKNOWN_REJECT_FLAG)
343 .to_le_bytes()
344 .as_slice()]
345 .concat();
346 assert_eq!(
347 Some(ParseError::InvalidHandleUnknownConfigurationBits {
348 masked_bits: CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG | CONFIG_HANDLE_UNKNOWN_REJECT_FLAG
349 }),
350 Config::parse(PolicyCursor::new(Arc::new(bytes))).err()
351 );
352 }
353}