1use std::num::NonZeroU16;
6
7use fuchsia_rcu::RcuDroppable;
8use selinux_policy_derive::{HasName, HasPolicyId, Parse, Serialize, Validate};
9
10use super::Policy;
11use super::constraints::{Constraint, ConstraintTerm};
12use super::error::{ParseError, SerializeError, ValidateError};
13use super::id_type::IdType;
14use super::indexed::IdAndNameIndexed;
15use super::parser::{Array, PolicyCursor, PolicyWriter};
16use super::permissions::Permission;
17use super::traits::{Parse, PolicyId, Serialize, Validate};
18
19#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RcuDroppable)]
21pub struct ClassTag;
22
23pub type ClassId = IdType<NonZeroU16, ClassTag>;
25
26#[derive(Parse, Serialize)]
27struct BinaryClassMetadata {
28 key_length: u32,
29 common_key_length: u32,
30 id: u32,
31 permission_primary_names_count: u32,
33 permission_count: u32,
34 constraint_count: u32,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Parse, Serialize, Validate)]
39#[policy(wire_type = u32)]
40pub enum ClassDefault {
41 Unspecified = 0,
42 Source = 1,
43 Target = 2,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Parse, Serialize, Validate)]
48#[policy(wire_type = u32)]
49pub enum ClassDefaultRange {
50 Unspecified = 0,
51 SourceLow = 1,
52 SourceHigh = 2,
53 SourceLowHigh = 3,
54 TargetLow = 4,
55 TargetHigh = 5,
56 TargetLowHigh = 6,
57 Glblub = 7,
60}
61
62#[derive(Debug, Parse, Serialize, Validate)]
64pub struct ClassDefaults {
65 default_user: ClassDefault,
66 default_role: ClassDefault,
67 default_range: ClassDefaultRange,
68 default_type: ClassDefault,
69}
70
71impl ClassDefaults {
72 pub fn user(&self) -> ClassDefault {
73 self.default_user
74 }
75
76 pub fn role(&self) -> ClassDefault {
77 self.default_role
78 }
79
80 pub fn range(&self) -> ClassDefaultRange {
81 self.default_range
82 }
83
84 pub fn type_(&self) -> ClassDefault {
85 self.default_type
86 }
87}
88
89#[derive(Debug, HasName, HasPolicyId)]
91pub struct Class {
92 id: ClassId,
93 name: Box<[u8]>,
94 common_name: Box<[u8]>,
95 permission_primary_names_count: u32,
97 permissions: IdAndNameIndexed<Box<[Permission]>>,
98 constraints: Box<[Constraint]>,
99 validate_transitions: Array<ConstraintTerm>,
100 defaults: ClassDefaults,
101}
102
103impl Class {
104 pub(super) fn common_name(&self) -> &[u8] {
110 &self.common_name
111 }
112
113 pub(super) fn permissions(&self) -> &IdAndNameIndexed<Box<[Permission]>> {
114 &self.permissions
115 }
116
117 pub(super) fn constraints(&self) -> &[Constraint] {
118 &self.constraints
119 }
120
121 #[cfg(test)]
122 pub(super) fn validate_transitions(&self) -> &[ConstraintTerm] {
123 &self.validate_transitions
124 }
125
126 pub(super) fn defaults(&self) -> &ClassDefaults {
127 &self.defaults
128 }
129}
130
131impl Parse for Class {
132 fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
133 let metadata = BinaryClassMetadata::parse(cursor)?;
134
135 let id_val = metadata.id;
136 let id = ClassId::from_u32(id_val).ok_or(ParseError::InvalidId { value: id_val })?;
137
138 let name_len = metadata.key_length as usize;
139 let name = Box::from(cursor.read_bytes(name_len)?);
140
141 let common_name_len = metadata.common_key_length as usize;
142 let common_name = Box::from(cursor.read_bytes(common_name_len)?);
143
144 let permissions_count = metadata.permission_count as usize;
145 let permissions = IdAndNameIndexed::new(cursor.parse_elements(permissions_count)?)?;
146
147 let constraint_count = metadata.constraint_count as usize;
148 let constraints = cursor.parse_elements(constraint_count)?;
149
150 let validate_transitions = Array::<ConstraintTerm>::parse(cursor)?;
151 let defaults = ClassDefaults::parse(cursor)?;
152
153 Ok(Self {
154 id,
155 name,
156 common_name,
157 permission_primary_names_count: metadata.permission_primary_names_count,
158 permissions,
159 constraints,
160 validate_transitions,
161 defaults,
162 })
163 }
164}
165
166impl Serialize for Class {
167 fn serialize(&self, writer: &mut PolicyWriter<'_>) -> Result<(), SerializeError> {
168 let metadata = BinaryClassMetadata {
169 key_length: self.name.len() as u32,
170 common_key_length: self.common_name.len() as u32,
171 id: self.id.as_u32(),
172 permission_primary_names_count: self.permission_primary_names_count,
173 permission_count: self.permissions.len() as u32,
174 constraint_count: self.constraints.len() as u32,
175 };
176 metadata.serialize(writer)?;
177
178 writer.write_bytes(&self.name);
179 writer.write_bytes(&self.common_name);
180
181 self.permissions.serialize(writer)?;
182 self.constraints.serialize(writer)?;
183 self.validate_transitions.serialize(writer)?;
184 self.defaults.serialize(writer)?;
185 Ok(())
186 }
187}
188
189impl Validate for Class {
190 fn validate(&self, policy: &Policy) -> Result<(), ValidateError> {
191 self.permissions.validate(policy)?;
192 self.constraints.validate(policy)?;
193 self.validate_transitions.validate(policy)?;
194 self.defaults.validate(policy)?;
195
196 let mut common_permissions_count = 0;
197 if !self.common_name.is_empty() {
198 let common_symbol =
199 policy.common_symbols().get_by_name(&self.common_name).ok_or_else(|| {
200 ValidateError::UndefinedCommonSymbol { name: self.common_name.as_ref().into() }
201 })?;
202 common_permissions_count = common_symbol.permissions().len();
203 }
204
205 let expected_at_most = self.permissions.len() + common_permissions_count;
206 if self.permission_primary_names_count > expected_at_most as u32 {
207 return Err(ValidateError::InvalidPrimaryNamesCount {
208 expected_at_most: expected_at_most as u32,
209 found: self.permission_primary_names_count,
210 });
211 }
212
213 Ok(())
214 }
215}
216
217impl Validate for ClassId {
218 fn validate(&self, policy: &Policy) -> Result<(), ValidateError> {
219 policy
220 .classes()
221 .get_by_id(*self)
222 .map(|_| ())
223 .ok_or_else(|| ValidateError::UnknownId { kind: "class", id: self.as_u32() })
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::{PolicyCursor, *};
230 use crate::policy::metadata::PolicyVersion;
231 use crate::policy::parser::PolicyWriter;
232 use crate::policy::traits::{HasName, HasPolicyId};
233
234 #[test]
235 fn test_class_defaults_parse_and_serialize() {
236 let data = [
237 1, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, ];
242 let mut cursor = PolicyCursor::new(&data);
243 let defaults = ClassDefaults::parse(&mut cursor).unwrap();
244 assert_eq!(defaults.user(), ClassDefault::Source);
245 assert_eq!(defaults.role(), ClassDefault::Target);
246 assert_eq!(defaults.range(), ClassDefaultRange::TargetLowHigh);
247 assert_eq!(defaults.type_(), ClassDefault::Source);
248
249 let mut writer = Vec::new();
250 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
251 defaults.serialize(&mut policy_writer).unwrap();
252 assert_eq!(writer, data);
253 }
254
255 #[test]
256 fn test_minimal_class_parse_and_serialize() {
257 let data = [
258 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269 ];
270 let mut cursor = PolicyCursor::new(&data);
271 let class = Class::parse(&mut cursor).unwrap();
272 assert_eq!(class.id(), ClassId::from_u32(1).unwrap());
273 assert_eq!(class.name(), b"test");
274 assert!(class.common_name().is_empty());
275 assert!(class.permissions().is_empty());
276 assert!(class.constraints().is_empty());
277 assert!(class.validate_transitions().is_empty());
278
279 let mut writer = Vec::new();
280 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
281 class.serialize(&mut policy_writer).unwrap();
282 assert_eq!(writer, data);
283 }
284}