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