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