1use super::error::ValidateError;
6use super::extensible_bitmap::ExtensibleBitmap;
7use super::parser::{PolicyCursor, PolicyData, PolicyOffset};
8
9use super::view::U24;
10use super::{
11 Array, CategoryId, Counted, MlsLevel, MlsRange, Parse, PolicyValidationContext, RoleId,
12 SensitivityId, TypeId, UserId, Validate, ValidateArray, array_type,
13 array_type_validate_deref_both,
14};
15
16use crate::new_policy::traits::PolicyId;
17use anyhow::{Context as _, anyhow};
18use hashbrown::hash_table::HashTable;
19use rapidhash::RapidHasher;
20use std::fmt::Debug;
21use std::hash::{Hash, Hasher};
22use std::ops::Deref;
23use zerocopy::{FromBytes, Immutable, KnownLayout, Unaligned, little_endian as le};
24
25const TYPE_PROPERTIES_TYPE: u32 = 1;
27
28const TYPE_PROPERTIES_ALIAS: u32 = 0;
30
31const TYPE_PROPERTIES_ATTRIBUTE: u32 = 3;
33
34#[derive(Debug, PartialEq)]
37pub(super) struct SymbolList<T>(Array<Metadata, T>);
38
39impl<T> Deref for SymbolList<T> {
40 type Target = Array<Metadata, T>;
41
42 fn deref(&self) -> &Self::Target {
43 &self.0
44 }
45}
46
47impl<T: Parse> Parse for SymbolList<T> {
48 type Error = <Array<Metadata, T> as Parse>::Error;
49
50 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
51 let (array, tail) = Array::<Metadata, T>::parse(bytes)?;
52 Ok((Self(array), tail))
53 }
54}
55
56impl<T: Validate> Validate for SymbolList<T> {
57 type Error = anyhow::Error;
58
59 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
60 self.0.metadata.validate(context)?;
61 self.0.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
62
63 Ok(())
64 }
65}
66
67#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
69#[repr(C, packed)]
70pub(super) struct Metadata {
71 primary_names_count: le::U32,
73 count: le::U32,
75}
76
77impl Metadata {
78 pub fn primary_names_count(&self) -> u32 {
79 self.primary_names_count.get()
80 }
81}
82
83impl Counted for Metadata {
84 fn count(&self) -> u32 {
87 self.count.get()
88 }
89}
90
91impl Validate for Metadata {
92 type Error = anyhow::Error;
93
94 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
96 Ok(())
97 }
98}
99
100impl Validate for Role {
101 type Error = anyhow::Error;
102
103 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
105 Ok(())
106 }
107}
108
109#[derive(Debug, PartialEq)]
110pub(super) struct Role {
111 metadata: RoleMetadata,
112 role_dominates: ExtensibleBitmap,
113 role_types: ExtensibleBitmap,
114}
115
116impl Role {
117 pub(super) fn id(&self) -> RoleId {
118 RoleId::from_u32(self.metadata.metadata.id.get()).unwrap()
119 }
120
121 pub(super) fn name_bytes(&self) -> &[u8] {
122 &self.metadata.data
123 }
124
125 pub(super) fn types(&self) -> &ExtensibleBitmap {
126 &self.role_types
127 }
128}
129
130impl Parse for Role {
131 type Error = anyhow::Error;
132
133 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
134 let tail = bytes;
135
136 let (metadata, tail) = RoleMetadata::parse(tail)
137 .map_err(Into::<anyhow::Error>::into)
138 .context("parsing role metadata")?;
139
140 let (role_dominates, tail) = ExtensibleBitmap::parse(tail)
141 .map_err(Into::<anyhow::Error>::into)
142 .context("parsing role dominates")?;
143
144 let (role_types, tail) = ExtensibleBitmap::parse(tail)
145 .map_err(Into::<anyhow::Error>::into)
146 .context("parsing role types")?;
147
148 Ok((Self { metadata, role_dominates, role_types }, tail))
149 }
150}
151
152array_type!(RoleMetadata, RoleStaticMetadata, u8);
153
154array_type_validate_deref_both!(RoleMetadata);
155
156impl ValidateArray<RoleStaticMetadata, u8> for RoleMetadata {
157 type Error = anyhow::Error;
158
159 fn validate_array(
161 _context: &PolicyValidationContext,
162 _metadata: &RoleStaticMetadata,
163 _items: &[u8],
164 ) -> Result<(), Self::Error> {
165 Ok(())
166 }
167}
168
169#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
170#[repr(C, packed)]
171pub(super) struct RoleStaticMetadata {
172 length: le::U32,
173 id: le::U32,
174 bounds: le::U32,
175}
176
177impl Counted for RoleStaticMetadata {
178 fn count(&self) -> u32 {
180 self.length.get()
181 }
182}
183
184impl Validate for RoleStaticMetadata {
185 type Error = anyhow::Error;
186
187 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
189 Ok(())
190 }
191}
192
193array_type!(Type, TypeMetadata, u8);
194
195array_type_validate_deref_both!(Type);
196
197impl Type {
198 pub fn name_bytes(&self) -> &[u8] {
200 &self.data
201 }
202
203 pub fn id(&self) -> TypeId {
207 TypeId::from_u32(self.metadata.id.get()).unwrap()
208 }
209
210 pub fn bounded_by(&self) -> Option<TypeId> {
212 TypeId::from_u32(self.metadata.bounds.get())
213 }
214}
215
216impl ValidateArray<TypeMetadata, u8> for Type {
217 type Error = anyhow::Error;
218
219 fn validate_array(
221 _context: &PolicyValidationContext,
222 _metadata: &TypeMetadata,
223 _items: &[u8],
224 ) -> Result<(), Self::Error> {
225 Ok(())
226 }
227}
228
229#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
230#[repr(C, packed)]
231pub(super) struct TypeMetadata {
232 length: le::U32,
233 id: le::U32,
234 properties: le::U32,
235 bounds: le::U32,
236}
237
238impl Counted for TypeMetadata {
239 fn count(&self) -> u32 {
240 self.length.get()
241 }
242}
243
244impl Validate for TypeMetadata {
245 type Error = anyhow::Error;
246
247 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
249 Ok(())
250 }
251}
252
253fn name_hash(name: &[u8]) -> u64 {
254 let mut hasher = RapidHasher::default();
255 name.hash(&mut hasher);
256 hasher.finish()
257}
258
259#[derive(Debug)]
260pub(super) struct TypeIndex {
261 primary_names_count: u32,
264
265 offsets_by_id_minus_one: Box<[U24]>,
279
280 offsets_by_name: HashTable<U24>,
286}
287
288impl TypeIndex {
289 fn parse_type_at(policy_bytes: &PolicyData, offset: U24) -> Type {
290 Type::parse(PolicyCursor::new_at(policy_bytes, PolicyOffset::from(offset)))
291 .expect("These bytes already successfully parsed")
292 .0
293 }
294
295 pub(super) fn primary_names_count(&self) -> u32 {
296 self.primary_names_count
297 }
298
299 pub(super) fn type_id_by_name(&self, name: &str, data: &PolicyData) -> Option<TypeId> {
300 let name_bytes = name.as_bytes();
301 self.offsets_by_name
302 .find(name_hash(name_bytes), |&other_offset| {
303 Self::parse_type_at(data, other_offset).name_bytes() == name_bytes
304 })
305 .map(|&offset| Self::parse_type_at(data, offset).id())
306 }
307
308 pub(super) fn type_by_type_id(&self, id: TypeId, data: &PolicyData) -> Type {
309 Self::parse_type_at(data, self.offsets_by_id_minus_one[(id.as_u32() - 1) as usize])
310 }
311
312 pub(super) fn all_type_ids(&self) -> impl Iterator<Item = TypeId> {
314 self.offsets_by_id_minus_one.iter().enumerate().filter_map(
315 |(index, offset)| match u32::from(*offset) {
316 0 => None,
317 _ => Some(TypeId::from_u32((index + 1) as u32).unwrap()),
318 },
319 )
320 }
321}
322
323impl Parse for TypeIndex {
324 type Error = anyhow::Error;
325
326 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
327 let policy_data = bytes.data();
328 let (metadata, mut tail) = Metadata::parse(bytes)?;
329 let type_count = usize::try_from(metadata.count()).unwrap();
330 let mut offsets_by_id_minus_one = Vec::with_capacity(type_count);
331 let mut offsets_by_name = HashTable::with_capacity(type_count);
332 for _ in 0..type_count {
333 let offset = U24::try_from(tail.offset()).unwrap();
334 let (type_, next_tail) = Type::parse(tail)?;
335
336 let will_be_looked_up_by_id;
337 let will_be_looked_up_by_name;
338 match type_.metadata.properties.get() {
339 TYPE_PROPERTIES_TYPE => {
340 will_be_looked_up_by_id = true;
341 will_be_looked_up_by_name = true;
342 }
343 TYPE_PROPERTIES_ATTRIBUTE => {
344 will_be_looked_up_by_id = true;
345 will_be_looked_up_by_name = false;
346 }
347 TYPE_PROPERTIES_ALIAS => {
348 will_be_looked_up_by_id = false;
349 will_be_looked_up_by_name = true;
350 }
351 unrecognized => {
352 return Err(anyhow!(
353 "Can't parse \"type\" element with \"properties\" value {:?}",
354 unrecognized
355 ));
356 }
357 }
358
359 if will_be_looked_up_by_id {
360 let type_id_as_usize = type_.id().as_u32() as usize;
361 if offsets_by_id_minus_one.len() < type_id_as_usize {
362 offsets_by_id_minus_one.resize(type_id_as_usize, U24::try_from(0).unwrap());
363 }
364 offsets_by_id_minus_one[type_id_as_usize - 1] = offset;
365 }
366
367 if will_be_looked_up_by_name {
368 let name_bytes = type_.name_bytes();
369 offsets_by_name
370 .entry(
371 name_hash(name_bytes),
372 |&other_offset| {
373 Self::parse_type_at(&policy_data, other_offset).name_bytes()
374 == name_bytes
375 },
376 |&other_offset| {
377 name_hash(Self::parse_type_at(&policy_data, other_offset).name_bytes())
378 },
379 )
380 .insert(offset);
381 }
382
383 tail = next_tail;
384 }
385 let offsets_by_id_minus_one = Box::<[U24]>::from(offsets_by_id_minus_one);
386 offsets_by_name.shrink_to_fit(|&other_offset| {
387 name_hash(Self::parse_type_at(&policy_data, other_offset).name_bytes())
388 });
389
390 Ok((
391 Self {
392 primary_names_count: metadata.primary_names_count(),
393 offsets_by_id_minus_one,
394 offsets_by_name,
395 },
396 tail,
397 ))
398 }
399}
400
401impl Validate for TypeIndex {
402 type Error = anyhow::Error;
403
404 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
406 let data = context.data.clone();
407 let mut primary_names_count = 0u32;
408 for offset in &self.offsets_by_id_minus_one {
409 if PolicyOffset::from(*offset) != 0 {
410 Self::parse_type_at(&data, *offset).validate(context)?;
411 primary_names_count += 1;
412 }
413 }
414
415 if self.primary_names_count != primary_names_count {
416 return Err(anyhow!(
417 "Expected {:?} primary names but found {:?}",
418 self.primary_names_count,
419 primary_names_count
420 ));
421 }
422
423 Ok(())
424 }
425}
426
427impl Validate for User {
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 User {
438 user_data: UserData,
439 roles: ExtensibleBitmap,
440 expanded_range: MlsRange,
441 default_level: MlsLevel,
442}
443
444impl User {
445 pub(super) fn id(&self) -> UserId {
446 UserId::from_u32(self.user_data.metadata.id.get()).unwrap()
447 }
448
449 pub(super) fn name_bytes(&self) -> &[u8] {
450 &self.user_data.data
451 }
452
453 pub(super) fn roles(&self) -> &ExtensibleBitmap {
454 &self.roles
455 }
456
457 pub(super) fn mls_range(&self) -> &MlsRange {
458 &self.expanded_range
459 }
460}
461
462impl Parse for User {
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 (user_data, tail) = UserData::parse(tail)
469 .map_err(Into::<anyhow::Error>::into)
470 .context("parsing user data")?;
471
472 let (roles, tail) = ExtensibleBitmap::parse(tail)
473 .map_err(Into::<anyhow::Error>::into)
474 .context("parsing user roles")?;
475
476 let (expanded_range, tail) =
477 MlsRange::parse(tail).context("parsing user expanded range")?;
478
479 let (default_level, tail) = MlsLevel::parse(tail).context("parsing user default level")?;
480
481 Ok((Self { user_data, roles, expanded_range, default_level }, tail))
482 }
483}
484
485array_type!(UserData, UserMetadata, u8);
486
487array_type_validate_deref_both!(UserData);
488
489impl ValidateArray<UserMetadata, u8> for UserData {
490 type Error = anyhow::Error;
491
492 fn validate_array(
494 _context: &PolicyValidationContext,
495 _metadata: &UserMetadata,
496 _items: &[u8],
497 ) -> Result<(), Self::Error> {
498 Ok(())
499 }
500}
501
502#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
503#[repr(C, packed)]
504pub(super) struct UserMetadata {
505 length: le::U32,
506 id: le::U32,
507 bounds: le::U32,
508}
509
510impl Counted for UserMetadata {
511 fn count(&self) -> u32 {
512 self.length.get()
513 }
514}
515
516impl Validate for UserMetadata {
517 type Error = anyhow::Error;
518
519 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
521 Ok(())
522 }
523}
524
525impl Parse for MlsLevel {
526 type Error = anyhow::Error;
527
528 fn parse<'a>(cursor: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
529 let offset = cursor.offset() as usize;
530 let slice = &cursor.data().as_ref()[offset..];
531 let mut new_cursor = crate::new_policy::parser::PolicyCursor::new(slice);
532 let level = <Self as crate::new_policy::traits::Parse>::parse(&mut new_cursor)
533 .map_err(|e| anyhow::anyhow!("Parse error: {:?}", e))?;
534 let bytes_parsed = new_cursor.offset();
535 let new_offset = cursor.offset() + bytes_parsed as u32;
536 Ok((level, PolicyCursor::new_at(cursor.data(), new_offset)))
537 }
538}
539
540impl Validate for MlsLevel {
541 type Error = anyhow::Error;
542
543 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
544 crate::new_policy::traits::Validate::validate(self, &context.new_policy).map_err(Into::into)
545 }
546}
547
548impl Parse for MlsRange {
549 type Error = anyhow::Error;
550
551 fn parse<'a>(cursor: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
552 let offset = cursor.offset() as usize;
553 let slice = &cursor.data().as_ref()[offset..];
554 let mut new_cursor = crate::new_policy::parser::PolicyCursor::new(slice);
555 let range = <Self as crate::new_policy::traits::Parse>::parse(&mut new_cursor)
556 .map_err(|e| anyhow::anyhow!("Parse error: {:?}", e))?;
557 let bytes_parsed = new_cursor.offset();
558 let new_offset = cursor.offset() + bytes_parsed as u32;
559 Ok((range, PolicyCursor::new_at(cursor.data(), new_offset)))
560 }
561}
562
563impl Validate for MlsRange {
564 type Error = anyhow::Error;
565
566 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
567 crate::new_policy::traits::Validate::validate(self, &context.new_policy).map_err(Into::into)
568 }
569}
570
571array_type!(ConditionalBoolean, ConditionalBooleanMetadata, u8);
572
573array_type_validate_deref_both!(ConditionalBoolean);
574
575impl ValidateArray<ConditionalBooleanMetadata, u8> for ConditionalBoolean {
576 type Error = anyhow::Error;
577
578 fn validate_array(
580 _context: &PolicyValidationContext,
581 _metadata: &ConditionalBooleanMetadata,
582 _items: &[u8],
583 ) -> Result<(), Self::Error> {
584 Ok(())
585 }
586}
587
588#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
589#[repr(C, packed)]
590pub(super) struct ConditionalBooleanMetadata {
591 id: le::U32,
592 active: le::U32,
594 length: le::U32,
595}
596
597impl ConditionalBooleanMetadata {
598 pub(super) fn active(&self) -> bool {
600 self.active != le::U32::ZERO
601 }
602}
603
604impl Counted for ConditionalBooleanMetadata {
605 fn count(&self) -> u32 {
608 self.length.get()
609 }
610}
611
612impl Validate for ConditionalBooleanMetadata {
613 type Error = anyhow::Error;
614
615 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
617 Ok(())
618 }
619}
620
621#[derive(Debug, PartialEq)]
622pub(super) struct Sensitivity {
623 metadata: SensitivityMetadata,
624 level: MlsLevel,
625}
626
627impl Sensitivity {
628 pub fn id(&self) -> SensitivityId {
629 self.level.sensitivity()
630 }
631
632 pub fn name_bytes(&self) -> &[u8] {
633 &self.metadata.data
634 }
635}
636
637impl Parse for Sensitivity {
638 type Error = anyhow::Error;
639
640 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
641 let tail = bytes;
642
643 let (metadata, tail) = SensitivityMetadata::parse(tail)
644 .map_err(Into::<anyhow::Error>::into)
645 .context("parsing sensitivity metadata")?;
646
647 let (level, tail) = MlsLevel::parse(tail)
648 .map_err(Into::<anyhow::Error>::into)
649 .context("parsing sensitivity mls level")?;
650
651 Ok((Self { metadata, level }, tail))
652 }
653}
654
655impl Validate for Sensitivity {
656 type Error = anyhow::Error;
657
658 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
660 Ok(())
661 }
662}
663
664array_type!(SensitivityMetadata, SensitivityStaticMetadata, u8);
665
666array_type_validate_deref_both!(SensitivityMetadata);
667
668impl ValidateArray<SensitivityStaticMetadata, u8> for SensitivityMetadata {
669 type Error = anyhow::Error;
670
671 fn validate_array(
673 _context: &PolicyValidationContext,
674 _metadata: &SensitivityStaticMetadata,
675 _items: &[u8],
676 ) -> Result<(), Self::Error> {
677 Ok(())
678 }
679}
680
681#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
682#[repr(C, packed)]
683pub(super) struct SensitivityStaticMetadata {
684 length: le::U32,
685 is_alias: le::U32,
686}
687
688impl Counted for SensitivityStaticMetadata {
689 fn count(&self) -> u32 {
692 self.length.get()
693 }
694}
695
696impl Validate for SensitivityStaticMetadata {
697 type Error = anyhow::Error;
698
699 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
701 Ok(())
702 }
703}
704
705array_type!(Category, CategoryMetadata, u8);
706
707array_type_validate_deref_both!(Category);
708
709impl Category {
710 pub fn id(&self) -> CategoryId {
711 CategoryId::from_u32(self.metadata.id.get()).unwrap()
712 }
713
714 pub fn name_bytes(&self) -> &[u8] {
715 &self.data
716 }
717}
718
719impl ValidateArray<CategoryMetadata, u8> for Category {
720 type Error = anyhow::Error;
721
722 fn validate_array(
724 _context: &PolicyValidationContext,
725 _metadata: &CategoryMetadata,
726 _items: &[u8],
727 ) -> Result<(), Self::Error> {
728 Ok(())
729 }
730}
731
732#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
733#[repr(C, packed)]
734pub(super) struct CategoryMetadata {
735 length: le::U32,
736 id: le::U32,
737 is_alias: le::U32,
738}
739
740impl Counted for CategoryMetadata {
741 fn count(&self) -> u32 {
744 self.length.get()
745 }
746}
747
748impl Validate for CategoryMetadata {
749 type Error = anyhow::Error;
750
751 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
753 CategoryId::from_u32(self.id.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
754 Ok(())
755 }
756}
757
758#[derive(Debug)]
759pub(super) struct CategoryIndex {
760 offsets_by_id_minus_one: Box<[U24]>,
770
771 offsets_by_name: HashTable<U24>,
773}
774
775impl CategoryIndex {
776 fn parse_category_at(policy_bytes: &PolicyData, offset: U24) -> Category {
777 Category::parse(PolicyCursor::new_at(policy_bytes, PolicyOffset::from(offset)))
778 .expect("These bytes already successfully parsed")
779 .0
780 }
781
782 pub fn category(&self, policy_bytes: &PolicyData, category_id: CategoryId) -> Category {
784 let offset = self.offsets_by_id_minus_one[(category_id.as_u32() - 1) as usize];
785 Self::parse_category_at(policy_bytes, offset)
786 }
787
788 pub fn categories<'a>(
793 &'a self,
794 policy_bytes: &'a PolicyData,
795 ) -> impl Iterator<Item = Category> + 'a {
796 self.offsets_by_id_minus_one.iter().filter_map(|&offset| match PolicyOffset::from(offset) {
797 0 => None,
798 offset => {
799 let (category, _) =
800 Category::parse(PolicyCursor::new_at(policy_bytes, PolicyOffset::from(offset)))
801 .expect("These bytes already successfully parsed");
802 Some(category)
803 }
804 })
805 }
806
807 pub fn category_by_name(&self, policy_bytes: &PolicyData, name: &str) -> Option<Category> {
809 let name_bytes = name.as_bytes();
810 self.offsets_by_name
811 .find(name_hash(name_bytes), |&other_offset| {
812 name_bytes == Self::parse_category_at(policy_bytes, other_offset).name_bytes()
813 })
814 .map(|&offset| Self::parse_category_at(policy_bytes, offset))
815 }
816}
817
818impl Parse for CategoryIndex {
819 type Error = anyhow::Error;
820
821 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
822 let policy_data = bytes.data();
823 let (metadata, mut tail) = Metadata::parse(bytes)?;
824 let category_count = usize::try_from(metadata.count()).unwrap();
825 let mut offsets_by_id_minus_one = vec![U24::ZERO; category_count];
826 let mut offsets_by_name = HashTable::with_capacity(category_count);
827
828 for _ in 0..category_count {
829 let offset = U24::try_from(tail.offset()).unwrap();
830 let (category, next_tail) = Category::parse(tail)?;
831 let category_id_as_usize = category.id().as_u32() as usize;
832
833 if offsets_by_id_minus_one.len() < category_id_as_usize {
834 offsets_by_id_minus_one.resize(category_id_as_usize, U24::ZERO);
835 }
836 offsets_by_id_minus_one[category_id_as_usize - 1] = offset;
837
838 offsets_by_name
839 .entry(
840 name_hash(category.name_bytes()),
841 |&other_offset| {
842 category.name_bytes()
843 == Self::parse_category_at(&policy_data, other_offset).name_bytes()
844 },
845 |&other_offset| {
846 name_hash(Self::parse_category_at(&policy_data, other_offset).name_bytes())
847 },
848 )
849 .insert(offset);
850
851 tail = next_tail;
852 }
853
854 offsets_by_name.shrink_to_fit(|&other_offset| {
855 name_hash(Self::parse_category_at(&policy_data, other_offset).name_bytes())
856 });
857
858 Ok((
859 Self {
860 offsets_by_id_minus_one: Box::<[U24]>::from(offsets_by_id_minus_one),
861 offsets_by_name,
862 },
863 tail,
864 ))
865 }
866}
867
868impl Validate for CategoryIndex {
869 type Error = anyhow::Error;
870
871 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
873 for offset in &self.offsets_by_id_minus_one {
874 let (category, _) =
875 Category::parse(PolicyCursor::new_at(&context.data, PolicyOffset::from(*offset)))
876 .expect("These bytes already successfully parsed");
877
878 category.validate(context).context("category defaults")?;
879 }
880
881 Ok(())
882 }
883}
884
885#[cfg(test)]
886mod tests {
887 use super::super::{AccessVector, CategoryId, SensitivityId, UserId, parse_policy_by_value};
888
889 use crate::new_policy::{
890 ConstraintNames, ConstraintOperand, ConstraintOperator, ConstraintSubject, ConstraintTerm,
891 };
892
893 #[test]
894 fn mls_levels_for_user_context() {
895 const TEST_POLICY: &[u8] =
896 include_bytes! {"../../testdata/micro_policies/multiple_levels_and_categories_policy"};
897 let policy = parse_policy_by_value(TEST_POLICY.to_vec()).unwrap();
898 let policy = policy.validate().unwrap();
899
900 let user = policy.user(UserId::for_test(1));
901 let mls_range = user.mls_range();
902 let low_level = mls_range.low();
903 let high_level = mls_range.high().as_ref().expect("user 1 has a high mls level");
904
905 assert_eq!(low_level.sensitivity(), SensitivityId::for_test(1));
906 assert_eq!(low_level.category_ids().collect::<Vec<_>>(), vec![CategoryId::for_test(1)]);
907
908 assert_eq!(high_level.sensitivity(), SensitivityId::for_test(2));
909 assert_eq!(
910 high_level.category_ids().collect::<Vec<_>>(),
911 vec![
912 CategoryId::for_test(1),
913 CategoryId::for_test(2),
914 CategoryId::for_test(3),
915 CategoryId::for_test(4),
916 CategoryId::for_test(5),
917 ]
918 );
919 }
920
921 #[test]
922 fn parse_mls_constrain_statement() {
923 let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy");
924 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
925 let policy = policy.validate().expect("validate policy");
926
927 let classes = policy.classes();
928 let class = classes.get_by_name(b"class_mls_constraints").expect("look up class");
929 let constraints = class.constraints();
930 assert_eq!(constraints.len(), 6);
931
932 let expected = [
933 ConstraintTerm::Expression {
934 operand: ConstraintOperand::L1H1,
935 operator: ConstraintOperator::Incomp,
936 },
937 ConstraintTerm::Expression {
938 operand: ConstraintOperand::H1H2,
939 operator: ConstraintOperator::Incomp,
940 },
941 ConstraintTerm::Expression {
942 operand: ConstraintOperand::L1H2,
943 operator: ConstraintOperator::DomBy,
944 },
945 ConstraintTerm::Expression {
946 operand: ConstraintOperand::H1L2,
947 operator: ConstraintOperator::Dom,
948 },
949 ConstraintTerm::Expression {
950 operand: ConstraintOperand::L2H2,
951 operator: ConstraintOperator::Ne,
952 },
953 ConstraintTerm::Expression {
954 operand: ConstraintOperand::L1L2,
955 operator: ConstraintOperator::Eq,
956 },
957 ];
958 for (i, constraint) in constraints.iter().enumerate() {
959 assert_eq!(constraint.access_vector(), AccessVector::from(1), "constraint {}", i);
960 let terms = constraint.constraint_expr();
961 assert_eq!(terms.len(), 1, "constraint {}", i);
962 assert_eq!(terms[0], expected[i], "constraint {}", i);
963 }
964 }
965
966 #[test]
967 fn parse_constrain_statement() {
968 let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy");
969 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
970 let policy = policy.validate().expect("validate policy");
971
972 let classes = policy.classes();
973 let class = classes.get_by_name(b"class_constraint_nested").expect("look up class");
974 let constraints = class.constraints();
975 assert_eq!(constraints.len(), 1);
976 let constraint = &constraints[0];
977 assert_eq!(constraint.access_vector(), AccessVector::from(1));
978 let terms = constraint.constraint_expr();
979 assert_eq!(terms.len(), 8);
980
981 assert_eq!(terms[7], ConstraintTerm::Or);
982 assert_eq!(terms[6], ConstraintTerm::And);
983 assert_eq!(terms[5], ConstraintTerm::Not);
984
985 assert_eq!(
986 terms[4],
987 ConstraintTerm::Expression {
988 operand: ConstraintOperand::Type(ConstraintSubject::Source),
989 operator: ConstraintOperator::Eq,
990 }
991 );
992
993 assert_eq!(
994 terms[3],
995 ConstraintTerm::Expression {
996 operand: ConstraintOperand::User(ConstraintSubject::Source),
997 operator: ConstraintOperator::Eq,
998 }
999 );
1000
1001 assert_eq!(terms[2], ConstraintTerm::And);
1002
1003 assert_eq!(
1004 terms[1],
1005 ConstraintTerm::Expression {
1006 operand: ConstraintOperand::Role(ConstraintSubject::Source),
1007 operator: ConstraintOperator::Eq,
1008 }
1009 );
1010
1011 match &terms[0] {
1012 ConstraintTerm::ExpressionWithNames { operand, operator, names } => {
1013 assert_eq!(operand, &ConstraintOperand::User(ConstraintSubject::Target));
1014 assert_eq!(operator, &ConstraintOperator::Eq);
1015 match &**names {
1016 ConstraintNames::Users(ids, set) => {
1017 assert!(!ids.is_empty());
1018 assert!(set.is_empty());
1019 }
1020 _ => panic!("expected Users"),
1021 }
1022 }
1023 _ => panic!("expected ExpressionWithNames"),
1024 }
1025 }
1026}