Skip to main content

selinux/new_policy/
types.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 std::num::{NonZeroU16, NonZeroUsize};
6
7use hashbrown::HashTable;
8use selinux_policy_derive::{HasPolicyId, Parse, Serialize};
9
10use super::bitmap::IdSet;
11use super::error::{ParseError, SerializeError, ValidateError};
12use super::id_type::IdType;
13use super::indexed::hash_name;
14use super::parser::{Array, PolicyCursor};
15use super::traits::{HasName, Parse, PolicyId, Serialize, Validate};
16use super::NewPolicy;
17
18/// Tag type for type safety of policy type identifiers.
19#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
20pub struct TypeTag;
21
22/// Identifies a type (or type attribute) within a policy.
23pub type TypeId = IdType<NonZeroU16, TypeTag>;
24
25/// Set of types that are marked permissive.
26pub type PermissiveTypeSet = IdSet<TypeId, true>;
27
28/// Set of [`TypeId`]s.
29pub type TypeSet = IdSet<TypeId>;
30
31/// Wrapper for [`usize`] that cannot be [`usize::MAX`].
32///
33/// Allows [`Option`]<[`NonMaxUsize`]> to have the same size in memory as a [`usize`]
34/// by using [`usize::MAX`] as a niche.
35#[derive(Copy, Clone, Debug, PartialEq, Eq)]
36pub struct NonMaxUsize {
37    value: NonZeroUsize,
38}
39
40impl NonMaxUsize {
41    pub fn new(value: usize) -> Option<Self> {
42        NonZeroUsize::new(value.wrapping_add(1)).map(|value| Self { value })
43    }
44
45    pub fn get(self) -> usize {
46        self.value.get().wrapping_sub(1)
47    }
48}
49
50impl Validate for TypeId {
51    fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError> {
52        policy
53            .types()
54            .get_by_id(*self)
55            .map(|_| ())
56            .ok_or_else(|| ValidateError::UnknownId { kind: "type", id: self.as_u32() })
57    }
58}
59
60#[derive(Copy, Clone, Debug, PartialEq, Eq)]
61pub enum TypeKind {
62    Alias,
63    Type,
64    Attribute,
65}
66
67impl TypeKind {
68    pub const ALIAS: u32 = 0;
69    pub const TYPE: u32 = 1;
70    pub const ATTRIBUTE: u32 = 3;
71}
72
73/// Parsed SELinux type, containing an ID, a name, properties, and optional bounds.
74#[derive(Debug, Clone, PartialEq, Eq, HasPolicyId)]
75pub struct Type {
76    pub(super) id: TypeId,
77    pub(super) name: Box<[u8]>,
78    pub(super) properties: TypeKind,
79    pub(super) bounds: Option<TypeId>,
80}
81
82impl HasName for Type {
83    fn name(&self) -> &[u8] {
84        &self.name
85    }
86}
87
88impl Type {
89    pub fn bounded_by(&self) -> Option<TypeId> {
90        self.bounds
91    }
92}
93
94#[derive(Parse, Serialize)]
95struct BinaryTypeMetadata {
96    length: u32,
97    id: u32,
98    properties: u32,
99    bounds: u32,
100}
101
102impl Parse for Type {
103    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
104        let metadata = BinaryTypeMetadata::parse(cursor)?;
105        let name = cursor.read_bytes(metadata.length as usize)?.to_vec().into_boxed_slice();
106
107        let properties_val = metadata.properties;
108        let properties = match properties_val {
109            TypeKind::ALIAS => TypeKind::Alias,
110            TypeKind::TYPE => TypeKind::Type,
111            TypeKind::ATTRIBUTE => TypeKind::Attribute,
112            v => {
113                return Err(ParseError::InvalidEnumValue {
114                    enum_name: "TypeKind",
115                    value: v as u64,
116                });
117            }
118        };
119
120        let bounds = TypeId::from_u32(metadata.bounds);
121        let id =
122            TypeId::from_u32(metadata.id).ok_or(ParseError::InvalidId { value: metadata.id })?;
123
124        Ok(Self { id, name, properties, bounds })
125    }
126}
127
128impl Serialize for Type {
129    fn serialize(&self, writer: &mut Vec<u8>) -> Result<(), SerializeError> {
130        let properties_val = match self.properties {
131            TypeKind::Alias => TypeKind::ALIAS,
132            TypeKind::Type => TypeKind::TYPE,
133            TypeKind::Attribute => TypeKind::ATTRIBUTE,
134        };
135        let metadata = BinaryTypeMetadata {
136            length: self.name.len() as u32,
137            id: self.id.as_u32(),
138            properties: properties_val,
139            bounds: self.bounds.map_or(0, |id| id.as_u32()),
140        };
141        metadata.serialize(writer)?;
142        writer.extend_from_slice(&self.name);
143        Ok(())
144    }
145}
146
147impl Validate for Type {
148    fn validate(&self, _policy: &NewPolicy) -> Result<(), ValidateError> {
149        // Structural validation is done during parsing.
150        Ok(())
151    }
152}
153
154/// Container for all types in the policy, providing indices for fast lookup by ID and Name.
155#[derive(Debug, Clone)]
156pub struct Types {
157    pub primary_names_count: u32,
158    /// In-order list of all types, attributes, and aliases.
159    pub ordered: Array<Type>,
160
161    /// Maps TypeId -> index in `ordered`. Only contains Types and Attributes.
162    /// Index is `TypeId - 1`.
163    by_id: Box<[Option<NonMaxUsize>]>,
164
165    /// Maps name -> index in `ordered`. Only contains Types and Aliases.
166    /// Stores only u32 index to avoid keeping copies of type names.
167    by_name: HashTable<u32>,
168    hasher: rapidhash::RapidBuildHasher,
169}
170
171impl PartialEq for Types {
172    fn eq(&self, other: &Self) -> bool {
173        self.primary_names_count == other.primary_names_count && self.ordered == other.ordered
174    }
175}
176
177impl Eq for Types {}
178
179impl Parse for Types {
180    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
181        let primary_names_count = u32::parse(cursor)?;
182        let ordered = Array::<Type>::parse(cursor)?;
183
184        // Build indices
185        let mut by_id = Vec::new();
186        let hasher = rapidhash::RapidBuildHasher::default();
187        let mut by_name = HashTable::new();
188
189        for (index, t) in ordered.iter().enumerate() {
190            if t.properties == TypeKind::Type || t.properties == TypeKind::Attribute {
191                let id = t.id.as_u32() as usize;
192                if id > by_id.len() {
193                    by_id.resize(id, None);
194                }
195                by_id[id - 1] = Some(NonMaxUsize::new(index).expect("index overflow"));
196            }
197            if t.properties == TypeKind::Type || t.properties == TypeKind::Alias {
198                let hash = hash_name(&hasher, t.name.as_ref());
199                by_name.insert_unique(hash, index as u32, |&idx| {
200                    hash_name(&hasher, ordered[idx as usize].name.as_ref())
201                });
202            }
203        }
204
205        Ok(Self { primary_names_count, ordered, by_id: by_id.into_boxed_slice(), by_name, hasher })
206    }
207}
208
209impl Serialize for Types {
210    fn serialize(&self, writer: &mut Vec<u8>) -> Result<(), SerializeError> {
211        self.primary_names_count.serialize(writer)?;
212        self.ordered.serialize(writer)
213    }
214}
215
216impl Validate for Types {
217    fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError> {
218        for t in self.ordered.iter() {
219            t.validate(policy)?;
220        }
221        Ok(())
222    }
223}
224
225impl Types {
226    pub fn primary_names_count(&self) -> u32 {
227        self.primary_names_count
228    }
229
230    pub fn get_by_id(&self, id: TypeId) -> Option<&Type> {
231        let index = self.by_id.get((id.as_u32() - 1) as usize)?.as_ref()?;
232        Some(&self.ordered[index.get()])
233    }
234
235    pub fn get_by_name(&self, name: &[u8]) -> Option<&Type> {
236        let hash = hash_name(&self.hasher, name);
237        let idx =
238            self.by_name.find(hash, |&idx| self.ordered[idx as usize].name.as_ref() == name)?;
239        Some(&self.ordered[*idx as usize])
240    }
241
242    pub fn is_empty(&self) -> bool {
243        self.ordered.is_empty()
244    }
245
246    pub fn iter(&self) -> impl Iterator<Item = &Type> {
247        self.ordered.iter()
248    }
249}