1use crate::policy::arrays::Context;
6use crate::policy::extensible_bitmap::ExtensibleBitmapSpan;
7use crate::policy::index::PolicyIndex;
8use crate::policy::symbols::MlsLevel;
9use crate::policy::{
10 CategoryId, ParseStrategy, ParsedPolicy, RoleId, SensitivityId, TypeId, UserId,
11};
12
13use crate::NullessByteStr;
14use bstr::BString;
15use std::cell::RefCell;
16use std::cmp::Ordering;
17use std::num::NonZeroU32;
18use std::slice::Iter;
19use thiserror::Error;
20
21#[derive(Clone, Debug, Eq, PartialEq)]
28pub struct SecurityContext {
29 user: UserId,
31 role: RoleId,
33 type_: TypeId,
35 low_level: SecurityLevel,
37 high_level: Option<SecurityLevel>,
39}
40
41impl SecurityContext {
42 pub(super) fn new(
46 user: UserId,
47 role: RoleId,
48 type_: TypeId,
49 low_level: SecurityLevel,
50 high_level: Option<SecurityLevel>,
51 ) -> Self {
52 Self { user, role, type_, low_level, high_level }
53 }
54
55 pub(super) fn new_from_policy_context<PS: ParseStrategy>(
57 context: &Context<PS>,
58 ) -> SecurityContext {
59 let low_level = SecurityLevel::new_from_mls_level(context.low_level());
60 let high_level =
61 context.high_level().as_ref().map(|x| SecurityLevel::new_from_mls_level(x));
62
63 SecurityContext::new(
64 context.user_id(),
65 context.role_id(),
66 context.type_id(),
67 low_level,
68 high_level,
69 )
70 }
71
72 pub fn user(&self) -> UserId {
74 self.user
75 }
76
77 pub fn role(&self) -> RoleId {
79 self.role
80 }
81
82 pub fn type_(&self) -> TypeId {
84 self.type_
85 }
86
87 pub fn low_level(&self) -> &SecurityLevel {
89 &self.low_level
90 }
91
92 pub fn high_level(&self) -> Option<&SecurityLevel> {
94 self.high_level.as_ref()
95 }
96
97 pub fn effective_high_level(&self) -> &SecurityLevel {
100 self.high_level().map_or(&self.low_level, |x| x)
101 }
102
103 pub(super) fn parse<PS: ParseStrategy>(
132 policy_index: &PolicyIndex<PS>,
133 security_context: NullessByteStr<'_>,
134 ) -> Result<Self, SecurityContextError> {
135 let as_str = std::str::from_utf8(security_context.as_bytes())
136 .map_err(|_| SecurityContextError::InvalidSyntax)?;
137
138 let mut items = as_str.splitn(4, ":");
140 let user = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
141 let role = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
142 let type_ = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
143
144 let mut levels = items.next().ok_or(SecurityContextError::InvalidSyntax)?.split("-");
146 let low_level = levels.next().ok_or(SecurityContextError::InvalidSyntax)?;
147 if low_level.is_empty() {
148 return Err(SecurityContextError::InvalidSyntax);
149 }
150 let high_level = levels.next();
151 if let Some(high_level) = high_level {
152 if high_level.is_empty() {
153 return Err(SecurityContextError::InvalidSyntax);
154 }
155 }
156 if levels.next() != None {
157 return Err(SecurityContextError::InvalidSyntax);
158 }
159
160 let user = policy_index
162 .parsed_policy()
163 .user_by_name(user)
164 .ok_or_else(|| SecurityContextError::UnknownUser { name: user.into() })?
165 .id();
166 let role = policy_index
167 .parsed_policy()
168 .role_by_name(role)
169 .ok_or_else(|| SecurityContextError::UnknownRole { name: role.into() })?
170 .id();
171 let type_ = policy_index
172 .parsed_policy()
173 .type_by_name(type_)
174 .ok_or_else(|| SecurityContextError::UnknownType { name: type_.into() })?
175 .id();
176
177 let low_level = SecurityLevel::parse(policy_index, low_level)?;
178 let high_level = high_level.map(|x| SecurityLevel::parse(policy_index, x)).transpose()?;
179
180 Ok(Self::new(user, role, type_, low_level, high_level))
181 }
182
183 pub(super) fn serialize<PS: ParseStrategy>(&self, policy_index: &PolicyIndex<PS>) -> Vec<u8> {
185 let mut levels = self.low_level.serialize(policy_index.parsed_policy());
186 if let Some(high_level) = &self.high_level {
187 levels.push(b'-');
188 levels.extend(high_level.serialize(policy_index.parsed_policy()));
189 }
190 let parts: [&[u8]; 4] = [
191 policy_index.parsed_policy().user(self.user).name_bytes(),
192 policy_index.parsed_policy().role(self.role).name_bytes(),
193 policy_index.parsed_policy().type_(self.type_).name_bytes(),
194 levels.as_slice(),
195 ];
196 parts.join(b":".as_ref())
197 }
198
199 pub(super) fn validate<PS: ParseStrategy>(
202 &self,
203 policy_index: &PolicyIndex<PS>,
204 ) -> Result<(), SecurityContextError> {
205 let user = policy_index.parsed_policy().user(self.user);
206
207 if self.role != policy_index.object_role() {
210 if !user.roles().is_set(self.role.0.get() - 1) {
214 return Err(SecurityContextError::InvalidRoleForUser {
215 role: policy_index.parsed_policy().role(self.role).name_bytes().into(),
216 user: user.name_bytes().into(),
217 });
218 }
219
220 let role = policy_index.parsed_policy().role(self.role);
222 if !role.types().is_set(self.type_.0.get() - 1) {
224 return Err(SecurityContextError::InvalidTypeForRole {
225 type_: policy_index.parsed_policy().type_(self.type_).name_bytes().into(),
226 role: role.name_bytes().into(),
227 });
228 }
229 }
230
231 let valid_low = user.mls_range().low();
234 let valid_high = user.mls_range().high().as_ref().unwrap_or(valid_low);
235
236 if !(self.low_level.dominates(valid_low) && valid_high.dominates(&self.low_level)) {
238 return Err(SecurityContextError::InvalidLevelForUser {
239 level: self.low_level.serialize(policy_index.parsed_policy()).into(),
240 user: user.name_bytes().into(),
241 });
242 }
243 if let Some(ref high_level) = self.high_level {
244 if !(valid_high.dominates(high_level) && high_level.dominates(valid_low)) {
246 return Err(SecurityContextError::InvalidLevelForUser {
247 level: high_level.serialize(policy_index.parsed_policy()).into(),
248 user: user.name_bytes().into(),
249 });
250 }
251
252 if !(high_level).dominates(&self.low_level) {
255 return Err(SecurityContextError::InvalidSecurityRange {
256 low: self.low_level.serialize(policy_index.parsed_policy()).into(),
257 high: high_level.serialize(policy_index.parsed_policy()).into(),
258 });
259 }
260 }
261 Ok(())
262 }
263}
264
265#[derive(Clone, Debug, Eq, PartialEq)]
268pub struct SecurityLevel {
269 sensitivity: SensitivityId,
270 categories: Vec<CategorySpan>,
271}
272
273impl SecurityLevel {
274 pub(super) fn new(sensitivity: SensitivityId, categories: Vec<CategorySpan>) -> Self {
275 Self { sensitivity, categories }
276 }
277
278 pub(super) fn new_from_mls_level<PS: ParseStrategy>(level: &MlsLevel<PS>) -> SecurityLevel {
281 SecurityLevel::new(
282 level.sensitivity(),
283 level.category_spans().map(|span| span.into()).collect(),
284 )
285 }
286
287 fn parse<PS: ParseStrategy>(
289 policy_index: &PolicyIndex<PS>,
290 level: &str,
291 ) -> Result<Self, SecurityContextError> {
292 if level.is_empty() {
293 return Err(SecurityContextError::InvalidSyntax);
294 }
295
296 let mut items = level.split(":");
298 let sensitivity = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
299 let categories_item = items.next();
300 if items.next() != None {
301 return Err(SecurityContextError::InvalidSyntax);
302 }
303
304 let sensitivity = policy_index
306 .parsed_policy()
307 .sensitivity_by_name(sensitivity)
308 .ok_or_else(|| SecurityContextError::UnknownSensitivity { name: sensitivity.into() })?
309 .id();
310 let mut categories = Vec::new();
311 if let Some(categories_str) = categories_item {
312 for entry in categories_str.split(",") {
313 let category = if let Some((low, high)) = entry.split_once(".") {
314 let low = Self::category_id_by_name(policy_index, low)?;
315 let high = Self::category_id_by_name(policy_index, high)?;
316 if high <= low {
317 return Err(SecurityContextError::InvalidSyntax);
318 }
319 CategorySpan::new(low, high)
320 } else {
321 let id = Self::category_id_by_name(policy_index, entry)?;
322 CategorySpan::new(id, id)
323 };
324 categories.push(category);
325 }
326 }
327 if categories.is_empty() {
328 return Ok(Self { sensitivity, categories });
329 }
330 categories.sort_by(|x, y| (x.low, x.high).cmp(&(y.low, y.high)));
336 let categories = categories.into_iter();
338 let normalized =
339 categories.fold(vec![], |mut normalized: Vec<CategorySpan>, current: CategorySpan| {
340 if let Some(last) = normalized.last_mut() {
341 if current.low <= last.high
342 || (u32::from(current.low.0) - u32::from(last.high.0) == 1)
343 {
344 *last = CategorySpan::new(last.low, current.high)
345 } else {
346 normalized.push(current);
347 }
348 return normalized;
349 }
350 normalized.push(current);
351 normalized
352 });
353
354 Ok(Self { sensitivity, categories: normalized })
355 }
356
357 fn category_id_by_name<PS: ParseStrategy>(
358 policy_index: &PolicyIndex<PS>,
359 name: &str,
360 ) -> Result<CategoryId, SecurityContextError> {
361 Ok(policy_index
362 .parsed_policy()
363 .category_by_name(name)
364 .ok_or_else(|| SecurityContextError::UnknownCategory { name: name.into() })?
365 .id())
366 }
367}
368
369pub trait Level<'a, T: Into<CategorySpan> + Clone, IterT: 'a + Iterator<Item = T>> {
372 fn sensitivity(&self) -> SensitivityId;
374
375 fn category_spans(&'a self) -> CategoryIterator<T, IterT>;
377
378 fn serialize<PS: ParseStrategy>(&'a self, parsed_policy: &ParsedPolicy<PS>) -> Vec<u8> {
381 let sensitivity = parsed_policy.sensitivity(self.sensitivity()).name_bytes();
382 let categories = self
383 .category_spans()
384 .map(|x| x.serialize(parsed_policy))
385 .collect::<Vec<Vec<u8>>>()
386 .join(b",".as_ref());
387
388 if categories.is_empty() {
389 sensitivity.to_vec()
390 } else {
391 [sensitivity, categories.as_slice()].join(b":".as_ref())
392 }
393 }
394
395 fn compare<U: Into<CategorySpan> + Clone, IterU: 'a + Iterator<Item = U>>(
397 &'a self,
398 other: &'a (impl Level<'a, U, IterU> + 'a),
399 ) -> Option<Ordering> {
400 let s_order = self.sensitivity().cmp(&other.sensitivity());
401 let c_order = self.category_spans().compare(&other.category_spans())?;
402 if s_order == c_order {
403 return Some(s_order);
404 } else if c_order == Ordering::Equal {
405 return Some(s_order);
406 } else if s_order == Ordering::Equal {
407 return Some(c_order);
408 }
409 None
412 }
413
414 fn dominates<U: Into<CategorySpan> + Clone, IterU: 'a + Iterator<Item = U>>(
416 &'a self,
417 other: &'a (impl Level<'a, U, IterU> + 'a),
418 ) -> bool {
419 match self.compare(other) {
420 Some(Ordering::Equal) | Some(Ordering::Greater) => true,
421 _ => false,
422 }
423 }
424}
425
426impl<'a> Level<'a, &'a CategorySpan, Iter<'a, CategorySpan>> for SecurityLevel {
427 fn sensitivity(&self) -> SensitivityId {
428 self.sensitivity
429 }
430 fn category_spans(&'a self) -> CategoryIterator<&'a CategorySpan, Iter<'a, CategorySpan>> {
431 CategoryIterator::<&'a CategorySpan, Iter<'a, CategorySpan>>::new(self.categories.iter())
432 }
433}
434
435pub struct CategoryIterator<T: Into<CategorySpan>, IterT: Iterator<Item = T>>(RefCell<IterT>);
437
438impl<T: Into<CategorySpan> + Clone, IterT: Iterator<Item = T>> CategoryIterator<T, IterT> {
439 pub fn new(iter: IterT) -> Self {
440 Self(RefCell::new(iter))
441 }
442
443 fn next(&self) -> Option<CategorySpan> {
444 self.0.borrow_mut().next().map(|x| x.into())
445 }
446
447 fn compare<'a, U: Into<CategorySpan> + Clone, IterU: 'a + Iterator<Item = U>>(
448 &'a self,
449 other: &'a CategoryIterator<U, IterU>,
450 ) -> Option<Ordering> {
451 let mut self_contains_other = true;
452 let mut other_contains_self = true;
453
454 let mut self_now = self.next();
455 let mut other_now = other.next();
456
457 while let (Some(self_span), Some(other_span)) = (self_now.clone(), other_now.clone()) {
458 if self_span.high < other_span.low {
459 other_contains_self = false;
460 } else if other_span.high < self_span.low {
461 self_contains_other = false;
462 } else {
463 match self_span.compare(&other_span) {
464 None => {
465 return None;
466 }
467 Some(Ordering::Less) => {
468 self_contains_other = false;
469 }
470 Some(Ordering::Greater) => {
471 other_contains_self = false;
472 }
473 Some(Ordering::Equal) => {}
474 }
475 if !self_contains_other && !other_contains_self {
476 return None;
477 }
478 }
479 if self_span.high <= other_span.high {
480 self_now = self.next();
481 }
482 if other_span.high <= self_span.high {
483 other_now = other.next();
484 }
485 }
486 if self_now.is_some() {
487 other_contains_self = false;
488 } else if other_now.is_some() {
489 self_contains_other = false;
490 }
491 match (self_contains_other, other_contains_self) {
492 (true, true) => Some(Ordering::Equal),
493 (true, false) => Some(Ordering::Greater),
494 (false, true) => Some(Ordering::Less),
495 (false, false) => None,
496 }
497 }
498}
499
500impl<T: Into<CategorySpan>, IterT: Iterator<Item = T>> Iterator for CategoryIterator<T, IterT> {
501 type Item = CategorySpan;
502
503 fn next(&mut self) -> Option<Self::Item> {
504 self.0.borrow_mut().next().map(|x| x.into())
505 }
506}
507
508#[derive(Clone, Debug, Eq, PartialEq)]
512pub struct CategorySpan {
513 low: CategoryId,
514 high: CategoryId,
515}
516
517impl CategorySpan {
518 pub(super) fn new(low: CategoryId, high: CategoryId) -> Self {
519 Self { low, high }
520 }
521
522 fn serialize<PS: ParseStrategy>(&self, parsed_policy: &ParsedPolicy<PS>) -> Vec<u8> {
524 match self.low == self.high {
525 true => parsed_policy.category(self.low).name_bytes().into(),
526 false => [
527 parsed_policy.category(self.low).name_bytes(),
528 parsed_policy.category(self.high).name_bytes(),
529 ]
530 .join(b".".as_ref()),
531 }
532 }
533
534 fn compare(&self, other: &Self) -> Option<Ordering> {
536 match (self.low.cmp(&other.low), self.high.cmp(&other.high)) {
537 (Ordering::Equal, Ordering::Equal) => Some(Ordering::Equal),
538 (Ordering::Equal, Ordering::Greater)
539 | (Ordering::Less, Ordering::Equal)
540 | (Ordering::Less, Ordering::Greater) => Some(Ordering::Greater),
541 (Ordering::Equal, Ordering::Less)
542 | (Ordering::Greater, Ordering::Equal)
543 | (Ordering::Greater, Ordering::Less) => Some(Ordering::Less),
544 _ => None,
545 }
546 }
547}
548
549impl From<ExtensibleBitmapSpan> for CategorySpan {
550 fn from(value: ExtensibleBitmapSpan) -> CategorySpan {
551 CategorySpan {
552 low: CategoryId(NonZeroU32::new(value.low + 1).unwrap()),
553 high: CategoryId(NonZeroU32::new(value.high + 1).unwrap()),
554 }
555 }
556}
557
558impl From<&CategorySpan> for CategorySpan {
559 fn from(value: &CategorySpan) -> Self {
560 value.clone()
561 }
562}
563
564#[derive(Clone, Debug, Error, Eq, PartialEq)]
566pub enum SecurityContextError {
567 #[error("security context syntax is invalid")]
568 InvalidSyntax,
569 #[error("sensitivity {name:?} not defined by policy")]
570 UnknownSensitivity { name: BString },
571 #[error("category {name:?} not defined by policy")]
572 UnknownCategory { name: BString },
573 #[error("user {name:?} not defined by policy")]
574 UnknownUser { name: BString },
575 #[error("role {name:?} not defined by policy")]
576 UnknownRole { name: BString },
577 #[error("type {name:?} not defined by policy")]
578 UnknownType { name: BString },
579 #[error("role {role:?} not valid for {user:?}")]
580 InvalidRoleForUser { role: BString, user: BString },
581 #[error("type {type_:?} not valid for {role:?}")]
582 InvalidTypeForRole { role: BString, type_: BString },
583 #[error("security level {level:?} not valid for {user:?}")]
584 InvalidLevelForUser { level: BString, user: BString },
585 #[error("high security level {high:?} lower than low level {low:?}")]
586 InvalidSecurityRange { low: BString, high: BString },
587}
588
589#[cfg(test)]
590mod tests {
591 use super::super::{parse_policy_by_reference, ByRef, Policy};
592 use super::*;
593
594 use std::num::NonZeroU32;
595
596 type TestPolicy = Policy<ByRef<&'static [u8]>>;
597 fn test_policy() -> TestPolicy {
598 const TEST_POLICY: &[u8] =
599 include_bytes!("../../testdata/micro_policies/security_context_tests_policy.pp");
600 parse_policy_by_reference(TEST_POLICY).unwrap().validate().unwrap()
601 }
602
603 #[derive(Debug, Eq, PartialEq)]
605 struct CategoryItem<'a> {
606 low: &'a str,
607 high: &'a str,
608 }
609
610 fn user_name(policy: &TestPolicy, id: UserId) -> &str {
611 std::str::from_utf8(policy.0.parsed_policy().user(id).name_bytes()).unwrap()
612 }
613
614 fn role_name(policy: &TestPolicy, id: RoleId) -> &str {
615 std::str::from_utf8(policy.0.parsed_policy().role(id).name_bytes()).unwrap()
616 }
617
618 fn type_name(policy: &TestPolicy, id: TypeId) -> &str {
619 std::str::from_utf8(policy.0.parsed_policy().type_(id).name_bytes()).unwrap()
620 }
621
622 fn sensitivity_name(policy: &TestPolicy, id: SensitivityId) -> &str {
623 std::str::from_utf8(policy.0.parsed_policy().sensitivity(id).name_bytes()).unwrap()
624 }
625
626 fn category_name(policy: &TestPolicy, id: CategoryId) -> &str {
627 std::str::from_utf8(policy.0.parsed_policy().category(id).name_bytes()).unwrap()
628 }
629
630 fn category_span<'a>(policy: &'a TestPolicy, category: &CategorySpan) -> CategoryItem<'a> {
631 CategoryItem {
632 low: category_name(policy, category.low),
633 high: category_name(policy, category.high),
634 }
635 }
636
637 fn category_spans<'a>(
638 policy: &'a TestPolicy,
639 categories: &Vec<CategorySpan>,
640 ) -> Vec<CategoryItem<'a>> {
641 categories.iter().map(|x| category_span(policy, x)).collect()
642 }
643
644 fn cat(low: u32, high: u32) -> CategorySpan {
646 CategorySpan {
647 low: CategoryId(NonZeroU32::new(low).expect("category ids are nonzero")),
648 high: CategoryId(NonZeroU32::new(high).expect("category ids are nonzero")),
649 }
650 }
651
652 fn compare(lhs: &[CategorySpan], rhs: &[CategorySpan]) -> Option<Ordering> {
654 CategoryIterator::new(lhs.iter()).compare(&CategoryIterator::new(rhs.iter()))
655 }
656
657 #[test]
658 fn category_compare() {
659 let cat_1 = cat(1, 1);
660 let cat_2 = cat(1, 3);
661 let cat_3 = cat(2, 3);
662 assert_eq!(cat_1.compare(&cat_1), Some(Ordering::Equal));
663 assert_eq!(cat_1.compare(&cat_2), Some(Ordering::Less));
664 assert_eq!(cat_1.compare(&cat_3), None);
665 assert_eq!(cat_2.compare(&cat_1), Some(Ordering::Greater));
666 assert_eq!(cat_2.compare(&cat_3), Some(Ordering::Greater));
667 }
668
669 #[test]
670 fn categories_compare_empty_iter() {
671 let cats_0 = &[];
672 let cats_1 = &[cat(1, 1)];
673 assert_eq!(compare(cats_0, cats_0), Some(Ordering::Equal));
674 assert_eq!(compare(cats_0, cats_1), Some(Ordering::Less));
675 assert_eq!(compare(cats_1, cats_0), Some(Ordering::Greater));
676 }
677
678 #[test]
679 fn categories_compare_same_length() {
680 let cats_1 = &[cat(1, 1), cat(3, 3)];
681 let cats_2 = &[cat(1, 1), cat(4, 4)];
682 let cats_3 = &[cat(1, 2), cat(4, 4)];
683 let cats_4 = &[cat(1, 2), cat(4, 5)];
684
685 assert_eq!(compare(cats_1, cats_1), Some(Ordering::Equal));
686 assert_eq!(compare(cats_1, cats_2), None);
687 assert_eq!(compare(cats_1, cats_3), None);
688 assert_eq!(compare(cats_1, cats_4), None);
689
690 assert_eq!(compare(cats_2, cats_1), None);
691 assert_eq!(compare(cats_2, cats_2), Some(Ordering::Equal));
692 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Less));
693 assert_eq!(compare(cats_2, cats_4), Some(Ordering::Less));
694
695 assert_eq!(compare(cats_3, cats_1), None);
696 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Greater));
697 assert_eq!(compare(cats_3, cats_3), Some(Ordering::Equal));
698 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
699
700 assert_eq!(compare(cats_4, cats_1), None);
701 assert_eq!(compare(cats_4, cats_2), Some(Ordering::Greater));
702 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
703 assert_eq!(compare(cats_4, cats_4), Some(Ordering::Equal));
704 }
705
706 #[test]
707 fn categories_compare_different_lengths() {
708 let cats_1 = &[cat(1, 1)];
709 let cats_2 = &[cat(1, 4)];
710 let cats_3 = &[cat(1, 1), cat(4, 4)];
711 let cats_4 = &[cat(1, 2), cat(4, 5), cat(7, 7)];
712
713 assert_eq!(compare(cats_1, cats_3), Some(Ordering::Less));
714 assert_eq!(compare(cats_1, cats_4), Some(Ordering::Less));
715
716 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Greater));
717 assert_eq!(compare(cats_2, cats_4), None);
718
719 assert_eq!(compare(cats_3, cats_1), Some(Ordering::Greater));
720 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Less));
721 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
722
723 assert_eq!(compare(cats_4, cats_1), Some(Ordering::Greater));
724 assert_eq!(compare(cats_4, cats_2), None);
725 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
726 }
727
728 #[test]
729 fn categories_compare_with_gaps() {
732 let cats_1 = &[cat(1, 2), cat(4, 5)];
733 let cats_2 = &[cat(4, 5)];
734 let cats_3 = &[cat(2, 5), cat(10, 11)];
735 let cats_4 = &[cat(2, 5), cat(7, 8), cat(10, 11)];
736
737 assert_eq!(compare(cats_1, cats_2), Some(Ordering::Greater));
738 assert_eq!(compare(cats_1, cats_3), None);
739 assert_eq!(compare(cats_1, cats_4), None);
740
741 assert_eq!(compare(cats_2, cats_1), Some(Ordering::Less));
742 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Less));
743 assert_eq!(compare(cats_2, cats_4), Some(Ordering::Less));
744
745 assert_eq!(compare(cats_3, cats_1), None);
746 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Greater));
747 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
748
749 assert_eq!(compare(cats_4, cats_1), None);
750 assert_eq!(compare(cats_4, cats_2), Some(Ordering::Greater));
751 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
752 }
753
754 #[test]
755 fn parse_security_context_single_sensitivity() {
756 let policy = test_policy();
757 let security_context = policy
758 .parse_security_context(b"user0:object_r:type0:s0".into())
759 .expect("creating security context should succeed");
760 assert_eq!(user_name(&policy, security_context.user), "user0");
761 assert_eq!(role_name(&policy, security_context.role), "object_r");
762 assert_eq!(type_name(&policy, security_context.type_), "type0");
763 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s0");
764 assert_eq!(security_context.low_level.categories, Vec::new());
765 assert_eq!(security_context.high_level, None);
766 }
767
768 #[test]
769 fn parse_security_context_with_sensitivity_range() {
770 let policy = test_policy();
771 let security_context = policy
772 .parse_security_context(b"user0:object_r:type0:s0-s1".into())
773 .expect("creating security context should succeed");
774 assert_eq!(user_name(&policy, security_context.user), "user0");
775 assert_eq!(role_name(&policy, security_context.role), "object_r");
776 assert_eq!(type_name(&policy, security_context.type_), "type0");
777 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s0");
778 assert_eq!(security_context.low_level.categories, Vec::new());
779 let high_level = security_context.high_level.as_ref().unwrap();
780 assert_eq!(sensitivity_name(&policy, high_level.sensitivity), "s1");
781 assert_eq!(high_level.categories, Vec::new());
782 }
783
784 #[test]
785 fn parse_security_context_with_single_sensitivity_and_categories_interval() {
786 let policy = test_policy();
787 let security_context = policy
788 .parse_security_context(b"user0:object_r:type0:s1:c0.c4".into())
789 .expect("creating security context should succeed");
790 assert_eq!(user_name(&policy, security_context.user), "user0");
791 assert_eq!(role_name(&policy, security_context.role), "object_r");
792 assert_eq!(type_name(&policy, security_context.type_), "type0");
793 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s1");
794 assert_eq!(
795 category_spans(&policy, &security_context.low_level.categories),
796 [CategoryItem { low: "c0", high: "c4" }]
797 );
798 assert_eq!(security_context.high_level, None);
799 }
800
801 #[test]
802 fn parse_security_context_and_normalize_categories() {
803 let policy = &test_policy();
804 let normalize = {
805 |security_context: &str| -> String {
806 String::from_utf8(
807 policy.serialize_security_context(
808 &policy
809 .parse_security_context(security_context.into())
810 .expect("creating security context should succeed"),
811 ),
812 )
813 .unwrap()
814 }
815 };
816 assert_eq!(normalize("user0:object_r:type0:s1:c0.c1,c1"), "user0:object_r:type0:s1:c0.c1");
818 assert_eq!(
819 normalize("user0:object_r:type0:s1:c0.c2,c1.c2"),
820 "user0:object_r:type0:s1:c0.c2"
821 );
822 assert_eq!(
823 normalize("user0:object_r:type0:s1:c0.c2,c1.c3"),
824 "user0:object_r:type0:s1:c0.c3"
825 );
826 assert_eq!(normalize("user0:object_r:type0:s1:c0.c1,c2"), "user0:object_r:type0:s1:c0.c2");
828 assert_eq!(
830 normalize("user0:object_r:type0:s1:c2.c3,c0"),
831 "user0:object_r:type0:s1:c0,c2.c3"
832 );
833 }
834
835 #[test]
836 fn parse_security_context_with_sensitivity_range_and_category_interval() {
837 let policy = test_policy();
838 let security_context = policy
839 .parse_security_context(b"user0:object_r:type0:s0-s1:c0.c4".into())
840 .expect("creating security context should succeed");
841 assert_eq!(user_name(&policy, security_context.user), "user0");
842 assert_eq!(role_name(&policy, security_context.role), "object_r");
843 assert_eq!(type_name(&policy, security_context.type_), "type0");
844 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s0");
845 assert_eq!(security_context.low_level.categories, Vec::new());
846 let high_level = security_context.high_level.as_ref().unwrap();
847 assert_eq!(sensitivity_name(&policy, high_level.sensitivity), "s1");
848 assert_eq!(
849 category_spans(&policy, &high_level.categories),
850 [CategoryItem { low: "c0", high: "c4" }]
851 );
852 }
853
854 #[test]
855 fn parse_security_context_with_sensitivity_range_with_categories() {
856 let policy = test_policy();
857 let security_context = policy
858 .parse_security_context(b"user0:object_r:type0:s0:c0-s1:c0.c4".into())
859 .expect("creating security context should succeed");
860 assert_eq!(user_name(&policy, security_context.user), "user0");
861 assert_eq!(role_name(&policy, security_context.role), "object_r");
862 assert_eq!(type_name(&policy, security_context.type_), "type0");
863 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s0");
864 assert_eq!(
865 category_spans(&policy, &security_context.low_level.categories),
866 [CategoryItem { low: "c0", high: "c0" }]
867 );
868
869 let high_level = security_context.high_level.as_ref().unwrap();
870 assert_eq!(sensitivity_name(&policy, high_level.sensitivity), "s1");
871 assert_eq!(
872 category_spans(&policy, &high_level.categories),
873 [CategoryItem { low: "c0", high: "c4" }]
874 );
875 }
876
877 #[test]
878 fn parse_security_context_with_single_sensitivity_and_category_list() {
879 let policy = test_policy();
880 let security_context = policy
881 .parse_security_context(b"user0:object_r:type0:s1:c0,c4".into())
882 .expect("creating security context should succeed");
883 assert_eq!(user_name(&policy, security_context.user), "user0");
884 assert_eq!(role_name(&policy, security_context.role), "object_r");
885 assert_eq!(type_name(&policy, security_context.type_), "type0");
886 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s1");
887 assert_eq!(
888 category_spans(&policy, &security_context.low_level.categories),
889 [CategoryItem { low: "c0", high: "c0" }, CategoryItem { low: "c4", high: "c4" }]
890 );
891 assert_eq!(security_context.high_level, None);
892 }
893
894 #[test]
895 fn parse_security_context_with_single_sensitivity_and_category_list_and_range() {
896 let policy = test_policy();
897 let security_context = policy
898 .parse_security_context(b"user0:object_r:type0:s1:c0,c3.c4".into())
899 .expect("creating security context should succeed");
900 assert_eq!(user_name(&policy, security_context.user), "user0");
901 assert_eq!(role_name(&policy, security_context.role), "object_r");
902 assert_eq!(type_name(&policy, security_context.type_), "type0");
903 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s1");
904 assert_eq!(
905 category_spans(&policy, &security_context.low_level.categories),
906 [CategoryItem { low: "c0", high: "c0" }, CategoryItem { low: "c3", high: "c4" }]
907 );
908 assert_eq!(security_context.high_level, None);
909 }
910
911 #[test]
912 fn parse_invalid_syntax() {
913 let policy = test_policy();
914 for invalid_label in [
915 "user0",
916 "user0:object_r",
917 "user0:object_r:type0",
918 "user0:object_r:type0:s0-",
919 "user0:object_r:type0:s0:s0:s0",
920 "user0:object_r:type0:s0:c0.c0", "user0:object_r:type0:s0:c1.c0", ] {
923 assert_eq!(
924 policy.parse_security_context(invalid_label.as_bytes().into()),
925 Err(SecurityContextError::InvalidSyntax),
926 "validating {:?}",
927 invalid_label
928 );
929 }
930 }
931
932 #[test]
933 fn parse_invalid_sensitivity() {
934 let policy = test_policy();
935 for invalid_label in ["user0:object_r:type0:s_invalid", "user0:object_r:type0:s0-s_invalid"]
936 {
937 assert_eq!(
938 policy.parse_security_context(invalid_label.as_bytes().into()),
939 Err(SecurityContextError::UnknownSensitivity { name: "s_invalid".into() }),
940 "validating {:?}",
941 invalid_label
942 );
943 }
944 }
945
946 #[test]
947 fn parse_invalid_category() {
948 let policy = test_policy();
949 for invalid_label in
950 ["user0:object_r:type0:s1:c_invalid", "user0:object_r:type0:s1:c0.c_invalid"]
951 {
952 assert_eq!(
953 policy.parse_security_context(invalid_label.as_bytes().into()),
954 Err(SecurityContextError::UnknownCategory { name: "c_invalid".into() }),
955 "validating {:?}",
956 invalid_label
957 );
958 }
959 }
960
961 #[test]
962 fn invalid_security_context_fields() {
963 let policy = test_policy();
964
965 let context = policy
968 .parse_security_context(b"user0:object_r:type0:s1:c0,c3.c4-s1".into())
969 .expect("successfully parsed");
970 assert_eq!(
971 policy.validate_security_context(&context),
972 Err(SecurityContextError::InvalidSecurityRange {
973 low: "s1:c0,c3.c4".into(),
974 high: "s1".into()
975 })
976 );
977
978 let context = policy
981 .parse_security_context(b"user0:object_r:type0:s1:c0-s1:c1".into())
982 .expect("successfully parsed");
983 assert_eq!(
984 policy.validate_security_context(&context),
985 Err(SecurityContextError::InvalidSecurityRange {
986 low: "s1:c0".into(),
987 high: "s1:c1".into()
988 })
989 );
990
991 let context = policy
994 .parse_security_context(b"user0:object_r:type0:s1:c0-s0:c0.c1".into())
995 .expect("successfully parsed");
996 assert_eq!(
997 policy.validate_security_context(&context),
998 Err(SecurityContextError::InvalidSecurityRange {
999 low: "s1:c0".into(),
1000 high: "s0:c0.c1".into()
1001 })
1002 );
1003
1004 let context = policy
1008 .parse_security_context(b"user1:subject_r:type0:s1-s1:c3".into())
1009 .expect("successfully parsed");
1010 assert_eq!(
1011 policy.validate_security_context(&context),
1012 Err(SecurityContextError::InvalidLevelForUser {
1013 level: "s1:c3".into(),
1014 user: "user1".into(),
1015 })
1016 );
1017
1018 let context = policy
1022 .parse_security_context(b"user1:object_r:type0:s0".into())
1023 .expect("successfully parsed");
1024 assert_eq!(
1025 policy.validate_security_context(&context),
1026 Err(SecurityContextError::InvalidLevelForUser {
1027 level: "s0".into(),
1028 user: "user1".into(),
1029 })
1030 );
1031
1032 let context = policy
1034 .parse_security_context(b"user1:object_r:type0:s0".into())
1035 .expect("successfully parsed");
1036 assert!(policy.validate_security_context(&context).is_err());
1037
1038 let context = policy
1040 .parse_security_context(b"user0:subject_r:type0:s0".into())
1041 .expect("successfully parsed");
1042 assert!(policy.validate_security_context(&context).is_err());
1043
1044 let context = policy
1046 .parse_security_context(b"user1:subject_r:non_subject_t:s1".into())
1047 .expect("successfully parsed");
1048 assert!(policy.validate_security_context(&context).is_err());
1049
1050 let context = policy
1053 .parse_security_context(b"user1:object_r:type0:s1".into())
1054 .expect("successfully parsed");
1055 assert!(policy.validate_security_context(&context).is_ok());
1056 }
1057
1058 #[test]
1059 fn format_security_contexts() {
1060 let policy = test_policy();
1061 for label in [
1062 "user0:object_r:type0:s0",
1063 "user0:object_r:type0:s0-s1",
1064 "user0:object_r:type0:s1:c0.c4",
1065 "user0:object_r:type0:s0-s1:c0.c4",
1066 "user0:object_r:type0:s1:c0,c3",
1067 "user0:object_r:type0:s0-s1:c0,c2,c4",
1068 "user0:object_r:type0:s1:c0,c3.c4-s1:c0,c2.c4",
1069 ] {
1070 let security_context =
1071 policy.parse_security_context(label.as_bytes().into()).expect("should succeed");
1072 assert_eq!(policy.serialize_security_context(&security_context), label.as_bytes());
1073 }
1074 }
1075}