Skip to main content

selinux/new_policy/
metadata.rs

1// Copyright 2026 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 selinux_policy_derive::{Parse, Serialize, Validate};
6
7use super::error::{ParseError, SerializeError, ValidateError};
8use super::parser::{ByteArray, PolicyCursor};
9use super::traits::{Parse, Serialize, Validate};
10
11/// Magic number identifying a SELinux policy file.
12pub(super) const SELINUX_MAGIC: u32 = 0xf97cff8c;
13
14/// Maximum allowed length for a signature in the policy database.
15pub(super) const POLICYDB_STRING_MAX_LENGTH: u32 = 32;
16
17/// Expected signature prefix for a valid SELinux policy.
18pub(super) const POLICYDB_SIGNATURE: &[u8] = b"SE Linux";
19
20/// Minimum supported SELinux policy database version.
21pub(super) const POLICYDB_VERSION_MIN: u32 = 30;
22
23/// Maximum supported SELinux policy database version.
24pub const POLICYDB_VERSION_MAX: u32 = 33;
25
26/// Config flag indicating that MLS is enabled.
27pub(super) const CONFIG_MLS_FLAG: u32 = 1;
28
29/// Config flag indicating that unknown permissions should be rejected.
30pub(super) const CONFIG_HANDLE_UNKNOWN_REJECT_FLAG: u32 = 1 << 1;
31
32/// Config flag indicating that unknown permissions should be allowed.
33pub(super) const CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG: u32 = 1 << 2;
34
35/// Mask for the handle-unknown configuration bits.
36pub(super) const CONFIG_HANDLE_UNKNOWN_MASK: u32 =
37    CONFIG_HANDLE_UNKNOWN_REJECT_FLAG | CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG;
38
39/// Controls how "unknown" policy decisions are handled.
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub enum HandleUnknown {
42    Deny,
43    Reject,
44    Allow,
45}
46
47/// Magic number at the start of a SELinux policy binary.
48#[derive(Debug, Clone, Parse, Serialize)]
49pub(super) struct Magic {
50    value: u32,
51}
52
53impl Validate for Magic {
54    fn validate(&self, _policy: &super::NewPolicy) -> Result<(), ValidateError> {
55        if self.value != SELINUX_MAGIC {
56            return Err(ValidateError::InvalidMagic { found_magic: self.value });
57        }
58        Ok(())
59    }
60}
61
62/// Signature string that identifies the policy database.
63#[derive(Debug, Clone, Parse, Serialize)]
64pub(super) struct Signature {
65    value: ByteArray,
66}
67
68impl Validate for Signature {
69    fn validate(&self, _policy: &super::NewPolicy) -> Result<(), ValidateError> {
70        let len = self.value.len() as u32;
71        if len > POLICYDB_STRING_MAX_LENGTH {
72            return Err(ValidateError::InvalidSignatureLength { found_length: len });
73        }
74        if self.value.as_ref() != POLICYDB_SIGNATURE {
75            return Err(ValidateError::InvalidSignature { found_signature: self.value.to_vec() });
76        }
77        Ok(())
78    }
79}
80
81/// Version of the SELinux policy database.
82#[derive(Debug, Clone, Parse, Serialize)]
83pub(super) struct PolicyVersion {
84    value: u32,
85}
86
87impl PolicyVersion {
88    /// Returns the raw policy version value.
89    pub(super) fn get(&self) -> u32 {
90        self.value
91    }
92}
93
94impl Validate for PolicyVersion {
95    fn validate(&self, _policy: &super::NewPolicy) -> Result<(), ValidateError> {
96        let version = self.value;
97        if version < POLICYDB_VERSION_MIN || version > POLICYDB_VERSION_MAX {
98            return Err(ValidateError::InvalidPolicyVersion { found_policy_version: version });
99        }
100        Ok(())
101    }
102}
103
104/// Configuration flags of the SELinux policy.
105#[derive(Debug, Clone, PartialEq, Eq)]
106pub(super) struct Config {
107    handle_unknown: HandleUnknown,
108    raw_flags: u32,
109}
110
111impl Config {
112    /// Returns the [`HandleUnknown`] configuration.
113    pub(super) fn handle_unknown(&self) -> HandleUnknown {
114        self.handle_unknown
115    }
116}
117
118impl Parse for Config {
119    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
120        let flags = u32::parse(cursor)?;
121
122        // Reject if MLS is not enabled.
123        let mls_enabled = (flags & CONFIG_MLS_FLAG) != 0;
124        if !mls_enabled {
125            return Err(ParseError::ConfigMissingMlsFlag { found_config: flags });
126        }
127
128        // Reject if invalid combination of handle_unknown bits (both Reject and Allow set).
129        let masked_bits = flags & CONFIG_HANDLE_UNKNOWN_MASK;
130        let handle_unknown = match masked_bits {
131            CONFIG_HANDLE_UNKNOWN_REJECT_FLAG => HandleUnknown::Reject,
132            CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG => HandleUnknown::Allow,
133            0 => HandleUnknown::Deny,
134            _ => return Err(ParseError::InvalidConfigFlags { flags }),
135        };
136
137        // Store the rest of the flags.
138        let raw_flags = flags & !CONFIG_HANDLE_UNKNOWN_MASK;
139
140        Ok(Self { handle_unknown, raw_flags })
141    }
142}
143
144impl Serialize for Config {
145    fn serialize(&self, writer: &mut Vec<u8>) -> Result<(), SerializeError> {
146        let mut flags = self.raw_flags;
147        match self.handle_unknown {
148            HandleUnknown::Reject => flags |= CONFIG_HANDLE_UNKNOWN_REJECT_FLAG,
149            HandleUnknown::Allow => flags |= CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG,
150            HandleUnknown::Deny => {}
151        }
152        flags.serialize(writer)
153    }
154}
155
156impl Validate for Config {
157    fn validate(&self, _policy: &super::NewPolicy) -> Result<(), ValidateError> {
158        Ok(())
159    }
160}
161
162/// Contains various count fields representing the size of different registries
163/// and tables in the policy.
164#[derive(Debug, Clone, Parse, Serialize, Validate)]
165pub(super) struct Counts {
166    /// Number of symbols in the symbol table.
167    symbols_count: u32,
168    /// Number of object contexts in the policy.
169    object_context_count: u32,
170}