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