Skip to main content

selinux/new_policy/
mod.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
5pub(super) mod access_vector;
6pub(super) mod bitmap;
7pub(super) mod classes;
8pub(super) mod common_symbols;
9pub(super) mod constraints;
10pub(super) mod context;
11pub(super) mod error;
12pub(super) mod id_type;
13pub(super) mod indexed;
14pub(super) mod metadata;
15pub(super) mod parser;
16pub(super) mod permissions;
17pub(super) mod traits;
18
19use selinux_policy_derive::{Parse, Serialize, Validate};
20
21use error::{ParseError, ValidateError};
22use metadata::{Config, Counts, Magic, PolicyVersion, Signature};
23pub use metadata::{HandleUnknown, POLICYDB_VERSION_MAX};
24use parser::{PolicyCursor, RemainingBytes};
25use traits::Validate;
26
27pub(super) mod types;
28
29pub use access_vector::AccessVector;
30pub use bitmap::{ExtensibleBitmap, IdSpan};
31pub use classes::{Class, ClassDefault, ClassDefaultRange, ClassId};
32pub use common_symbols::CommonSymbol;
33pub use constraints::{
34    ConstraintNames, ConstraintOperand, ConstraintOperator, ConstraintSubject, ConstraintTerm,
35};
36pub use context::{Context, MlsLevel, MlsRange};
37pub use id_type::*;
38pub use indexed::IdAndNameIndexed;
39pub use parser::SymbolArray;
40pub use permissions::PermissionId;
41pub use types::*;
42
43/// Tag type for type safety of policy user identifiers.
44#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
45pub struct UserTag;
46
47/// Identifies a user within a policy.
48pub type UserId = IdType<std::num::NonZeroU16, UserTag>;
49
50/// Tag type for type safety of policy role identifiers.
51#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
52pub struct RoleTag;
53
54/// Identifies a role within a policy.
55pub type RoleId = IdType<std::num::NonZeroU16, RoleTag>;
56
57/// Top-level [`NewPolicy`] structure that parses the first few fields
58/// and stores the rest in [`Self::rest`] to allow round-trip testing.
59#[derive(Debug, Clone, Parse, Serialize, Validate)]
60pub struct NewPolicy {
61    magic: Magic,
62    signature: Signature,
63    version: PolicyVersion,
64    config: Config,
65    counts: Counts,
66    policy_capabilities: ExtensibleBitmap,
67    permissive_map: PermissiveTypeSet,
68    common_symbols: IdAndNameIndexed<SymbolArray<CommonSymbol>>,
69    classes: IdAndNameIndexed<SymbolArray<Class>>,
70    rest: RemainingBytes,
71}
72
73impl NewPolicy {
74    /// Parses a [`NewPolicy`] from the raw binary data.
75    pub fn parse(data: &[u8]) -> Result<Self, ParseError> {
76        let mut cursor = PolicyCursor::new(data);
77        cursor.parse()
78    }
79
80    /// Validates the parsed policy.
81    pub fn validate(&self) -> Result<(), ValidateError> {
82        Validate::validate(self, self)
83    }
84
85    /// Returns the policy version.
86    pub fn policy_version(&self) -> u32 {
87        self.version.get()
88    }
89
90    /// Returns the [`HandleUnknown`] configuration.
91    pub fn handle_unknown(&self) -> HandleUnknown {
92        self.config.handle_unknown()
93    }
94
95    /// Returns the policy capabilities bitmap.
96    pub fn policy_capabilities(&self) -> &ExtensibleBitmap {
97        &self.policy_capabilities
98    }
99
100    /// Returns the permissive types set.
101    pub fn permissive_map(&self) -> &PermissiveTypeSet {
102        &self.permissive_map
103    }
104
105    /// Returns the common symbols table.
106    pub fn common_symbols(&self) -> &IdAndNameIndexed<SymbolArray<CommonSymbol>> {
107        &self.common_symbols
108    }
109
110    /// Returns the object classes table.
111    pub fn classes(&self) -> &IdAndNameIndexed<SymbolArray<Class>> {
112        &self.classes
113    }
114
115    /// Returns a shared reference to the remaining unparsed bytes.
116    pub fn rest_bytes(&self) -> std::sync::Arc<[u8]> {
117        self.rest.bytes.clone()
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124    use crate::new_policy::traits::{HasName, Parse, Serialize};
125
126    #[derive(Copy, Clone, Debug, Eq, PartialEq, Parse, Serialize, Validate)]
127    #[policy(wire_type = u32)]
128    enum TestEnum {
129        ValueOne = 1,
130        ValueTwo = 2,
131    }
132
133    #[test]
134    fn test_enum_derive() {
135        let mut cursor = PolicyCursor::new(&[1, 0, 0, 0]);
136        let parsed = TestEnum::parse(&mut cursor).unwrap();
137        assert_eq!(parsed, TestEnum::ValueOne);
138
139        let mut cursor = PolicyCursor::new(&[2, 0, 0, 0]);
140        let parsed = TestEnum::parse(&mut cursor).unwrap();
141        assert_eq!(parsed, TestEnum::ValueTwo);
142
143        let mut cursor = PolicyCursor::new(&[3, 0, 0, 0]);
144        let err = TestEnum::parse(&mut cursor).unwrap_err();
145        assert!(matches!(err, ParseError::InvalidEnumValue { enum_name: "TestEnum", value: 3 }));
146
147        let mut writer = Vec::new();
148        TestEnum::ValueOne.serialize(&mut writer).unwrap();
149        assert_eq!(writer, vec![1, 0, 0, 0]);
150
151        let mut writer = Vec::new();
152        TestEnum::ValueTwo.serialize(&mut writer).unwrap();
153        assert_eq!(writer, vec![2, 0, 0, 0]);
154
155        let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
156        let policy = NewPolicy::parse(policy_bytes).unwrap();
157        TestEnum::ValueOne.validate(&policy).unwrap();
158    }
159
160    #[test]
161    fn test_real_policy_roundtrip() {
162        let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
163        let new_policy = NewPolicy::parse(policy_bytes).unwrap();
164        new_policy.validate().unwrap();
165
166        // Verify metadata basics
167        assert!(new_policy.policy_version() >= 30);
168        assert_eq!(new_policy.handle_unknown(), HandleUnknown::Allow);
169
170        // Verify that we can query policy capabilities and permissive map
171        // (even if they are empty or have specific values in the test policy,
172        // we just verify the APIs exist and don't panic).
173        let _caps = new_policy.policy_capabilities();
174        let _permissive = new_policy.permissive_map();
175
176        // Verify common symbols are parsed
177        assert!(!new_policy.common_symbols().is_empty());
178        let common = &new_policy.common_symbols()[0];
179        assert!(!common.name().is_empty());
180        assert!(!common.permissions().is_empty());
181
182        // Verify classes are parsed
183        assert!(!new_policy.classes().is_empty());
184        let class = &new_policy.classes()[0];
185        assert!(!class.name().is_empty());
186
187        // Verify 100% byte-for-byte roundtrip fidelity
188        let mut serialized = Vec::new();
189        new_policy.serialize(&mut serialized).unwrap();
190        assert_eq!(serialized.len(), policy_bytes.len());
191        assert_eq!(serialized, policy_bytes);
192    }
193}