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