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 mls;
16pub(super) mod parser;
17pub(super) mod permissions;
18pub(super) mod roles;
19pub(super) mod rules;
20pub(super) mod traits;
21pub(super) mod u24_index;
22
23use selinux_policy_derive::{Parse, Serialize, Validate};
24
25use error::{ParseError, ValidateError};
26use metadata::{Config, Counts, Magic, PolicyVersion, Signature};
27pub use metadata::{HandleUnknown, POLICYDB_VERSION_MAX};
28use parser::{PolicyCursor, RemainingBytes};
29use traits::Validate;
30pub use u24_index::U24Index;
31
32pub(super) mod booleans;
33pub(super) mod types;
34pub(super) mod users;
35
36pub use access_vector::AccessVector;
37pub use bitmap::{ExtensibleBitmap, IdSpan};
38pub use booleans::ConditionalBoolean;
39pub use classes::{Class, ClassDefault, ClassDefaultRange, ClassId};
40pub use common_symbols::CommonSymbol;
41pub use constraints::{
42    ConstraintOperator, ConstraintSubject, ConstraintTerm, MlsOperands, MlsOperator, NameExpression,
43};
44pub use context::{Context, MlsLevel, MlsRange};
45pub use id_type::*;
46pub use indexed::IdAndNameIndexed;
47pub use mls::{Category, Sensitivity};
48pub use parser::SymbolArray;
49pub use permissions::PermissionId;
50pub use roles::{Role, RoleId, RoleSet};
51pub use rules::{AccessDecision, AccessVectorRules, SELINUX_AVD_FLAGS_PERMISSIVE, XpermsBitmap};
52pub use types::*;
53pub use users::User;
54
55/// Tag type for type safety of policy user identifiers.
56#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
57pub struct UserTag;
58
59/// Identifies a user within a policy.
60pub type UserId = IdType<std::num::NonZeroU16, UserTag>;
61
62/// Tag type for type safety of policy sensitivity identifiers.
63#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
64pub struct SensitivityTag;
65
66/// Identifies a sensitivity level within a policy.
67pub type SensitivityId = IdType<std::num::NonZeroU16, SensitivityTag>;
68
69/// Tag type for type safety of policy category identifiers.
70#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
71pub struct CategoryTag;
72
73/// Identifies a security category within a policy.
74pub type CategoryId = IdType<std::num::NonZeroU16, CategoryTag>;
75
76/// Set of security categories.
77pub type CategorySet = bitmap::IdSet<CategoryId>;
78
79/// Builder for constructing [`CategorySet`]s dynamically.
80pub type CategorySetBuilder = bitmap::IdSetBuilder<CategoryId>;
81
82/// Top-level [`NewPolicy`] structure that parses the first few fields
83/// and stores the rest in [`Self::rest`] to allow round-trip testing.
84#[derive(Debug, Clone, Parse, Serialize, Validate)]
85pub struct NewPolicy {
86    magic: Magic,
87    signature: Signature,
88    version: PolicyVersion,
89    config: Config,
90    counts: Counts,
91    policy_capabilities: ExtensibleBitmap,
92    permissive_map: PermissiveTypeSet,
93    common_symbols: IdAndNameIndexed<SymbolArray<CommonSymbol>>,
94    classes: IdAndNameIndexed<SymbolArray<Class>>,
95    roles: IdAndNameIndexed<SymbolArray<Role>>,
96    types: Types,
97    users: IdAndNameIndexed<SymbolArray<User>>,
98    conditional_booleans: IdAndNameIndexed<SymbolArray<ConditionalBoolean>>,
99    sensitivities: IdAndNameIndexed<SymbolArray<Sensitivity>>,
100    categories: IdAndNameIndexed<SymbolArray<Category>>,
101    access_vector_rules: AccessVectorRules,
102    rest: RemainingBytes,
103}
104
105impl NewPolicy {
106    /// Parses a [`NewPolicy`] from the raw binary data.
107    pub fn parse(data: &[u8]) -> Result<Self, ParseError> {
108        let mut cursor = PolicyCursor::new(data);
109        cursor.parse()
110    }
111
112    /// Validates the parsed policy.
113    pub fn validate(&self) -> Result<(), ValidateError> {
114        Validate::validate(self, self)
115    }
116
117    /// Returns the policy version.
118    pub fn policy_version(&self) -> u32 {
119        self.version.get()
120    }
121
122    /// Returns the [`HandleUnknown`] configuration.
123    pub fn handle_unknown(&self) -> HandleUnknown {
124        self.config.handle_unknown()
125    }
126
127    /// Returns the policy capabilities bitmap.
128    pub fn policy_capabilities(&self) -> &ExtensibleBitmap {
129        &self.policy_capabilities
130    }
131
132    /// Returns the permissive types set.
133    pub fn permissive_map(&self) -> &PermissiveTypeSet {
134        &self.permissive_map
135    }
136
137    /// Returns the common symbols table.
138    pub fn common_symbols(&self) -> &IdAndNameIndexed<SymbolArray<CommonSymbol>> {
139        &self.common_symbols
140    }
141
142    /// Returns the object classes table.
143    pub fn classes(&self) -> &IdAndNameIndexed<SymbolArray<Class>> {
144        &self.classes
145    }
146
147    /// Returns the roles table.
148    pub fn roles(&self) -> &IdAndNameIndexed<SymbolArray<Role>> {
149        &self.roles
150    }
151
152    /// Returns the types table.
153    pub fn types(&self) -> &Types {
154        &self.types
155    }
156
157    /// Returns the users table.
158    pub fn users(&self) -> &IdAndNameIndexed<SymbolArray<User>> {
159        &self.users
160    }
161
162    /// Returns the conditional booleans table.
163    pub fn conditional_booleans(&self) -> &IdAndNameIndexed<SymbolArray<ConditionalBoolean>> {
164        &self.conditional_booleans
165    }
166
167    /// Returns the sensitivities table.
168    pub fn sensitivities(&self) -> &IdAndNameIndexed<SymbolArray<Sensitivity>> {
169        &self.sensitivities
170    }
171
172    /// Returns the categories table.
173    pub fn categories(&self) -> &IdAndNameIndexed<SymbolArray<Category>> {
174        &self.categories
175    }
176
177    /// Returns the access vector rules table.
178    pub fn access_vector_rules(&self) -> &AccessVectorRules {
179        &self.access_vector_rules
180    }
181
182    /// Returns a shared reference to the remaining unparsed bytes.
183    pub fn rest_bytes(&self) -> std::sync::Arc<[u8]> {
184        self.rest.bytes.clone()
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use super::*;
191    use crate::new_policy::traits::{HasName, Parse, Serialize};
192
193    #[derive(Copy, Clone, Debug, Eq, PartialEq, Parse, Serialize, Validate)]
194    #[policy(wire_type = u32)]
195    enum TestEnum {
196        ValueOne = 1,
197        ValueTwo = 2,
198    }
199
200    #[test]
201    fn test_enum_derive() {
202        let mut cursor = PolicyCursor::new(&[1, 0, 0, 0]);
203        let parsed = TestEnum::parse(&mut cursor).unwrap();
204        assert_eq!(parsed, TestEnum::ValueOne);
205
206        let mut cursor = PolicyCursor::new(&[2, 0, 0, 0]);
207        let parsed = TestEnum::parse(&mut cursor).unwrap();
208        assert_eq!(parsed, TestEnum::ValueTwo);
209
210        let mut cursor = PolicyCursor::new(&[3, 0, 0, 0]);
211        let err = TestEnum::parse(&mut cursor).unwrap_err();
212        assert!(matches!(err, ParseError::InvalidEnumValue { enum_name: "TestEnum", value: 3 }));
213
214        let mut writer = Vec::new();
215        TestEnum::ValueOne.serialize(&mut writer).unwrap();
216        assert_eq!(writer, vec![1, 0, 0, 0]);
217
218        let mut writer = Vec::new();
219        TestEnum::ValueTwo.serialize(&mut writer).unwrap();
220        assert_eq!(writer, vec![2, 0, 0, 0]);
221
222        let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
223        let policy = NewPolicy::parse(policy_bytes).unwrap();
224        TestEnum::ValueOne.validate(&policy).unwrap();
225    }
226
227    #[test]
228    fn test_real_policy_roundtrip() {
229        let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
230        let new_policy = NewPolicy::parse(policy_bytes).unwrap();
231        new_policy.validate().unwrap();
232
233        // Verify metadata basics
234        assert!(new_policy.policy_version() >= 30);
235        assert_eq!(new_policy.handle_unknown(), HandleUnknown::Allow);
236
237        // Verify that we can query policy capabilities and permissive map
238        // (even if they are empty or have specific values in the test policy,
239        // we just verify the APIs exist and don't panic).
240        let _caps = new_policy.policy_capabilities();
241        let _permissive = new_policy.permissive_map();
242
243        // Verify common symbols are parsed
244        assert!(!new_policy.common_symbols().is_empty());
245        let common = &new_policy.common_symbols()[0];
246        assert!(!common.name().is_empty());
247        assert!(!common.permissions().is_empty());
248
249        // Verify classes are parsed
250        assert!(!new_policy.classes().is_empty());
251        let class = &new_policy.classes()[0];
252        assert!(!class.name().is_empty());
253
254        // Verify types are parsed
255        assert!(!new_policy.types().is_empty());
256        let t = &new_policy.types().iter().next().unwrap();
257        assert!(!t.name().is_empty());
258
259        // Verify users are parsed
260        assert!(!new_policy.users().is_empty());
261        let u = &new_policy.users()[0];
262        assert!(!u.name().is_empty());
263
264        // Verify conditional booleans are parsed
265        assert!(!new_policy.conditional_booleans().is_empty());
266        let b = &new_policy.conditional_booleans()[0];
267        assert!(!b.name().is_empty());
268
269        // Verify sensitivities are parsed
270        assert!(!new_policy.sensitivities().is_empty());
271        let s = &new_policy.sensitivities()[0];
272        assert!(!s.name().is_empty());
273
274        // Verify categories are parsed
275        assert!(!new_policy.categories().is_empty());
276        let c = &new_policy.categories()[0];
277        assert!(!c.name().is_empty());
278
279        // Verify 100% byte-for-byte roundtrip fidelity
280        let mut serialized = Vec::new();
281        new_policy.serialize(&mut serialized).unwrap();
282        assert_eq!(serialized.len(), policy_bytes.len());
283        assert_eq!(serialized, policy_bytes);
284    }
285}