1use crate::policy::view::Hashable;
6
7use super::error::ValidateError;
8use super::extensible_bitmap::ExtensibleBitmap;
9use super::parser::{PolicyCursor, PolicyData, PolicyOffset};
10use super::view::{ArrayView, Walk};
11use super::{
12 Array, ClassId, Counted, MlsLevel, MlsRange, Parse, PolicyValidationContext, RoleId, TypeId,
13 UserId, Validate, ValidateArray, array_type, array_type_validate_deref_both,
14};
15
16use crate::new_policy::traits::PolicyId;
17use anyhow::Context as _;
18use std::hash::{Hash, Hasher};
19use zerocopy::{FromBytes, Immutable, KnownLayout, Unaligned, little_endian as le};
20
21pub(super) const MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY: u32 = 31;
22
23#[allow(type_alias_bounds)]
24pub(super) type SimpleArray<T> = Array<le::U32, T>;
25
26impl<T: Validate> Validate for SimpleArray<T> {
27 type Error = <T as Validate>::Error;
28 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
32 self.data.validate(context)
33 }
34}
35
36pub(super) type SimpleArrayView<T> = ArrayView<le::U32, T>;
37
38impl<T: Validate + Parse + Walk> Validate for SimpleArrayView<T> {
39 type Error = anyhow::Error;
40
41 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
44 for item in self.data().iter(&context.data) {
45 item.validate(context)?;
46 }
47 Ok(())
48 }
49}
50
51impl Counted for le::U32 {
52 fn count(&self) -> u32 {
53 self.get()
54 }
55}
56
57impl Validate for ConditionalNode {
58 type Error = anyhow::Error;
59
60 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
62 Ok(())
63 }
64}
65
66array_type!(ConditionalNodeItems, ConditionalNodeMetadata, ConditionalNodeDatum);
67
68array_type_validate_deref_both!(ConditionalNodeItems);
69
70impl ValidateArray<ConditionalNodeMetadata, ConditionalNodeDatum> for ConditionalNodeItems {
71 type Error = anyhow::Error;
72
73 fn validate_array(
76 _context: &PolicyValidationContext,
77 _metadata: &ConditionalNodeMetadata,
78 _items: &[ConditionalNodeDatum],
79 ) -> Result<(), Self::Error> {
80 Ok(())
81 }
82}
83
84#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
85#[repr(C, packed)]
86struct BinaryAccessVectorRuleHeader {
87 source_type: le::U16,
88 target_type: le::U16,
89 class: le::U16,
90 rule_flags: le::U16,
91}
92
93const AV_DATA_IS_XPERM_MASK: u16 = 0x0700;
94
95fn skip_rules<'a>(cursor: PolicyCursor<'a>) -> Result<PolicyCursor<'a>, anyhow::Error> {
96 let (count, mut tail) = le::U32::parse(cursor).context("parsing rule count")?;
97 for _ in 0..count.get() {
98 let (header, t) =
99 BinaryAccessVectorRuleHeader::parse(tail).context("parsing rule header")?;
100 let len = if header.rule_flags.get() & AV_DATA_IS_XPERM_MASK != 0 { 34 } else { 4 };
101 tail = PolicyCursor::new_at(t.data(), t.offset() + len);
102 }
103 Ok(tail)
104}
105
106#[derive(Debug, PartialEq)]
107pub(super) struct ConditionalNode {
108 items: ConditionalNodeItems,
109}
110
111impl Parse for ConditionalNode
112where
113 ConditionalNodeItems: Parse,
114{
115 type Error = anyhow::Error;
116
117 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
118 let (items, tail) = ConditionalNodeItems::parse(bytes)
119 .map_err(Into::<anyhow::Error>::into)
120 .context("parsing conditional node items")?;
121
122 let tail = skip_rules(tail).context("skipping conditional node true list")?;
123 let tail = skip_rules(tail).context("skipping conditional node false list")?;
124
125 Ok((Self { items }, tail))
126 }
127}
128
129#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
130#[repr(C, packed)]
131pub(super) struct ConditionalNodeMetadata {
132 state: le::U32,
133 count: le::U32,
134}
135
136impl Counted for ConditionalNodeMetadata {
137 fn count(&self) -> u32 {
138 self.count.get()
139 }
140}
141
142impl Validate for ConditionalNodeMetadata {
143 type Error = anyhow::Error;
144
145 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
147 Ok(())
148 }
149}
150
151#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
152#[repr(C, packed)]
153pub(super) struct ConditionalNodeDatum {
154 node_type: le::U32,
155 boolean: le::U32,
156}
157
158impl Validate for ConditionalNodeDatum {
159 type Error = anyhow::Error;
160
161 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
163 Ok(())
164 }
165}
166
167array_type!(RoleTransitions, le::U32, RoleTransition);
168
169array_type_validate_deref_both!(RoleTransitions);
170
171impl ValidateArray<le::U32, RoleTransition> for RoleTransitions {
172 type Error = anyhow::Error;
173
174 fn validate_array(
176 _context: &PolicyValidationContext,
177 _metadata: &le::U32,
178 _items: &[RoleTransition],
179 ) -> Result<(), Self::Error> {
180 Ok(())
181 }
182}
183
184#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
185#[repr(C, packed)]
186pub(super) struct RoleTransition {
187 role: le::U32,
188 role_type: le::U32,
189 new_role: le::U32,
190 tclass: le::U32,
191}
192
193impl RoleTransition {
194 pub(super) fn current_role(&self) -> RoleId {
195 RoleId::from_u32(self.role.get()).unwrap()
196 }
197
198 pub(super) fn type_(&self) -> TypeId {
199 TypeId::from_u32(self.role_type.get()).unwrap()
200 }
201
202 pub(super) fn class(&self) -> ClassId {
203 ClassId::try_from(self.tclass.get()).unwrap()
204 }
205
206 pub(super) fn new_role(&self) -> RoleId {
207 RoleId::from_u32(self.new_role.get()).unwrap()
208 }
209}
210
211impl Validate for RoleTransition {
212 type Error = anyhow::Error;
213
214 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
215 RoleId::from_u32(self.role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
216 TypeId::from_u32(self.role_type.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
217 ClassId::from_u32(self.tclass.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
218 RoleId::from_u32(self.new_role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
219 Ok(())
220 }
221}
222
223array_type!(RoleAllows, le::U32, RoleAllow);
224
225array_type_validate_deref_both!(RoleAllows);
226
227impl ValidateArray<le::U32, RoleAllow> for RoleAllows {
228 type Error = anyhow::Error;
229
230 fn validate_array(
232 _context: &PolicyValidationContext,
233 _metadata: &le::U32,
234 _items: &[RoleAllow],
235 ) -> Result<(), Self::Error> {
236 Ok(())
237 }
238}
239
240#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
241#[repr(C, packed)]
242pub(super) struct RoleAllow {
243 role: le::U32,
244 new_role: le::U32,
245}
246
247impl RoleAllow {
248 pub(super) fn source_role(&self) -> RoleId {
249 RoleId::from_u32(self.role.get()).unwrap()
250 }
251
252 pub(super) fn new_role(&self) -> RoleId {
253 RoleId::from_u32(self.new_role.get()).unwrap()
254 }
255}
256
257impl Validate for RoleAllow {
258 type Error = anyhow::Error;
259
260 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
261 RoleId::from_u32(self.role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
262 RoleId::from_u32(self.new_role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
263 Ok(())
264 }
265}
266
267#[derive(Debug, PartialEq)]
268pub(super) enum FilenameTransitionList {
269 PolicyVersionGeq33(SimpleArray<FilenameTransition>),
270 PolicyVersionLeq32(SimpleArray<DeprecatedFilenameTransition>),
271}
272
273impl Validate for FilenameTransitionList {
274 type Error = anyhow::Error;
275
276 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
277 match self {
278 Self::PolicyVersionLeq32(list) => {
279 list.validate(context).map_err(Into::<anyhow::Error>::into)
280 }
281 Self::PolicyVersionGeq33(list) => {
282 list.validate(context).map_err(Into::<anyhow::Error>::into)
283 }
284 }
285 }
286}
287
288impl Validate for FilenameTransition {
289 type Error = anyhow::Error;
290 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
291 Ok(())
292 }
293}
294
295#[derive(Debug, PartialEq)]
296pub(super) struct FilenameTransition {
297 filename: SimpleArray<u8>,
298 transition_type: le::U32,
299 transition_class: le::U32,
300 items: SimpleArray<FilenameTransitionItem>,
301}
302
303impl FilenameTransition {
304 pub(super) fn name_bytes(&self) -> &[u8] {
305 &self.filename.data
306 }
307
308 pub(super) fn target_type(&self) -> TypeId {
309 TypeId::from_u32(self.transition_type.get()).unwrap()
310 }
311
312 pub(super) fn target_class(&self) -> ClassId {
313 ClassId::try_from(self.transition_class.get()).unwrap()
314 }
315
316 pub(super) fn outputs(&self) -> &[FilenameTransitionItem] {
317 &self.items.data
318 }
319}
320
321impl Parse for FilenameTransition
322where
323 SimpleArray<u8>: Parse,
324 SimpleArray<FilenameTransitionItem>: Parse,
325{
326 type Error = anyhow::Error;
327
328 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
329 let tail = bytes;
330
331 let (filename, tail) = SimpleArray::<u8>::parse(tail)
332 .map_err(Into::<anyhow::Error>::into)
333 .context("parsing filename for filename transition")?;
334
335 let (transition_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
336
337 let (transition_class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
338
339 let (items, tail) = SimpleArray::<FilenameTransitionItem>::parse(tail)
340 .map_err(Into::<anyhow::Error>::into)
341 .context("parsing items for filename transition")?;
342
343 Ok((Self { filename, transition_type, transition_class, items }, tail))
344 }
345}
346
347#[derive(Debug, PartialEq)]
348pub(super) struct FilenameTransitionItem {
349 stypes: ExtensibleBitmap,
350 out_type: le::U32,
351}
352
353impl FilenameTransitionItem {
354 pub(super) fn has_source_type(&self, source_type: TypeId) -> bool {
355 self.stypes.is_set(source_type.as_u32() - 1)
356 }
357
358 pub(super) fn out_type(&self) -> TypeId {
359 TypeId::from_u32(self.out_type.get()).unwrap()
360 }
361}
362
363impl Parse for FilenameTransitionItem
364where
365 ExtensibleBitmap: Parse,
366{
367 type Error = anyhow::Error;
368
369 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
370 let tail = bytes;
371
372 let (stypes, tail) = ExtensibleBitmap::parse(tail)
373 .map_err(Into::<anyhow::Error>::into)
374 .context("parsing stypes extensible bitmap for file transition")?;
375
376 let (out_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
377
378 Ok((Self { stypes, out_type }, tail))
379 }
380}
381
382impl Validate for DeprecatedFilenameTransition {
383 type Error = anyhow::Error;
384 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
385 Ok(())
386 }
387}
388
389#[derive(Debug, PartialEq)]
390pub(super) struct DeprecatedFilenameTransition {
391 filename: SimpleArray<u8>,
392 metadata: DeprecatedFilenameTransitionMetadata,
393}
394
395impl DeprecatedFilenameTransition {
396 pub(super) fn name_bytes(&self) -> &[u8] {
397 &self.filename.data
398 }
399
400 pub(super) fn source_type(&self) -> TypeId {
401 TypeId::from_u32(self.metadata.source_type.get()).unwrap()
402 }
403
404 pub(super) fn target_type(&self) -> TypeId {
405 TypeId::from_u32(self.metadata.transition_type.get()).unwrap()
406 }
407
408 pub(super) fn target_class(&self) -> ClassId {
409 ClassId::try_from(self.metadata.transition_class.get()).unwrap()
410 }
411
412 pub(super) fn out_type(&self) -> TypeId {
413 TypeId::from_u32(self.metadata.out_type.get()).unwrap()
414 }
415}
416
417impl Parse for DeprecatedFilenameTransition
418where
419 SimpleArray<u8>: Parse,
420{
421 type Error = anyhow::Error;
422
423 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
424 let tail = bytes;
425
426 let (filename, tail) = SimpleArray::<u8>::parse(tail)
427 .map_err(Into::<anyhow::Error>::into)
428 .context("parsing filename for deprecated filename transition")?;
429
430 let (metadata, tail) = PolicyCursor::parse::<DeprecatedFilenameTransitionMetadata>(tail)?;
431
432 Ok((Self { filename, metadata }, tail))
433 }
434}
435
436#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
437#[repr(C, packed)]
438pub(super) struct DeprecatedFilenameTransitionMetadata {
439 source_type: le::U32,
440 transition_type: le::U32,
441 transition_class: le::U32,
442 out_type: le::U32,
443}
444
445impl Validate for SimpleArray<InitialSid> {
446 type Error = anyhow::Error;
447
448 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
449 for initial_sid in crate::InitialSid::all_variants() {
450 if *initial_sid == crate::InitialSid::Init && !context.need_init_sid {
451 continue;
452 }
453 self.data
454 .iter()
455 .find(|initial| initial.id().get() == *initial_sid as u32)
456 .ok_or(ValidateError::MissingInitialSid { initial_sid: *initial_sid })?;
457 }
458 Ok(())
459 }
460}
461
462#[derive(Debug, PartialEq)]
463pub(super) struct InitialSid {
464 id: le::U32,
465 context: Context,
466}
467
468impl InitialSid {
469 pub(super) fn id(&self) -> le::U32 {
470 self.id
471 }
472
473 pub(super) fn context(&self) -> &Context {
474 &self.context
475 }
476}
477
478impl Parse for InitialSid
479where
480 Context: Parse,
481{
482 type Error = anyhow::Error;
483
484 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
485 let tail = bytes;
486
487 let (id, tail) = PolicyCursor::parse::<le::U32>(tail)?;
488
489 let (context, tail) = Context::parse(tail)
490 .map_err(Into::<anyhow::Error>::into)
491 .context("parsing context for initial sid")?;
492
493 Ok((Self { id, context }, tail))
494 }
495}
496
497#[derive(Debug, PartialEq)]
498pub(super) struct Context {
499 metadata: ContextMetadata,
500 mls_range: MlsRange,
501}
502
503impl Context {
504 pub(super) fn user_id(&self) -> UserId {
505 UserId::from_u32(self.metadata.user.get()).unwrap()
506 }
507 pub(super) fn role_id(&self) -> RoleId {
508 RoleId::from_u32(self.metadata.role.get()).unwrap()
509 }
510 pub(super) fn type_id(&self) -> TypeId {
511 TypeId::from_u32(self.metadata.context_type.get()).unwrap()
512 }
513 pub(super) fn low_level(&self) -> &MlsLevel {
514 self.mls_range.low()
515 }
516 pub(super) fn high_level(&self) -> &Option<MlsLevel> {
517 self.mls_range.high()
518 }
519}
520
521impl Parse for Context
522where
523 MlsRange: Parse,
524{
525 type Error = anyhow::Error;
526
527 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
528 let tail = bytes;
529
530 let (metadata, tail) =
531 PolicyCursor::parse::<ContextMetadata>(tail).context("parsing metadata for context")?;
532
533 let (mls_range, tail) = MlsRange::parse(tail)
534 .map_err(Into::<anyhow::Error>::into)
535 .context("parsing mls range for context")?;
536
537 Ok((Self { metadata, mls_range }, tail))
538 }
539}
540
541#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
542#[repr(C, packed)]
543pub(super) struct ContextMetadata {
544 user: le::U32,
545 role: le::U32,
546 context_type: le::U32,
547}
548
549impl Validate for NamedContextPair {
550 type Error = anyhow::Error;
551
552 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
557 Ok(())
558 }
559}
560
561#[derive(Debug, PartialEq)]
562pub(super) struct NamedContextPair {
563 name: SimpleArray<u8>,
564 context1: Context,
565 context2: Context,
566}
567
568impl Parse for NamedContextPair
569where
570 SimpleArray<u8>: Parse,
571 Context: Parse,
572{
573 type Error = anyhow::Error;
574
575 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
576 let tail = bytes;
577
578 let (name, tail) = SimpleArray::parse(tail)
579 .map_err(Into::<anyhow::Error>::into)
580 .context("parsing filesystem context name")?;
581
582 let (context1, tail) = Context::parse(tail)
583 .map_err(Into::<anyhow::Error>::into)
584 .context("parsing first context for filesystem context")?;
585
586 let (context2, tail) = Context::parse(tail)
587 .map_err(Into::<anyhow::Error>::into)
588 .context("parsing second context for filesystem context")?;
589
590 Ok((Self { name, context1, context2 }, tail))
591 }
592}
593
594impl Validate for Port {
595 type Error = anyhow::Error;
596
597 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
599 Ok(())
600 }
601}
602
603#[derive(Debug, PartialEq)]
604pub(super) struct Port {
605 metadata: PortMetadata,
606 context: Context,
607}
608
609impl Parse for Port
610where
611 Context: Parse,
612{
613 type Error = anyhow::Error;
614
615 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
616 let tail = bytes;
617
618 let (metadata, tail) =
619 PolicyCursor::parse::<PortMetadata>(tail).context("parsing metadata for context")?;
620
621 let (context, tail) = Context::parse(tail)
622 .map_err(Into::<anyhow::Error>::into)
623 .context("parsing context for port")?;
624
625 Ok((Self { metadata, context }, tail))
626 }
627}
628
629#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
630#[repr(C, packed)]
631pub(super) struct PortMetadata {
632 protocol: le::U32,
633 low_port: le::U32,
634 high_port: le::U32,
635}
636
637impl Validate for Node {
638 type Error = anyhow::Error;
639
640 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
642 Ok(())
643 }
644}
645
646#[derive(Debug, PartialEq)]
647pub(super) struct Node {
648 address: le::U32,
649 mask: le::U32,
650 context: Context,
651}
652
653impl Parse for Node
654where
655 Context: Parse,
656{
657 type Error = anyhow::Error;
658
659 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
660 let tail = bytes;
661
662 let (address, tail) = PolicyCursor::parse::<le::U32>(tail)?;
663
664 let (mask, tail) = PolicyCursor::parse::<le::U32>(tail)?;
665
666 let (context, tail) = Context::parse(tail)
667 .map_err(Into::<anyhow::Error>::into)
668 .context("parsing context for node")?;
669
670 Ok((Self { address, mask, context }, tail))
671 }
672}
673
674#[derive(Debug, PartialEq)]
675pub(super) struct FsUse {
676 behavior_and_name: Array<FsUseMetadata, u8>,
677 context: Context,
678}
679
680impl FsUse {
681 pub fn fs_type(&self) -> &[u8] {
682 &self.behavior_and_name.data
683 }
684
685 pub(super) fn behavior(&self) -> FsUseType {
686 FsUseType::try_from(self.behavior_and_name.metadata.behavior).unwrap()
687 }
688
689 pub(super) fn context(&self) -> &Context {
690 &self.context
691 }
692}
693
694impl Parse for FsUse
695where
696 Array<FsUseMetadata, u8>: Parse,
697 Context: Parse,
698{
699 type Error = anyhow::Error;
700
701 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
702 let tail = bytes;
703
704 let (behavior_and_name, tail) = Array::<FsUseMetadata, u8>::parse(tail)
705 .map_err(Into::<anyhow::Error>::into)
706 .context("parsing fs use metadata")?;
707
708 let (context, tail) = Context::parse(tail)
709 .map_err(Into::<anyhow::Error>::into)
710 .context("parsing context for fs use")?;
711
712 Ok((Self { behavior_and_name, context }, tail))
713 }
714}
715
716impl Validate for FsUse {
717 type Error = anyhow::Error;
718
719 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
720 FsUseType::try_from(self.behavior_and_name.metadata.behavior)?;
721
722 Ok(())
723 }
724}
725
726#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
727#[repr(C, packed)]
728pub(super) struct FsUseMetadata {
729 behavior: le::U32,
731 name_length: le::U32,
733}
734
735impl Counted for FsUseMetadata {
736 fn count(&self) -> u32 {
737 self.name_length.get()
738 }
739}
740
741#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
744pub enum FsUseType {
745 Xattr = 1,
746 Trans = 2,
747 Task = 3,
748}
749
750impl TryFrom<le::U32> for FsUseType {
751 type Error = anyhow::Error;
752
753 fn try_from(value: le::U32) -> Result<Self, Self::Error> {
754 match value.get() {
755 1 => Ok(FsUseType::Xattr),
756 2 => Ok(FsUseType::Trans),
757 3 => Ok(FsUseType::Task),
758 _ => Err(ValidateError::InvalidFsUseType { value: value.get() }.into()),
759 }
760 }
761}
762
763impl Validate for IPv6Node {
764 type Error = anyhow::Error;
765
766 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
768 Ok(())
769 }
770}
771
772#[derive(Debug, PartialEq)]
773pub(super) struct IPv6Node {
774 address: [le::U32; 4],
775 mask: [le::U32; 4],
776 context: Context,
777}
778
779impl Parse for IPv6Node
780where
781 Context: Parse,
782{
783 type Error = anyhow::Error;
784
785 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
786 let tail = bytes;
787
788 let (address, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
789
790 let (mask, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
791
792 let (context, tail) = Context::parse(tail)
793 .map_err(Into::<anyhow::Error>::into)
794 .context("parsing context for ipv6 node")?;
795
796 Ok((Self { address, mask, context }, tail))
797 }
798}
799
800impl Validate for InfinitiBandPartitionKey {
801 type Error = anyhow::Error;
802
803 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
805 Ok(())
806 }
807}
808
809#[derive(Debug, PartialEq)]
810pub(super) struct InfinitiBandPartitionKey {
811 low: le::U32,
812 high: le::U32,
813 context: Context,
814}
815
816impl Parse for InfinitiBandPartitionKey
817where
818 Context: Parse,
819{
820 type Error = anyhow::Error;
821
822 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
823 let tail = bytes;
824
825 let (low, tail) = PolicyCursor::parse::<le::U32>(tail)?;
826
827 let (high, tail) = PolicyCursor::parse::<le::U32>(tail)?;
828
829 let (context, tail) = Context::parse(tail)
830 .map_err(Into::<anyhow::Error>::into)
831 .context("parsing context for infiniti band partition key")?;
832
833 Ok((Self { low, high, context }, tail))
834 }
835}
836
837impl Validate for InfinitiBandEndPort {
838 type Error = anyhow::Error;
839
840 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
842 Ok(())
843 }
844}
845
846#[derive(Debug, PartialEq)]
847pub(super) struct InfinitiBandEndPort {
848 port_and_name: Array<InfinitiBandEndPortMetadata, u8>,
849 context: Context,
850}
851
852impl Parse for InfinitiBandEndPort
853where
854 Array<InfinitiBandEndPortMetadata, u8>: Parse,
855 Context: Parse,
856{
857 type Error = anyhow::Error;
858
859 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
860 let tail = bytes;
861
862 let (port_and_name, tail) = Array::<InfinitiBandEndPortMetadata, u8>::parse(tail)
863 .map_err(Into::<anyhow::Error>::into)
864 .context("parsing infiniti band end port metadata")?;
865
866 let (context, tail) = Context::parse(tail)
867 .map_err(Into::<anyhow::Error>::into)
868 .context("parsing context for infiniti band end port")?;
869
870 Ok((Self { port_and_name, context }, tail))
871 }
872}
873
874#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
875#[repr(C, packed)]
876pub(super) struct InfinitiBandEndPortMetadata {
877 length: le::U32,
878 port: le::U32,
879}
880
881impl Counted for InfinitiBandEndPortMetadata {
882 fn count(&self) -> u32 {
883 self.length.get()
884 }
885}
886
887impl Validate for GenericFsContext {
888 type Error = anyhow::Error;
889
890 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
892 Ok(())
893 }
894}
895
896#[derive(Debug)]
899pub(super) struct GenericFsContext {
900 fs_type: SimpleArray<u8>,
901 fs_context: SimpleArrayView<FsContext>,
902}
903
904impl GenericFsContext {
905 pub(super) fn for_query(fs_type: &str) -> SimpleArray<u8> {
907 Array { data: fs_type.as_bytes().to_vec(), metadata: le::U32::new(fs_type.len() as u32) }
908 }
909}
910
911impl Parse for GenericFsContext {
912 type Error = anyhow::Error;
913
914 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
915 let tail = bytes;
916
917 let (fs_type, tail) = SimpleArray::<u8>::parse(tail)
918 .map_err(Into::<anyhow::Error>::into)
919 .context("parsing fs_type for generic fs context")?;
920
921 let (fs_context, tail) = SimpleArrayView::<FsContext>::parse(tail)
922 .map_err(Into::<anyhow::Error>::into)
923 .context("parsing fs_context for generic fs context")?;
924
925 Ok((Self { fs_type, fs_context }, tail))
926 }
927}
928
929impl Hashable for GenericFsContext {
930 type Key = SimpleArray<u8>;
931 type Value = FsContext;
932
933 fn key(&self) -> &Self::Key {
934 &self.fs_type
935 }
936
937 fn values(&self) -> &SimpleArrayView<Self::Value> {
938 &self.fs_context
939 }
940}
941
942impl Eq for SimpleArray<u8> {}
943
944impl Hash for SimpleArray<u8> {
945 fn hash<H: Hasher>(&self, state: &mut H) {
946 self.data.hash(state);
947 }
948}
949
950impl SimpleArrayView<FsContext> {
951 fn try_validate_alphabetic_order(&self, context: &PolicyValidationContext) -> bool {
952 self.data()
953 .iter(&context.data)
954 .map(|view| view.parse(&context.data).partial_path().to_vec())
955 .is_sorted_by(|a, b| a <= b)
956 }
957
958 fn try_validate_length_descending_order(&self, context: &PolicyValidationContext) -> bool {
959 self.data()
960 .iter(&context.data)
961 .map(|view| view.parse(&context.data).partial_path().len())
962 .is_sorted_by(|a, b| a >= b)
963 }
964}
965
966impl Validate for SimpleArrayView<FsContext> {
967 type Error = anyhow::Error;
968
969 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
974 if !self.try_validate_alphabetic_order(context)
975 && !self.try_validate_length_descending_order(context)
976 {
977 return Err(anyhow::anyhow!(
978 "FsContexts must be sorted by partial path length (descending) or alphabetically.",
979 ));
980 }
981 Ok(())
982 }
983}
984
985#[derive(Debug, PartialEq)]
986pub(super) struct FsContext {
987 partial_path: SimpleArray<u8>,
990 class: le::U32,
994 context: Context,
996}
997
998impl FsContext {
999 pub(super) fn partial_path(&self) -> &[u8] {
1000 &self.partial_path.data
1001 }
1002
1003 pub(super) fn context(&self) -> &Context {
1004 &self.context
1005 }
1006
1007 pub(super) fn class(&self) -> Option<ClassId> {
1008 ClassId::try_from(self.class.get()).ok()
1009 }
1010}
1011
1012impl Parse for FsContext
1013where
1014 SimpleArray<u8>: Parse,
1015 Context: Parse,
1016{
1017 type Error = anyhow::Error;
1018
1019 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1020 let tail = bytes;
1021
1022 let (partial_path, tail) = SimpleArray::<u8>::parse(tail)
1023 .map_err(Into::<anyhow::Error>::into)
1024 .context("parsing filesystem context partial path")?;
1025
1026 let (class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1027
1028 let (context, tail) = Context::parse(tail)
1029 .map_err(Into::<anyhow::Error>::into)
1030 .context("parsing context for filesystem context")?;
1031
1032 Ok((Self { partial_path, class, context }, tail))
1033 }
1034}
1035
1036impl Walk for FsContext {
1037 fn walk(policy_data: &PolicyData, offset: PolicyOffset) -> PolicyOffset {
1038 let cursor = PolicyCursor::new_at(policy_data, offset);
1039 let (_, tail) = FsContext::parse(cursor)
1040 .map_err(Into::<anyhow::Error>::into)
1041 .expect("policy should be valid");
1042 tail.offset()
1043 }
1044}
1045
1046impl Validate for RangeTransition {
1047 type Error = anyhow::Error;
1048 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1049 if self.metadata.target_class.get() == 0 {
1050 return Err(ValidateError::NonOptionalIdIsZero.into());
1051 }
1052 Ok(())
1053 }
1054}
1055
1056#[derive(Debug, PartialEq)]
1057pub(super) struct RangeTransition {
1058 metadata: RangeTransitionMetadata,
1059 mls_range: MlsRange,
1060}
1061
1062impl RangeTransition {
1063 pub fn source_type(&self) -> TypeId {
1064 TypeId::from_u32(self.metadata.source_type.get()).unwrap()
1065 }
1066
1067 pub fn target_type(&self) -> TypeId {
1068 TypeId::from_u32(self.metadata.target_type.get()).unwrap()
1069 }
1070
1071 pub fn target_class(&self) -> ClassId {
1072 ClassId::try_from(self.metadata.target_class.get()).unwrap()
1073 }
1074
1075 pub fn mls_range(&self) -> &MlsRange {
1076 &self.mls_range
1077 }
1078}
1079
1080impl Parse for RangeTransition
1081where
1082 MlsRange: Parse,
1083{
1084 type Error = anyhow::Error;
1085
1086 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1087 let tail = bytes;
1088
1089 let (metadata, tail) = PolicyCursor::parse::<RangeTransitionMetadata>(tail)
1090 .context("parsing range transition metadata")?;
1091
1092 let (mls_range, tail) = MlsRange::parse(tail)
1093 .map_err(Into::<anyhow::Error>::into)
1094 .context("parsing mls range for range transition")?;
1095
1096 Ok((Self { metadata, mls_range }, tail))
1097 }
1098}
1099
1100#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1101#[repr(C, packed)]
1102pub(super) struct RangeTransitionMetadata {
1103 source_type: le::U32,
1104 target_type: le::U32,
1105 target_class: le::U32,
1106}
1107
1108#[cfg(test)]
1109mod tests {
1110 use super::super::parse_policy_by_value;
1111 use crate::new_policy::rules::{
1112 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES, XPERMS_TYPE_IOCTL_PREFIXES, XPERMS_TYPE_NLMSG,
1113 };
1114 use crate::new_policy::traits::HasPolicyId;
1115
1116 #[test]
1117 fn parse_allowxperm_one_ioctl() {
1118 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1119 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1120 let policy = policy.validate().expect("validate policy");
1121
1122 let class_id =
1123 policy.classes().get_by_name(b"class_one_ioctl").expect("look up class_one_ioctl").id();
1124
1125 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1126 let rules: Vec<_> = policy
1127 .access_vector_rules()
1128 .find_xperms_decisions(type0, type0, class_id)
1129 .allow
1130 .collect();
1131
1132 assert_eq!(rules.len(), 1);
1133 assert_eq!(rules[0].count(), 1);
1134 assert!(rules[0].contains(0xabcd));
1135 }
1136
1137 #[test]
1140 fn parse_allowxperm_two_ioctls_same_range() {
1141 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1142 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1143 let policy = policy.validate().expect("validate policy");
1144
1145 let class_id = policy
1146 .classes()
1147 .get_by_name(b"class_two_ioctls_same_range")
1148 .expect("look up class_two_ioctls_same_range")
1149 .id();
1150
1151 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1152 let rules: Vec<_> = policy
1153 .access_vector_rules()
1154 .find_xperms_decisions(type0, type0, class_id)
1155 .allow
1156 .collect();
1157
1158 assert_eq!(rules.len(), 1);
1159 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1160 assert_eq!(rules[0].xperms_optional_prefix(), 0x12);
1161 assert_eq!(rules[0].count(), 2);
1162 assert!(rules[0].contains(0x1234));
1163 assert!(rules[0].contains(0x1256));
1164 }
1165
1166 #[test]
1169 fn parse_allowxperm_two_ioctls_same_range_diff_rules() {
1170 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1171 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1172 let policy = policy.validate().expect("validate policy");
1173
1174 let class_id = policy
1175 .classes()
1176 .get_by_name(b"class_four_ioctls_same_range_diff_rules")
1177 .expect("look up class_four_ioctls_same_range_diff_rules")
1178 .id();
1179
1180 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1181 let rules: Vec<_> = policy
1182 .access_vector_rules()
1183 .find_xperms_decisions(type0, type0, class_id)
1184 .allow
1185 .collect();
1186
1187 assert_eq!(rules.len(), 1);
1188 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1189 assert_eq!(rules[0].xperms_optional_prefix(), 0x30);
1190 assert_eq!(rules[0].count(), 4);
1191 assert!(rules[0].contains(0x3008));
1192 assert!(rules[0].contains(0x3009));
1193 assert!(rules[0].contains(0x3011));
1194 assert!(rules[0].contains(0x3013));
1195 }
1196
1197 #[test]
1200 fn parse_allowxperm_two_ioctls_different_range() {
1201 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1202 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1203 let policy = policy.validate().expect("validate policy");
1204
1205 let class_id = policy
1206 .classes()
1207 .get_by_name(b"class_two_ioctls_diff_range")
1208 .expect("look up class_two_ioctls_diff_range")
1209 .id();
1210
1211 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1212 let rules: Vec<_> = policy
1213 .access_vector_rules()
1214 .find_xperms_decisions(type0, type0, class_id)
1215 .allow
1216 .collect();
1217
1218 assert_eq!(rules.len(), 2);
1219 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1220 assert_eq!(rules[0].xperms_optional_prefix(), 0x56);
1221 assert_eq!(rules[0].count(), 1);
1222 assert!(rules[0].contains(0x5678));
1223 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1224 assert_eq!(rules[1].xperms_optional_prefix(), 0x12);
1225 assert_eq!(rules[1].count(), 1);
1226 assert!(rules[1].contains(0x1234));
1227 }
1228
1229 #[test]
1232 fn parse_allowxperm_one_driver_range() {
1233 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1234 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1235 let policy = policy.validate().expect("validate policy");
1236
1237 let class_id = policy
1238 .classes()
1239 .get_by_name(b"class_one_driver_range")
1240 .expect("look up class_one_driver_range")
1241 .id();
1242
1243 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1244 let rules: Vec<_> = policy
1245 .access_vector_rules()
1246 .find_xperms_decisions(type0, type0, class_id)
1247 .allow
1248 .collect();
1249
1250 assert_eq!(rules.len(), 1);
1251 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_IOCTL_PREFIXES);
1252 assert_eq!(rules[0].count(), 0x100);
1253 assert!(rules[0].contains(0x1000));
1254 assert!(rules[0].contains(0x10ab));
1255 }
1256
1257 #[test]
1261 fn parse_allowxperm_most_ioctls() {
1262 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1263 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1264 let policy = policy.validate().expect("validate policy");
1265
1266 let class_id = policy
1267 .classes()
1268 .get_by_name(b"class_most_ioctls")
1269 .expect("look up class_most_ioctls")
1270 .id();
1271
1272 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1273 let rules: Vec<_> = policy
1274 .access_vector_rules()
1275 .find_xperms_decisions(type0, type0, class_id)
1276 .allow
1277 .collect();
1278
1279 assert_eq!(rules.len(), 3);
1280 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1281 assert_eq!(rules[0].xperms_optional_prefix(), 0xff);
1282 assert_eq!(rules[0].count(), 0xfe);
1283 for xperm in 0xff00..0xfffd {
1284 assert!(rules[0].contains(xperm));
1285 }
1286 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1287 assert_eq!(rules[1].xperms_optional_prefix(), 0x00);
1288 assert_eq!(rules[1].count(), 0xfe);
1289 for xperm in 0x0002..0x0100 {
1290 assert!(rules[1].contains(xperm));
1291 }
1292 assert_eq!(rules[2].xperms_type(), XPERMS_TYPE_IOCTL_PREFIXES);
1293 assert_eq!(rules[2].count(), 0xfe00);
1294 for xperm in 0x0100..0xff00 {
1295 assert!(rules[2].contains(xperm));
1296 }
1297 }
1298
1299 #[test]
1303 fn parse_allowxperm_most_ioctls_with_hole() {
1304 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1305 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1306 let policy = policy.validate().expect("validate policy");
1307
1308 let class_id = policy
1309 .classes()
1310 .get_by_name(b"class_most_ioctls_with_hole")
1311 .expect("look up class_most_ioctls_with_hole")
1312 .id();
1313
1314 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1315 let rules: Vec<_> = policy
1316 .access_vector_rules()
1317 .find_xperms_decisions(type0, type0, class_id)
1318 .allow
1319 .collect();
1320
1321 assert_eq!(rules.len(), 5);
1322 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1323 assert_eq!(rules[0].xperms_optional_prefix(), 0xff);
1324 assert_eq!(rules[0].count(), 0xfe);
1325 for xperm in 0xff00..0xfffd {
1326 assert!(rules[0].contains(xperm));
1327 }
1328 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1329 assert_eq!(rules[1].xperms_optional_prefix(), 0x40);
1330 assert_eq!(rules[1].count(), 0xfe);
1331 for xperm in 0x4002..0x4100 {
1332 assert!(rules[1].contains(xperm));
1333 }
1334 assert_eq!(rules[2].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1335 assert_eq!(rules[2].xperms_optional_prefix(), 0x2f);
1336 assert_eq!(rules[2].count(), 0xfe);
1337 for xperm in 0x2f00..0x2ffd {
1338 assert!(rules[2].contains(xperm));
1339 }
1340 assert_eq!(rules[3].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1341 assert_eq!(rules[3].xperms_optional_prefix(), 0x00);
1342 assert_eq!(rules[3].count(), 0xfe);
1343 for xperm in 0x0002..0x0100 {
1344 assert!(rules[3].contains(xperm));
1345 }
1346 assert_eq!(rules[4].xperms_type(), XPERMS_TYPE_IOCTL_PREFIXES);
1347 assert_eq!(rules[4].count(), 0xec00);
1348 for xperm in 0x0100..0x2f00 {
1349 assert!(rules[4].contains(xperm));
1350 }
1351 for xperm in 0x4100..0xff00 {
1352 assert!(rules[4].contains(xperm));
1353 }
1354 }
1355
1356 #[test]
1361 fn parse_allowxperm_all_ioctls() {
1362 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1363 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1364 let policy = policy.validate().expect("validate policy");
1365
1366 let class_id = policy
1367 .classes()
1368 .get_by_name(b"class_all_ioctls")
1369 .expect("look up class_all_ioctls")
1370 .id();
1371
1372 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1373 let rules: Vec<_> = policy
1374 .access_vector_rules()
1375 .find_xperms_decisions(type0, type0, class_id)
1376 .allow
1377 .collect();
1378
1379 assert_eq!(rules.len(), 1);
1380 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_IOCTL_PREFIXES);
1381 assert_eq!(rules[0].count(), 0x10000);
1382 }
1383
1384 #[test]
1385 fn parse_allowxperm_one_nlmsg() {
1386 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1387 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1388 let policy = policy.validate().expect("validate policy");
1389
1390 let class_id =
1391 policy.classes().get_by_name(b"class_one_nlmsg").expect("look up class_one_nlmsg").id();
1392
1393 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1394 let rules: Vec<_> = policy
1395 .access_vector_rules()
1396 .find_xperms_decisions(type0, type0, class_id)
1397 .allow
1398 .collect();
1399
1400 assert_eq!(rules.len(), 1);
1401 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1402 assert_eq!(rules[0].xperms_optional_prefix(), 0x00);
1403 assert_eq!(rules[0].count(), 1);
1404 assert!(rules[0].contains(0x12));
1405 }
1406
1407 #[test]
1410 fn parse_allowxperm_two_nlmsg_same_range() {
1411 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1412 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1413 let policy = policy.validate().expect("validate policy");
1414
1415 let class_id = policy
1416 .classes()
1417 .get_by_name(b"class_two_nlmsg_same_range")
1418 .expect("look up class_two_nlmsg_same_range")
1419 .id();
1420
1421 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1422 let rules: Vec<_> = policy
1423 .access_vector_rules()
1424 .find_xperms_decisions(type0, type0, class_id)
1425 .allow
1426 .collect();
1427
1428 assert_eq!(rules.len(), 1);
1429 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1430 assert_eq!(rules[0].xperms_optional_prefix(), 0x00);
1431 assert_eq!(rules[0].count(), 2);
1432 assert!(rules[0].contains(0x12));
1433 assert!(rules[0].contains(0x24));
1434 }
1435
1436 #[test]
1439 fn parse_allowxperm_two_nlmsg_different_range() {
1440 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1441 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1442 let policy = policy.validate().expect("validate policy");
1443
1444 let class_id = policy
1445 .classes()
1446 .get_by_name(b"class_two_nlmsg_diff_range")
1447 .expect("look up class_two_nlmsg_diff_range")
1448 .id();
1449
1450 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1451 let rules: Vec<_> = policy
1452 .access_vector_rules()
1453 .find_xperms_decisions(type0, type0, class_id)
1454 .allow
1455 .collect();
1456
1457 assert_eq!(rules.len(), 2);
1458 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1459 assert_eq!(rules[0].xperms_optional_prefix(), 0x10);
1460 assert_eq!(rules[0].count(), 1);
1461 assert!(rules[0].contains(0x1024));
1462 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_NLMSG);
1463 assert_eq!(rules[1].xperms_optional_prefix(), 0x00);
1464 assert_eq!(rules[1].count(), 1);
1465 assert!(rules[1].contains(0x12));
1466 }
1467
1468 #[test]
1471 fn parse_allowxperm_one_nlmsg_range() {
1472 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1473 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1474 let policy = policy.validate().expect("validate policy");
1475
1476 let class_id = policy
1477 .classes()
1478 .get_by_name(b"class_one_nlmsg_range")
1479 .expect("look up class_one_nlmsg_range")
1480 .id();
1481
1482 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1483 let rules: Vec<_> = policy
1484 .access_vector_rules()
1485 .find_xperms_decisions(type0, type0, class_id)
1486 .allow
1487 .collect();
1488
1489 assert_eq!(rules.len(), 1);
1490 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1491 assert_eq!(rules[0].xperms_optional_prefix(), 0x00);
1492 assert_eq!(rules[0].count(), 0x100);
1493 for i in 0x0..0xff {
1494 assert!(rules[0].contains(i), "{i}");
1495 }
1496 }
1497
1498 #[test]
1504 fn parse_allowxperm_two_nlmsg_ranges() {
1505 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1506 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1507 let policy = policy.validate().expect("validate policy");
1508
1509 let class_id = policy
1510 .classes()
1511 .get_by_name(b"class_two_nlmsg_ranges")
1512 .expect("look up class_two_nlmsg_ranges")
1513 .id();
1514
1515 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1516 let rules: Vec<_> = policy
1517 .access_vector_rules()
1518 .find_xperms_decisions(type0, type0, class_id)
1519 .allow
1520 .collect();
1521
1522 assert_eq!(rules.len(), 2);
1523 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1524 assert_eq!(rules[0].xperms_optional_prefix(), 0x01);
1525 assert_eq!(rules[0].count(), 0x100);
1526 for i in 0x0100..0x01ff {
1527 assert!(rules[0].contains(i), "{i}");
1528 }
1529 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_NLMSG);
1530 assert_eq!(rules[1].xperms_optional_prefix(), 0x00);
1531 assert_eq!(rules[1].count(), 0x100);
1532 for i in 0x0..0xff {
1533 assert!(rules[1].contains(i), "{i}");
1534 }
1535 }
1536
1537 #[test]
1544 fn parse_allowxperm_three_separate_nlmsg_ranges() {
1545 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1546 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1547 let policy = policy.validate().expect("validate policy");
1548
1549 let class_id = policy
1550 .classes()
1551 .get_by_name(b"class_three_separate_nlmsg_ranges")
1552 .expect("look up class_three_separate_nlmsg_ranges")
1553 .id();
1554
1555 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1556 let rules: Vec<_> = policy
1557 .access_vector_rules()
1558 .find_xperms_decisions(type0, type0, class_id)
1559 .allow
1560 .collect();
1561
1562 assert_eq!(rules.len(), 3);
1563 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1564 assert_eq!(rules[0].xperms_optional_prefix(), 0x20);
1565 assert_eq!(rules[0].count(), 0x100);
1566 for i in 0x2000..0x20ff {
1567 assert!(rules[0].contains(i), "{i}");
1568 }
1569 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_NLMSG);
1570 assert_eq!(rules[1].xperms_optional_prefix(), 0x10);
1571 assert_eq!(rules[1].count(), 0x100);
1572 for i in 0x1000..0x10ff {
1573 assert!(rules[1].contains(i), "{i}");
1574 }
1575 assert_eq!(rules[2].xperms_type(), XPERMS_TYPE_NLMSG);
1576 assert_eq!(rules[2].xperms_optional_prefix(), 0x00);
1577 assert_eq!(rules[2].count(), 0x100);
1578 for i in 0x0..0xff {
1579 assert!(rules[2].contains(i), "{i}");
1580 }
1581 }
1582
1583 #[test]
1590 fn parse_allowxperm_three_contiguous_nlmsg_ranges() {
1591 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1592 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1593 let policy = policy.validate().expect("validate policy");
1594
1595 let class_id = policy
1596 .classes()
1597 .get_by_name(b"class_three_contiguous_nlmsg_ranges")
1598 .expect("look up class_three_contiguous_nlmsg_ranges")
1599 .id();
1600
1601 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1602 let rules: Vec<_> = policy
1603 .access_vector_rules()
1604 .find_xperms_decisions(type0, type0, class_id)
1605 .allow
1606 .collect();
1607
1608 assert_eq!(rules.len(), 2);
1609 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1610 assert_eq!(rules[0].xperms_optional_prefix(), 0x02);
1611 assert_eq!(rules[0].count(), 0x100);
1612 for i in 0x0200..0x02ff {
1613 assert!(rules[0].contains(i), "{i}");
1614 }
1615 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_NLMSG);
1616 assert_eq!(rules[1].xperms_optional_prefix(), 0x00);
1617 assert_eq!(rules[1].count(), 0x100);
1618 for i in 0x0..0xff {
1619 assert!(rules[1].contains(i), "{i}");
1620 }
1621 }
1622
1623 #[test]
1626 fn parse_auditallowxperm() {
1627 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1628 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1629 let policy = policy.validate().expect("validate policy");
1630
1631 let class_id = policy
1632 .classes()
1633 .get_by_name(b"class_auditallowxperm")
1634 .expect("look up class_auditallowxperm")
1635 .id();
1636
1637 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1638 let decisions = policy.access_vector_rules().find_xperms_decisions(type0, type0, class_id);
1639 let rules: Vec<_> = decisions.auditallow.collect();
1640
1641 assert_eq!(rules.len(), 2);
1642 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1643 assert_eq!(rules[0].xperms_optional_prefix(), 0x00);
1644 assert_eq!(rules[0].count(), 1);
1645 assert!(rules[0].contains(0x10));
1646 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1647 assert_eq!(rules[1].xperms_optional_prefix(), 0x10);
1648 assert_eq!(rules[1].count(), 1);
1649 assert!(rules[1].contains(0x1000));
1650 }
1651
1652 #[test]
1660 fn parse_dontauditxperm() {
1661 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1662 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1663 let policy = policy.validate().expect("validate policy");
1664
1665 let class_id = policy
1666 .classes()
1667 .get_by_name(b"class_dontauditxperm")
1668 .expect("look up class_dontauditxperm")
1669 .id();
1670
1671 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1672 let decisions = policy.access_vector_rules().find_xperms_decisions(type0, type0, class_id);
1673 let rules: Vec<_> = decisions.dontaudit.collect();
1674
1675 assert_eq!(rules.len(), 2);
1676 assert_eq!(rules[0].xperms_type(), XPERMS_TYPE_NLMSG);
1677 assert_eq!(rules[0].xperms_optional_prefix(), 0x00);
1678 assert_eq!(rules[0].count(), 1);
1679 assert!(rules[0].contains(0x11));
1680 assert_eq!(rules[1].xperms_type(), XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1681 assert_eq!(rules[1].xperms_optional_prefix(), 0x10);
1682 assert_eq!(rules[1].count(), 1);
1683 assert!(rules[1].contains(0x1000));
1684 }
1685
1686 #[test]
1690 fn parse_auditallowxperm_not_coalesced() {
1691 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1692 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1693 let policy = policy.validate().expect("validate policy");
1694
1695 let class_id = policy
1696 .classes()
1697 .get_by_name(b"class_auditallowxperm_not_coalesced")
1698 .expect("class_auditallowxperm_not_coalesced")
1699 .id();
1700
1701 let type0 = policy.types().get_by_name(b"type0").expect("look up type0").id();
1702 let decisions = policy.access_vector_rules().find_xperms_decisions(type0, type0, class_id);
1703 let allow_rules: Vec<_> = decisions.allow.collect();
1704 let auditallow_rules: Vec<_> = decisions.auditallow.collect();
1705
1706 assert_eq!(allow_rules.len(), 1);
1707 assert_eq!(allow_rules[0].count(), 1);
1708 assert!(allow_rules[0].contains(0xabcd));
1709 assert_eq!(auditallow_rules.len(), 1);
1710 assert_eq!(auditallow_rules[0].count(), 1);
1711 assert!(auditallow_rules[0].contains(0xabcd));
1712 }
1713}