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, PolicyWriter};
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, 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, 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 {
76                found_signature: self.value.as_ref().into(),
77            });
78        }
79        Ok(())
80    }
81}
82
83/// Version of the SELinux policy database.
84#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
85pub struct PolicyVersion {
86    value: u32,
87}
88
89impl Parse for PolicyVersion {
90    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
91        let value = u32::parse(cursor)?;
92        let version = Self { value };
93        cursor.set_policy_version(version);
94        Ok(version)
95    }
96}
97
98impl PolicyVersion {
99    pub const V30: Self = Self { value: 30 };
100    pub const V31: Self = Self { value: 31 };
101    pub const V33: Self = Self { value: 33 };
102
103    /// Minimum policy version supporting InfiniBand partition keys and end ports.
104    pub const MIN_INFINIBAND: Self = Self { value: 31 };
105
106    /// Returns the raw policy version value.
107    pub fn get(&self) -> u32 {
108        self.value
109    }
110}
111
112impl Validate for PolicyVersion {
113    fn validate(&self, _policy: &super::NewPolicy) -> Result<(), ValidateError> {
114        let version = self.value;
115        if version < POLICYDB_VERSION_MIN || version > POLICYDB_VERSION_MAX {
116            return Err(ValidateError::InvalidPolicyVersion { found_policy_version: version });
117        }
118        Ok(())
119    }
120}
121
122/// Configuration flags of the SELinux policy.
123#[derive(Debug)]
124pub(super) struct Config {
125    handle_unknown: HandleUnknown,
126    raw_flags: u32,
127}
128
129impl Config {
130    /// Returns the [`HandleUnknown`] configuration.
131    pub(super) fn handle_unknown(&self) -> HandleUnknown {
132        self.handle_unknown
133    }
134}
135
136impl Parse for Config {
137    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
138        let flags = u32::parse(cursor)?;
139
140        // Reject if MLS is not enabled.
141        let mls_enabled = (flags & CONFIG_MLS_FLAG) != 0;
142        if !mls_enabled {
143            return Err(ParseError::ConfigMissingMlsFlag { found_config: flags });
144        }
145
146        // Reject if invalid combination of handle_unknown bits (both Reject and Allow set).
147        let masked_bits = flags & CONFIG_HANDLE_UNKNOWN_MASK;
148        let handle_unknown = match masked_bits {
149            CONFIG_HANDLE_UNKNOWN_REJECT_FLAG => HandleUnknown::Reject,
150            CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG => HandleUnknown::Allow,
151            0 => HandleUnknown::Deny,
152            _ => return Err(ParseError::InvalidConfigFlags { flags }),
153        };
154
155        // Store the rest of the flags.
156        let raw_flags = flags & !CONFIG_HANDLE_UNKNOWN_MASK;
157
158        Ok(Self { handle_unknown, raw_flags })
159    }
160}
161
162impl Serialize for Config {
163    fn serialize(&self, writer: &mut PolicyWriter<'_>) -> Result<(), SerializeError> {
164        let mut flags = self.raw_flags;
165        match self.handle_unknown {
166            HandleUnknown::Reject => flags |= CONFIG_HANDLE_UNKNOWN_REJECT_FLAG,
167            HandleUnknown::Allow => flags |= CONFIG_HANDLE_UNKNOWN_ALLOW_FLAG,
168            HandleUnknown::Deny => {}
169        }
170        flags.serialize(writer)
171    }
172}
173
174impl Validate for Config {
175    fn validate(&self, _policy: &super::NewPolicy) -> Result<(), ValidateError> {
176        Ok(())
177    }
178}
179
180/// Contains various count fields representing the size of different registries
181/// and tables in the policy.
182#[derive(Debug, Parse, Serialize, Validate)]
183pub(super) struct Counts {
184    /// Number of symbols in the symbol table.
185    symbols_count: u32,
186    /// Number of object contexts in the policy.
187    object_context_count: u32,
188}