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