1use std::num::NonZeroU32;
6use std::sync::atomic::{AtomicU64, Ordering};
7
8use hashbrown::HashTable;
9use hashbrown::hash_table::Entry;
10use rapidhash::RapidBuildHasher;
11
12use super::error::{ParseError, SerializeError, ValidateError};
13use super::parser::PolicyCursor;
14use super::traits::{Parse, Serialize, Validate};
15use super::{AccessVector, ClassId, NewPolicy, TypeId, U24Index};
16
17pub use selinux_policy_derive::{Parse, Serialize};
18
19pub const AV_ALLOW_RULE_FLAG: u16 = 0x1;
22pub const AV_AUDITALLOW_RULE_FLAG: u16 = 0x2;
24pub const AV_DONTAUDIT_RULE_FLAG: u16 = 0x4;
26
27pub const AV_TYPE_TRANSITION_RULE_FLAG: u16 = 0x10;
29pub const AV_TYPE_MEMBER_RULE_FLAG: u16 = 0x20;
31pub const AV_TYPE_CHANGE_RULE_FLAG: u16 = 0x40;
33
34pub const AV_ALLOWXPERM_RULE_FLAG: u16 = 0x100;
36pub const AV_AUDITALLOWXPERM_RULE_FLAG: u16 = 0x200;
38pub const AV_DONTAUDITXPERM_RULE_FLAG: u16 = 0x400;
40
41pub const AV_ENABLED_RULE_FLAG: u16 = 0x8000;
43
44pub const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
46
47pub const XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES: u8 = 1;
49pub const XPERMS_TYPE_IOCTL_PREFIXES: u8 = 2;
51pub const XPERMS_TYPE_NLMSG: u8 = 3;
53
54pub const XPERMS_BITMAP_BLOCKS: usize = 4;
56
57#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
59pub struct XpermsBitmap([u64; XPERMS_BITMAP_BLOCKS]);
60
61impl Parse for XpermsBitmap {
62 fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
63 let mut words = [0u64; XPERMS_BITMAP_BLOCKS];
64 for word in words.iter_mut() {
65 let low = cursor.parse::<u32>()? as u64;
66 let high = cursor.parse::<u32>()? as u64;
67 *word = low | (high << 32);
68 }
69 Ok(Self(words))
70 }
71}
72
73impl Serialize for XpermsBitmap {
74 fn serialize(&self, writer: &mut Vec<u8>) -> Result<(), SerializeError> {
75 for &word in self.0.iter() {
76 (word as u32).serialize(writer)?;
77 ((word >> 32) as u32).serialize(writer)?;
78 }
79 Ok(())
80 }
81}
82
83impl XpermsBitmap {
84 pub const BITMAP_BLOCKS: usize = XPERMS_BITMAP_BLOCKS;
85 pub const ALL: Self = Self([u64::MAX; Self::BITMAP_BLOCKS]);
87 pub const NONE: Self = Self([0u64; Self::BITMAP_BLOCKS]);
89
90 pub fn new(elements: [u64; Self::BITMAP_BLOCKS]) -> Self {
92 Self(elements)
93 }
94
95 pub fn contains(&self, value: u8) -> bool {
97 let block_index = (value as usize) / (u64::BITS as usize);
98 let bit_index = (value as usize) % (u64::BITS as usize);
99 self.0[block_index] & (1u64 << bit_index) != 0
100 }
101
102 pub fn from_atomics(atomics: &[AtomicU64; Self::BITMAP_BLOCKS]) -> Self {
104 let mut words = [0u64; Self::BITMAP_BLOCKS];
105 for (i, word) in words.iter_mut().enumerate() {
106 *word = atomics[i].load(Ordering::Relaxed);
107 }
108 Self(words)
109 }
110
111 pub fn to_atomics(&self, atomics: &[AtomicU64; Self::BITMAP_BLOCKS]) {
113 for (i, word) in self.0.iter().enumerate() {
114 atomics[i].store(*word, Ordering::Relaxed);
115 }
116 }
117}
118
119impl std::ops::BitAnd for XpermsBitmap {
120 type Output = Self;
121 fn bitand(self, rhs: Self) -> Self::Output {
122 Self(std::array::from_fn(|i| self.0[i] & rhs.0[i]))
123 }
124}
125
126impl std::ops::BitAndAssign for XpermsBitmap {
127 fn bitand_assign(&mut self, rhs: Self) {
128 for i in 0..4 {
129 self.0[i] &= rhs.0[i];
130 }
131 }
132}
133
134impl std::ops::BitOr for XpermsBitmap {
135 type Output = Self;
136 fn bitor(self, rhs: Self) -> Self::Output {
137 Self(std::array::from_fn(|i| self.0[i] | rhs.0[i]))
138 }
139}
140
141impl std::ops::BitOrAssign for XpermsBitmap {
142 fn bitor_assign(&mut self, rhs: Self) {
143 for i in 0..4 {
144 self.0[i] |= rhs.0[i];
145 }
146 }
147}
148
149impl std::ops::Sub for XpermsBitmap {
150 type Output = Self;
151 fn sub(self, rhs: Self) -> Self {
152 Self(std::array::from_fn(|i| self.0[i] & !rhs.0[i]))
153 }
154}
155
156impl std::ops::SubAssign for XpermsBitmap {
157 fn sub_assign(&mut self, rhs: Self) {
158 for i in 0..4 {
159 self.0[i] &= !rhs.0[i];
160 }
161 }
162}
163
164impl std::ops::Not for XpermsBitmap {
165 type Output = Self;
166 fn not(self) -> Self::Output {
167 Self(self.0.map(|word| !word))
168 }
169}
170
171impl Validate for XpermsBitmap {
172 fn validate(&self, _policy: &NewPolicy) -> Result<(), ValidateError> {
173 Ok(())
174 }
175}
176
177#[derive(Clone, Debug, PartialEq, Eq, Parse, Serialize)]
179pub struct ExtendedPermissions {
180 xperms_type: u8,
181 xperms_optional_prefix: u8,
182 xperms_bitmap: XpermsBitmap,
183}
184
185impl Validate for ExtendedPermissions {
186 fn validate(&self, _policy: &NewPolicy) -> Result<(), ValidateError> {
187 match self.xperms_type {
188 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
189 | XPERMS_TYPE_IOCTL_PREFIXES
190 | XPERMS_TYPE_NLMSG => Ok(()),
191 v => Err(ValidateError::InvalidExtendedPermissionsType { value: v }),
192 }
193 }
194}
195
196impl ExtendedPermissions {
197 pub fn xperms_type(&self) -> u8 {
199 self.xperms_type
200 }
201
202 pub fn xperms_optional_prefix(&self) -> u8 {
204 self.xperms_optional_prefix
205 }
206
207 pub fn xperms_bitmap(&self) -> &XpermsBitmap {
209 &self.xperms_bitmap
210 }
211
212 #[cfg(test)]
214 pub fn count(&self) -> u64 {
215 let count = self
216 .xperms_bitmap
217 .0
218 .iter()
219 .fold(0, |count, block| count as u64 + block.count_ones() as u64);
220 match self.xperms_type {
221 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES | XPERMS_TYPE_NLMSG => count,
222 XPERMS_TYPE_IOCTL_PREFIXES => count * 0x100,
223 _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
224 }
225 }
226
227 #[cfg(test)]
229 pub fn contains(&self, xperm: u16) -> bool {
230 let [postfix, prefix] = xperm.to_le_bytes();
231 if (self.xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
232 || self.xperms_type == XPERMS_TYPE_NLMSG)
233 && self.xperms_optional_prefix != prefix
234 {
235 return false;
236 }
237 let value = match self.xperms_type {
238 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES | XPERMS_TYPE_NLMSG => postfix,
239 XPERMS_TYPE_IOCTL_PREFIXES => prefix,
240 _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
241 };
242 self.xperms_bitmap.contains(value)
243 }
244}
245
246#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
248pub enum RuleKind {
249 Allow,
250 AuditAllow,
251 DontAudit,
252 TypeTransition,
253 TypeMember,
254 TypeChange,
255 AllowXperm,
256 AuditAllowXperm,
257 DontAuditXperm,
258}
259
260impl TryFrom<u16> for RuleKind {
261 type Error = ParseError;
262
263 fn try_from(rule_type: u16) -> Result<Self, Self::Error> {
264 let base_kind = rule_type & !AV_ENABLED_RULE_FLAG;
265 match base_kind {
266 AV_ALLOW_RULE_FLAG => Ok(Self::Allow),
267 AV_AUDITALLOW_RULE_FLAG => Ok(Self::AuditAllow),
268 AV_DONTAUDIT_RULE_FLAG => Ok(Self::DontAudit),
269 AV_TYPE_TRANSITION_RULE_FLAG => Ok(Self::TypeTransition),
270 AV_TYPE_MEMBER_RULE_FLAG => Ok(Self::TypeMember),
271 AV_TYPE_CHANGE_RULE_FLAG => Ok(Self::TypeChange),
272 AV_ALLOWXPERM_RULE_FLAG => Ok(Self::AllowXperm),
273 AV_AUDITALLOWXPERM_RULE_FLAG => Ok(Self::AuditAllowXperm),
274 AV_DONTAUDITXPERM_RULE_FLAG => Ok(Self::DontAuditXperm),
275 _ => {
276 Err(ParseError::InvalidEnumValue { enum_name: "RuleKind", value: rule_type as u64 })
277 }
278 }
279 }
280}
281
282impl From<RuleKind> for u16 {
283 fn from(kind: RuleKind) -> Self {
284 match kind {
285 RuleKind::Allow => AV_ALLOW_RULE_FLAG,
286 RuleKind::AuditAllow => AV_AUDITALLOW_RULE_FLAG,
287 RuleKind::DontAudit => AV_DONTAUDIT_RULE_FLAG,
288 RuleKind::TypeTransition => AV_TYPE_TRANSITION_RULE_FLAG,
289 RuleKind::TypeMember => AV_TYPE_MEMBER_RULE_FLAG,
290 RuleKind::TypeChange => AV_TYPE_CHANGE_RULE_FLAG,
291 RuleKind::AllowXperm => AV_ALLOWXPERM_RULE_FLAG,
292 RuleKind::AuditAllowXperm => AV_AUDITALLOWXPERM_RULE_FLAG,
293 RuleKind::DontAuditXperm => AV_DONTAUDITXPERM_RULE_FLAG,
294 }
295 }
296}
297
298#[derive(Clone, Debug, PartialEq, Eq)]
300pub struct AccessRule {
301 key: RuleKey,
302 access_vector: AccessVector,
303}
304
305#[derive(Clone, Debug, PartialEq, Eq)]
307pub struct TypeTransitionRule {
308 key: RuleKey,
309 new_type: TypeId,
310}
311
312#[derive(Clone, Debug, PartialEq, Eq)]
314pub struct XpermRule {
315 key: RuleKey,
316 kind: RuleKind,
317 extended_permissions: ExtendedPermissions,
318}
319
320#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
322pub struct RuleKey {
323 source_type: TypeId,
324 target_type: TypeId,
325 class: ClassId,
326}
327
328impl RuleKey {
329 pub fn new(source_type: TypeId, target_type: TypeId, class: ClassId) -> Self {
331 Self { source_type, target_type, class }
332 }
333
334 pub fn hash(&self, hasher: &RapidBuildHasher) -> u64 {
336 use std::hash::{BuildHasher, Hash, Hasher};
337 let mut state = hasher.build_hasher();
338 Hash::hash(self, &mut state);
339 state.finish()
340 }
341
342 fn to_header(&self, kind: RuleKind) -> BinaryAccessVectorRuleHeader {
344 BinaryAccessVectorRuleHeader {
345 source_type: self.source_type.as_u16(),
346 target_type: self.target_type.as_u16(),
347 class: self.class.as_u16(),
348 rule_flags: kind.into(),
349 }
350 }
351}
352
353impl Validate for RuleKey {
354 fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError> {
355 self.source_type.validate(policy)?;
356 self.target_type.validate(policy)?;
357 self.class.validate(policy)?;
358 Ok(())
359 }
360}
361
362pub trait HasRuleKey {
364 fn key(&self) -> RuleKey;
366}
367
368impl HasRuleKey for AccessRule {
369 fn key(&self) -> RuleKey {
370 self.key
371 }
372}
373
374impl HasRuleKey for TypeTransitionRule {
375 fn key(&self) -> RuleKey {
376 self.key
377 }
378}
379
380impl HasRuleKey for XpermRule {
381 fn key(&self) -> RuleKey {
382 self.key
383 }
384}
385
386#[derive(Debug, Clone, PartialEq)]
391pub struct AccessDecision {
392 pub allow: AccessVector,
393 pub auditallow: AccessVector,
394 pub auditdeny: AccessVector,
395 pub flags: u32,
396
397 pub todo_bug: Option<NonZeroU32>,
400}
401
402impl Default for AccessDecision {
403 fn default() -> Self {
404 Self::allow(AccessVector::NONE)
405 }
406}
407
408impl AccessDecision {
409 pub const fn allow(allow: AccessVector) -> Self {
412 Self {
413 allow,
414 auditallow: AccessVector::NONE,
415 auditdeny: AccessVector::ALL,
416 flags: 0,
417 todo_bug: None,
418 }
419 }
420}
421
422#[derive(Debug, Clone, Copy, PartialEq, Eq)]
424pub struct AccessVectorDecision {
425 pub allow: Option<AccessVector>,
427 pub auditallow: Option<AccessVector>,
429 pub dontaudit: Option<AccessVector>,
431}
432
433#[derive(Debug, Clone)]
449pub struct AccessVectorRules {
450 av_rules: Box<[AccessRule]>,
451 type_transitions: Box<[TypeTransitionRule]>,
452 xperm_rules: Box<[XpermRule]>,
453 rule_order: Box<[RuleKind]>,
454
455 allow: HashTable<U24Index>,
456 auditallow: HashTable<U24Index>,
457 dontaudit: HashTable<U24Index>,
458 type_transition: HashTable<U24Index>,
459 allowxperm: HashTable<U24Index>,
460 auditallowxperm: HashTable<U24Index>,
461 dontauditxperm: HashTable<U24Index>,
462 hasher: RapidBuildHasher,
463}
464
465impl PartialEq for AccessVectorRules {
466 fn eq(&self, other: &Self) -> bool {
467 self.av_rules == other.av_rules
468 && self.type_transitions == other.type_transitions
469 && self.xperm_rules == other.xperm_rules
470 && self.rule_order == other.rule_order
471 }
472}
473
474impl Eq for AccessVectorRules {}
475
476pub struct XpermsDecisions<'a> {
478 pub allow: XpermsIter<'a>,
480 pub auditallow: XpermsIter<'a>,
482 pub dontaudit: XpermsIter<'a>,
484}
485
486impl AccessVectorRules {
487 pub fn new(
489 av_rules: Box<[AccessRule]>,
490 type_transitions: Box<[TypeTransitionRule]>,
491 xperm_rules: Box<[XpermRule]>,
492 rule_order: Box<[RuleKind]>,
493 ) -> Result<Self, ParseError> {
494 let hasher = RapidBuildHasher::default();
495
496 let mut allow: HashTable<U24Index> = HashTable::new();
497 let mut auditallow: HashTable<U24Index> = HashTable::new();
498 let mut dontaudit: HashTable<U24Index> = HashTable::new();
499 let mut type_transition: HashTable<U24Index> = HashTable::new();
500
501 let mut allowxperm: HashTable<U24Index> = HashTable::new();
502 let mut auditallowxperm: HashTable<U24Index> = HashTable::new();
503 let mut dontauditxperm: HashTable<U24Index> = HashTable::new();
504
505 let mut av_idx = 0;
506 let mut tr_idx = 0;
507 let mut xp_idx = 0;
508
509 let mut rule_order_iter = rule_order.iter().peekable();
510 while let Some(&kind) = rule_order_iter.next() {
511 match kind {
512 RuleKind::Allow | RuleKind::AuditAllow | RuleKind::DontAudit => {
513 let table = match kind {
514 RuleKind::Allow => &mut allow,
515 RuleKind::AuditAllow => &mut auditallow,
516 RuleKind::DontAudit => &mut dontaudit,
517 _ => unreachable!(),
518 };
519 insert_rule(table, &hasher, &av_rules, av_idx.try_into()?, kind)?;
520 av_idx += 1;
521 }
522 RuleKind::TypeTransition | RuleKind::TypeChange | RuleKind::TypeMember => {
523 if kind == RuleKind::TypeTransition {
524 insert_rule(
525 &mut type_transition,
526 &hasher,
527 &type_transitions,
528 tr_idx.try_into()?,
529 kind,
530 )?;
531 }
532 tr_idx += 1;
533 }
534 RuleKind::AllowXperm | RuleKind::AuditAllowXperm | RuleKind::DontAuditXperm => {
535 let table = match kind {
536 RuleKind::AllowXperm => &mut allowxperm,
537 RuleKind::AuditAllowXperm => &mut auditallowxperm,
538 RuleKind::DontAuditXperm => &mut dontauditxperm,
539 _ => unreachable!(),
540 };
541 insert_rule(table, &hasher, &xperm_rules, xp_idx.try_into()?, kind)?;
542
543 while xp_idx + 1 < xperm_rules.len()
544 && xperm_rules[xp_idx + 1].kind == kind
545 && xperm_rules[xp_idx + 1].key() == xperm_rules[xp_idx].key()
546 {
547 xp_idx += 1;
548 rule_order_iter.next();
549 }
550 xp_idx += 1;
551 }
552 }
553 }
554
555 Ok(Self {
556 av_rules,
557 type_transitions,
558 xperm_rules,
559 rule_order,
560 allow,
561 auditallow,
562 dontaudit,
563 type_transition,
564 allowxperm,
565 auditallowxperm,
566 dontauditxperm,
567 hasher,
568 })
569 }
570
571 pub fn find_av_decisions(
573 &self,
574 source: TypeId,
575 target: TypeId,
576 class: ClassId,
577 ) -> AccessVectorDecision {
578 let key = RuleKey::new(source, target, class);
579 let hash = key.hash(&self.hasher);
580
581 let lookup = |table: &HashTable<U24Index>| {
582 let idx = table.find(hash, |&i| self.av_rules[i].key() == key)?;
583 Some(self.av_rules[*idx].access_vector)
584 };
585
586 AccessVectorDecision {
587 allow: lookup(&self.allow),
588 auditallow: lookup(&self.auditallow),
589 dontaudit: lookup(&self.dontaudit),
590 }
591 }
592
593 pub fn find_type_transition(
595 &self,
596 source: TypeId,
597 target: TypeId,
598 class: ClassId,
599 ) -> Option<TypeId> {
600 let key = RuleKey::new(source, target, class);
601 let hash = key.hash(&self.hasher);
602 let idx = self.type_transition.find(hash, |&i| self.type_transitions[i].key() == key)?;
603 Some(self.type_transitions[*idx].new_type)
604 }
605
606 pub fn find_xperms_decisions(
608 &self,
609 source: TypeId,
610 target: TypeId,
611 class: ClassId,
612 ) -> XpermsDecisions<'_> {
613 let key = RuleKey::new(source, target, class);
614 let hash = key.hash(&self.hasher);
615
616 let lookup = |table: &HashTable<U24Index>, kind: RuleKind| {
617 let r = table.find(hash, |&r| self.xperm_rules[r].key() == key).copied();
618 match r {
619 Some(r) => {
620 let slice = &self.xperm_rules[usize::from(r)..];
621 XpermsIter { iter: slice.iter(), key, kind }
622 }
623 None => XpermsIter { iter: [].iter(), key, kind },
624 }
625 };
626
627 XpermsDecisions {
628 allow: lookup(&self.allowxperm, RuleKind::AllowXperm),
629 auditallow: lookup(&self.auditallowxperm, RuleKind::AuditAllowXperm),
630 dontaudit: lookup(&self.dontauditxperm, RuleKind::DontAuditXperm),
631 }
632 }
633}
634
635pub struct XpermsIter<'a> {
637 iter: std::slice::Iter<'a, XpermRule>,
638 key: RuleKey,
639 kind: RuleKind,
640}
641
642impl<'a> Iterator for XpermsIter<'a> {
643 type Item = &'a ExtendedPermissions;
644 fn next(&mut self) -> Option<Self::Item> {
645 let rule = self.iter.as_slice().first()?;
646 if rule.key() != self.key || rule.kind != self.kind {
647 self.iter = [].iter();
648 return None;
649 }
650 let rule = self.iter.next()?;
651 Some(&rule.extended_permissions)
652 }
653}
654
655impl Parse for AccessVectorRules {
656 fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
657 let count = u32::parse(cursor)? as usize;
658
659 let mut av_rules = Vec::new();
660 let mut type_transitions = Vec::new();
661 let mut xperm_rules = Vec::new();
662 let mut rule_order = Vec::with_capacity(count);
663
664 for _ in 0..count {
665 let header = BinaryAccessVectorRuleHeader::parse(cursor)?;
666 let kind = RuleKind::try_from(header.rule_flags)?;
667
668 let source_val = header.source_type;
669 let source_type = TypeId::from_u16(source_val)
670 .ok_or(ParseError::InvalidId { value: source_val as u32 })?;
671
672 let target_val = header.target_type;
673 let target_type = TypeId::from_u16(target_val)
674 .ok_or(ParseError::InvalidId { value: target_val as u32 })?;
675
676 let class_val = header.class;
677 let class = ClassId::from_u16(class_val)
678 .ok_or(ParseError::InvalidId { value: class_val as u32 })?;
679
680 let key = RuleKey::new(source_type, target_type, class);
681
682 match kind {
683 RuleKind::AllowXperm | RuleKind::AuditAllowXperm | RuleKind::DontAuditXperm => {
684 let extended_permissions = ExtendedPermissions::parse(cursor)?;
685 xperm_rules.push(XpermRule { key, kind, extended_permissions });
686 rule_order.push(kind);
687 }
688 RuleKind::TypeTransition | RuleKind::TypeChange | RuleKind::TypeMember => {
689 let new_type = TypeId::parse(cursor)?;
690 type_transitions.push(TypeTransitionRule { key, new_type });
691 rule_order.push(kind);
692 }
693 RuleKind::Allow | RuleKind::AuditAllow | RuleKind::DontAudit => {
694 let access_vector = AccessVector::parse(cursor)?;
695 av_rules.push(AccessRule { key, access_vector });
696 rule_order.push(kind);
697 }
698 }
699 }
700
701 Self::new(
702 av_rules.into_boxed_slice(),
703 type_transitions.into_boxed_slice(),
704 xperm_rules.into_boxed_slice(),
705 rule_order.into_boxed_slice(),
706 )
707 }
708}
709
710impl Serialize for AccessVectorRules {
711 fn serialize(&self, writer: &mut Vec<u8>) -> Result<(), SerializeError> {
712 let count = self.rule_order.len() as u32;
713 count.serialize(writer)?;
714
715 let mut av_idx = 0;
716 let mut tr_idx = 0;
717 let mut xp_idx = 0;
718
719 for &kind in self.rule_order.iter() {
720 match kind {
721 RuleKind::Allow | RuleKind::AuditAllow | RuleKind::DontAudit => {
722 let rule = &self.av_rules[av_idx];
723 av_idx += 1;
724 rule.key.to_header(kind).serialize(writer)?;
725 let val: u32 = rule.access_vector.into();
726 val.serialize(writer)?;
727 }
728 RuleKind::TypeTransition | RuleKind::TypeChange | RuleKind::TypeMember => {
729 let rule = &self.type_transitions[tr_idx];
730 tr_idx += 1;
731 rule.key.to_header(kind).serialize(writer)?;
732 rule.new_type.serialize(writer)?;
733 }
734 RuleKind::AllowXperm | RuleKind::AuditAllowXperm | RuleKind::DontAuditXperm => {
735 let rule = &self.xperm_rules[xp_idx];
736 xp_idx += 1;
737 rule.key.to_header(kind).serialize(writer)?;
738 rule.extended_permissions.serialize(writer)?;
739 }
740 }
741 }
742 Ok(())
743 }
744}
745
746impl Validate for AccessVectorRules {
747 fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError> {
748 for rule in self.av_rules.iter() {
749 rule.key.validate(policy)?;
750 }
751 for rule in self.type_transitions.iter() {
752 rule.key.validate(policy)?;
753 rule.new_type.validate(policy)?;
754 }
755 for rule in self.xperm_rules.iter() {
756 rule.key.validate(policy)?;
757 rule.extended_permissions.validate(policy)?;
758 }
759 Ok(())
760 }
761}
762
763fn insert_rule<R: HasRuleKey>(
767 table: &mut HashTable<U24Index>,
768 hasher: &RapidBuildHasher,
769 rules: &[R],
770 arr_idx: U24Index,
771 kind: RuleKind,
772) -> Result<(), ParseError> {
773 let key = rules[arr_idx].key();
774 let hash = key.hash(hasher);
775
776 match table.entry(hash, |&i| rules[i].key() == key, |&i| rules[i].key().hash(hasher)) {
777 Entry::Occupied(_) => Err(ParseError::DuplicateAccessVectorRule { key, kind }),
778 Entry::Vacant(entry) => {
779 entry.insert(arr_idx);
780 Ok(())
781 }
782 }
783}
784
785#[derive(Clone, Debug, Eq, PartialEq, Hash, Parse, Serialize)]
787struct BinaryAccessVectorRuleHeader {
788 source_type: u16,
789 target_type: u16,
790 class: u16,
791 rule_flags: u16,
792}
793
794#[cfg(test)]
795mod tests {
796 use super::*;
797 use crate::new_policy::traits::PolicyId;
798
799 #[test]
800 fn test_xperms_bitmap_ops_and_contains() {
801 let mut bitmap1 = XpermsBitmap::NONE;
802 let mut bitmap2 = XpermsBitmap::NONE;
803 assert!(!bitmap1.contains(10));
804 assert!(!bitmap2.contains(10));
805
806 bitmap1.0[0] = 1 << 10;
807 bitmap2.0[0] = 1 << 20;
808 assert!(bitmap1.contains(10));
809 assert!(!bitmap1.contains(20));
810 assert!(bitmap2.contains(20));
811
812 let or_bitmap = bitmap1 | bitmap2;
813 assert!(or_bitmap.contains(10));
814 assert!(or_bitmap.contains(20));
815
816 let and_bitmap = or_bitmap & bitmap1;
817 assert!(and_bitmap.contains(10));
818 assert!(!and_bitmap.contains(20));
819
820 let sub_bitmap = or_bitmap - bitmap1;
821 assert!(!sub_bitmap.contains(10));
822 assert!(sub_bitmap.contains(20));
823
824 let not_bitmap = !XpermsBitmap::NONE;
825 assert_eq!(not_bitmap, XpermsBitmap::ALL);
826 assert!(not_bitmap.contains(0));
827 assert!(not_bitmap.contains(255));
828 }
829
830 #[test]
831 fn test_av_rule_parse_and_serialize() {
832 let data = [
833 1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 1, 0, 5, 0, 0, 0, ];
840 let mut cursor = PolicyCursor::new(&data);
841 let av_rules = AccessVectorRules::parse(&mut cursor).expect("parse rules table");
842 assert_eq!(av_rules.av_rules.len(), 1);
843 assert_eq!(av_rules.av_rules[0].key.source_type, TypeId::from_u32(1).unwrap());
844 assert_eq!(av_rules.av_rules[0].key.target_type, TypeId::from_u32(2).unwrap());
845 assert_eq!(av_rules.av_rules[0].key.class, ClassId::from_u32(3).unwrap());
846 assert_eq!(av_rules.av_rules[0].access_vector, AccessVector::from(5));
847
848 let mut writer = Vec::new();
849 av_rules.serialize(&mut writer).expect("serialize rules table");
850 assert_eq!(writer.as_slice(), &data);
851 }
852
853 #[test]
854 fn test_av_rule_type_transition_parse_and_serialize() {
855 let data = [
856 1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 16, 0, 10, 0, 0, 0, ];
863 let mut cursor = PolicyCursor::new(&data);
864 let av_rules = AccessVectorRules::parse(&mut cursor).expect("parse rules table");
865 assert_eq!(av_rules.type_transitions.len(), 1);
866 assert_eq!(av_rules.type_transitions[0].key.source_type, TypeId::from_u32(1).unwrap());
867 assert_eq!(av_rules.type_transitions[0].key.target_type, TypeId::from_u32(2).unwrap());
868 assert_eq!(av_rules.type_transitions[0].key.class, ClassId::from_u32(3).unwrap());
869 assert_eq!(av_rules.type_transitions[0].new_type, TypeId::from_u32(10).unwrap());
870
871 let mut writer = Vec::new();
872 av_rules.serialize(&mut writer).expect("serialize rules table");
873 assert_eq!(writer.as_slice(), &data);
874 }
875
876 #[test]
877 fn test_av_rule_xperm_parse_and_serialize() {
878 let mut data = vec![
879 1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 0, 1, 1, 0, ];
887 data.extend_from_slice(&[
888 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]);
893 let mut cursor = PolicyCursor::new(&data);
894 let av_rules = AccessVectorRules::parse(&mut cursor).expect("parse rules table");
895 assert_eq!(av_rules.xperm_rules.len(), 1);
896 let xp = &av_rules.xperm_rules[0].extended_permissions;
897 assert_eq!(xp.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
898 assert!(xp.xperms_bitmap.contains(0));
899 assert!(!xp.xperms_bitmap.contains(1));
900
901 let mut writer = Vec::new();
902 av_rules.serialize(&mut writer).expect("serialize rules table");
903 assert_eq!(writer.as_slice(), &data);
904 }
905
906 #[test]
907 fn test_access_vector_rules_indexing_and_decisions() {
908 let data = [
909 2, 0, 0, 0, 1, 0, 2, 0, 3, 0, 1, 0, 7, 0, 0, 0, 1, 0, 2, 0, 3, 0, 16, 0, 9, 0, 0, 0, ];
923
924 let mut cursor = PolicyCursor::new(&data);
925 let av_rules = AccessVectorRules::parse(&mut cursor).expect("parse rules table");
926
927 let s1 = TypeId::from_u32(1).unwrap();
928 let t2 = TypeId::from_u32(2).unwrap();
929 let c3 = ClassId::from_u32(3).unwrap();
930
931 let decision = av_rules.find_av_decisions(s1, t2, c3);
932 assert_eq!(decision.allow, Some(AccessVector::from(7)));
933 assert_eq!(decision.auditallow, None);
934 assert_eq!(decision.dontaudit, None);
935
936 let transition = av_rules.find_type_transition(s1, t2, c3);
937 assert_eq!(transition, Some(TypeId::from_u32(9).unwrap()));
938 }
939}