Skip to main content

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