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 Ok(Self::new(
178 user,
179 role,
180 type_,
181 SecurityLevel::parse(policy_index, low_level)?,
182 high_level.map(|x| SecurityLevel::parse(policy_index, x)).transpose()?,
183 ))
184 }
185
186 pub(super) fn serialize<PS: ParseStrategy>(&self, policy_index: &PolicyIndex<PS>) -> Vec<u8> {
188 let mut levels = self.low_level.serialize(policy_index.parsed_policy());
189 if let Some(high_level) = &self.high_level {
190 levels.push(b'-');
191 levels.extend(high_level.serialize(policy_index.parsed_policy()));
192 }
193 let parts: [&[u8]; 4] = [
194 policy_index.parsed_policy().user(self.user).name_bytes(),
195 policy_index.parsed_policy().role(self.role).name_bytes(),
196 policy_index.parsed_policy().type_(self.type_).name_bytes(),
197 levels.as_slice(),
198 ];
199 parts.join(b":".as_ref())
200 }
201
202 pub(super) fn validate<PS: ParseStrategy>(
205 &self,
206 policy_index: &PolicyIndex<PS>,
207 ) -> Result<(), SecurityContextError> {
208 let user = policy_index.parsed_policy().user(self.user);
209
210 if self.role != policy_index.object_role() && !user.roles().is_set(self.role.0.get() - 1) {
218 return Err(SecurityContextError::InvalidRoleForUser {
219 role: policy_index.parsed_policy().role(self.role).name_bytes().into(),
220 user: user.name_bytes().into(),
221 });
222 }
223
224 let valid_low = user.mls_range().low();
227 let valid_high = user.mls_range().high().as_ref().unwrap_or(valid_low);
228
229 if !(self.low_level.dominates(valid_low) && valid_high.dominates(&self.low_level)) {
231 return Err(SecurityContextError::InvalidLevelForUser {
232 level: self.low_level.serialize(policy_index.parsed_policy()).into(),
233 user: user.name_bytes().into(),
234 });
235 }
236 if let Some(ref high_level) = self.high_level {
237 if !(valid_high.dominates(high_level) && high_level.dominates(valid_low)) {
239 return Err(SecurityContextError::InvalidLevelForUser {
240 level: high_level.serialize(policy_index.parsed_policy()).into(),
241 user: user.name_bytes().into(),
242 });
243 }
244
245 if !(high_level).dominates(&self.low_level) {
248 return Err(SecurityContextError::InvalidSecurityRange {
249 low: self.low_level.serialize(policy_index.parsed_policy()).into(),
250 high: high_level.serialize(policy_index.parsed_policy()).into(),
251 });
252 }
253 }
254 Ok(())
255 }
256}
257
258#[derive(Clone, Debug, Eq, PartialEq)]
261pub struct SecurityLevel {
262 sensitivity: SensitivityId,
263 categories: Vec<CategorySpan>,
264}
265
266impl SecurityLevel {
267 pub(super) fn new(sensitivity: SensitivityId, categories: Vec<CategorySpan>) -> Self {
268 Self { sensitivity, categories }
269 }
270
271 pub(super) fn new_from_mls_level<PS: ParseStrategy>(level: &MlsLevel<PS>) -> SecurityLevel {
274 SecurityLevel::new(
275 level.sensitivity(),
276 level.category_spans().map(|span| span.into()).collect(),
277 )
278 }
279
280 fn parse<PS: ParseStrategy>(
282 policy_index: &PolicyIndex<PS>,
283 level: &str,
284 ) -> Result<Self, SecurityContextError> {
285 if level.is_empty() {
286 return Err(SecurityContextError::InvalidSyntax);
287 }
288
289 let mut items = level.split(":");
291 let sensitivity = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
292 let categories_item = items.next();
293 if items.next() != None {
294 return Err(SecurityContextError::InvalidSyntax);
295 }
296
297 let sensitivity = policy_index
299 .parsed_policy()
300 .sensitivity_by_name(sensitivity)
301 .ok_or_else(|| SecurityContextError::UnknownSensitivity { name: sensitivity.into() })?
302 .id();
303 let mut categories = Vec::new();
304 if let Some(categories_str) = categories_item {
305 for entry in categories_str.split(",") {
306 let category = if let Some((low, high)) = entry.split_once(".") {
307 let low = Self::category_id_by_name(policy_index, low)?;
308 let high = Self::category_id_by_name(policy_index, high)?;
309 if high <= low {
310 return Err(SecurityContextError::InvalidSyntax);
311 }
312 CategorySpan::new(low, high)
313 } else {
314 let id = Self::category_id_by_name(policy_index, entry)?;
315 CategorySpan::new(id, id)
316 };
317 categories.push(category);
318 }
319 }
320 if categories.is_empty() {
321 return Ok(Self { sensitivity, categories });
322 }
323 categories.sort_by(|x, y| (x.low, x.high).cmp(&(y.low, y.high)));
329 let categories = categories.into_iter();
331 let normalized =
332 categories.fold(vec![], |mut normalized: Vec<CategorySpan>, current: CategorySpan| {
333 if let Some(last) = normalized.last_mut() {
334 if current.low <= last.high
335 || (u32::from(current.low.0) - u32::from(last.high.0) == 1)
336 {
337 *last = CategorySpan::new(last.low, current.high)
338 } else {
339 normalized.push(current);
340 }
341 return normalized;
342 }
343 normalized.push(current);
344 normalized
345 });
346
347 Ok(Self { sensitivity, categories: normalized })
348 }
349
350 fn category_id_by_name<PS: ParseStrategy>(
351 policy_index: &PolicyIndex<PS>,
352 name: &str,
353 ) -> Result<CategoryId, SecurityContextError> {
354 Ok(policy_index
355 .parsed_policy()
356 .category_by_name(name)
357 .ok_or_else(|| SecurityContextError::UnknownCategory { name: name.into() })?
358 .id())
359 }
360}
361
362pub trait Level<'a, T: Into<CategorySpan> + Clone, IterT: 'a + Iterator<Item = T>> {
365 fn sensitivity(&self) -> SensitivityId;
367
368 fn category_spans(&'a self) -> CategoryIterator<T, IterT>;
370
371 fn serialize<PS: ParseStrategy>(&'a self, parsed_policy: &ParsedPolicy<PS>) -> Vec<u8> {
374 let sensitivity = parsed_policy.sensitivity(self.sensitivity()).name_bytes();
375 let categories = self
376 .category_spans()
377 .map(|x| x.serialize(parsed_policy))
378 .collect::<Vec<Vec<u8>>>()
379 .join(b",".as_ref());
380
381 if categories.is_empty() {
382 sensitivity.to_vec()
383 } else {
384 [sensitivity, categories.as_slice()].join(b":".as_ref())
385 }
386 }
387
388 fn compare<U: Into<CategorySpan> + Clone, IterU: 'a + Iterator<Item = U>>(
390 &'a self,
391 other: &'a (impl Level<'a, U, IterU> + 'a),
392 ) -> Option<Ordering> {
393 let s_order = self.sensitivity().cmp(&other.sensitivity());
394 let c_order = self.category_spans().compare(&other.category_spans())?;
395 if s_order == c_order {
396 return Some(s_order);
397 } else if c_order == Ordering::Equal {
398 return Some(s_order);
399 } else if s_order == Ordering::Equal {
400 return Some(c_order);
401 }
402 None
405 }
406
407 fn dominates<U: Into<CategorySpan> + Clone, IterU: 'a + Iterator<Item = U>>(
409 &'a self,
410 other: &'a (impl Level<'a, U, IterU> + 'a),
411 ) -> bool {
412 match self.compare(other) {
413 Some(Ordering::Equal) | Some(Ordering::Greater) => true,
414 _ => false,
415 }
416 }
417}
418
419impl<'a> Level<'a, &'a CategorySpan, Iter<'a, CategorySpan>> for SecurityLevel {
420 fn sensitivity(&self) -> SensitivityId {
421 self.sensitivity
422 }
423 fn category_spans(&'a self) -> CategoryIterator<&'a CategorySpan, Iter<'a, CategorySpan>> {
424 CategoryIterator::<&'a CategorySpan, Iter<'a, CategorySpan>>::new(self.categories.iter())
425 }
426}
427
428pub struct CategoryIterator<T: Into<CategorySpan>, IterT: Iterator<Item = T>>(RefCell<IterT>);
430
431impl<T: Into<CategorySpan> + Clone, IterT: Iterator<Item = T>> CategoryIterator<T, IterT> {
432 pub fn new(iter: IterT) -> Self {
433 Self(RefCell::new(iter))
434 }
435
436 fn next(&self) -> Option<CategorySpan> {
437 self.0.borrow_mut().next().map(|x| x.into())
438 }
439
440 fn compare<'a, U: Into<CategorySpan> + Clone, IterU: 'a + Iterator<Item = U>>(
441 &'a self,
442 other: &'a CategoryIterator<U, IterU>,
443 ) -> Option<Ordering> {
444 let mut self_contains_other = true;
445 let mut other_contains_self = true;
446
447 let mut self_now = self.next();
448 let mut other_now = other.next();
449
450 while let (Some(self_span), Some(other_span)) = (self_now.clone(), other_now.clone()) {
451 if self_span.high < other_span.low {
452 other_contains_self = false;
453 } else if other_span.high < self_span.low {
454 self_contains_other = false;
455 } else {
456 match self_span.compare(&other_span) {
457 None => {
458 return None;
459 }
460 Some(Ordering::Less) => {
461 self_contains_other = false;
462 }
463 Some(Ordering::Greater) => {
464 other_contains_self = false;
465 }
466 Some(Ordering::Equal) => {}
467 }
468 if !self_contains_other && !other_contains_self {
469 return None;
470 }
471 }
472 if self_span.high <= other_span.high {
473 self_now = self.next();
474 }
475 if other_span.high <= self_span.high {
476 other_now = other.next();
477 }
478 }
479 if self_now.is_some() {
480 other_contains_self = false;
481 } else if other_now.is_some() {
482 self_contains_other = false;
483 }
484 match (self_contains_other, other_contains_self) {
485 (true, true) => Some(Ordering::Equal),
486 (true, false) => Some(Ordering::Greater),
487 (false, true) => Some(Ordering::Less),
488 (false, false) => None,
489 }
490 }
491}
492
493impl<T: Into<CategorySpan>, IterT: Iterator<Item = T>> Iterator for CategoryIterator<T, IterT> {
494 type Item = CategorySpan;
495
496 fn next(&mut self) -> Option<Self::Item> {
497 self.0.borrow_mut().next().map(|x| x.into())
498 }
499}
500
501#[derive(Clone, Debug, Eq, PartialEq)]
505pub struct CategorySpan {
506 low: CategoryId,
507 high: CategoryId,
508}
509
510impl CategorySpan {
511 pub(super) fn new(low: CategoryId, high: CategoryId) -> Self {
512 Self { low, high }
513 }
514
515 fn serialize<PS: ParseStrategy>(&self, parsed_policy: &ParsedPolicy<PS>) -> Vec<u8> {
517 match self.low == self.high {
518 true => parsed_policy.category(self.low).name_bytes().into(),
519 false => [
520 parsed_policy.category(self.low).name_bytes(),
521 parsed_policy.category(self.high).name_bytes(),
522 ]
523 .join(b".".as_ref()),
524 }
525 }
526
527 fn compare(&self, other: &Self) -> Option<Ordering> {
529 match (self.low.cmp(&other.low), self.high.cmp(&other.high)) {
530 (Ordering::Equal, Ordering::Equal) => Some(Ordering::Equal),
531 (Ordering::Equal, Ordering::Greater)
532 | (Ordering::Less, Ordering::Equal)
533 | (Ordering::Less, Ordering::Greater) => Some(Ordering::Greater),
534 (Ordering::Equal, Ordering::Less)
535 | (Ordering::Greater, Ordering::Equal)
536 | (Ordering::Greater, Ordering::Less) => Some(Ordering::Less),
537 _ => None,
538 }
539 }
540}
541
542impl From<ExtensibleBitmapSpan> for CategorySpan {
543 fn from(value: ExtensibleBitmapSpan) -> CategorySpan {
544 CategorySpan {
545 low: CategoryId(NonZeroU32::new(value.low + 1).unwrap()),
546 high: CategoryId(NonZeroU32::new(value.high + 1).unwrap()),
547 }
548 }
549}
550
551impl From<&CategorySpan> for CategorySpan {
552 fn from(value: &CategorySpan) -> Self {
553 value.clone()
554 }
555}
556
557#[derive(Clone, Debug, Error, Eq, PartialEq)]
559pub enum SecurityContextError {
560 #[error("security context syntax is invalid")]
561 InvalidSyntax,
562 #[error("sensitivity {name:?} not defined by policy")]
563 UnknownSensitivity { name: BString },
564 #[error("category {name:?} not defined by policy")]
565 UnknownCategory { name: BString },
566 #[error("user {name:?} not defined by policy")]
567 UnknownUser { name: BString },
568 #[error("role {name:?} not defined by policy")]
569 UnknownRole { name: BString },
570 #[error("type {name:?} not defined by policy")]
571 UnknownType { name: BString },
572 #[error("role {role:?} not valid for {user:?}")]
573 InvalidRoleForUser { role: BString, user: BString },
574 #[error("security level {level:?} not valid for {user:?}")]
575 InvalidLevelForUser { level: BString, user: BString },
576 #[error("high security level {high:?} lower than low level {low:?}")]
577 InvalidSecurityRange { low: BString, high: BString },
578}
579
580#[cfg(test)]
581mod tests {
582 use super::super::{parse_policy_by_reference, ByRef, Policy};
583 use super::*;
584
585 use std::num::NonZeroU32;
586
587 type TestPolicy = Policy<ByRef<&'static [u8]>>;
588 fn test_policy() -> TestPolicy {
589 const TEST_POLICY: &[u8] =
590 include_bytes!("../../testdata/micro_policies/security_context_tests_policy.pp");
591 parse_policy_by_reference(TEST_POLICY).unwrap().validate().unwrap()
592 }
593
594 #[derive(Debug, Eq, PartialEq)]
596 struct CategoryItem<'a> {
597 low: &'a str,
598 high: &'a str,
599 }
600
601 fn user_name(policy: &TestPolicy, id: UserId) -> &str {
602 std::str::from_utf8(policy.0.parsed_policy().user(id).name_bytes()).unwrap()
603 }
604
605 fn role_name(policy: &TestPolicy, id: RoleId) -> &str {
606 std::str::from_utf8(policy.0.parsed_policy().role(id).name_bytes()).unwrap()
607 }
608
609 fn type_name(policy: &TestPolicy, id: TypeId) -> &str {
610 std::str::from_utf8(policy.0.parsed_policy().type_(id).name_bytes()).unwrap()
611 }
612
613 fn sensitivity_name(policy: &TestPolicy, id: SensitivityId) -> &str {
614 std::str::from_utf8(policy.0.parsed_policy().sensitivity(id).name_bytes()).unwrap()
615 }
616
617 fn category_name(policy: &TestPolicy, id: CategoryId) -> &str {
618 std::str::from_utf8(policy.0.parsed_policy().category(id).name_bytes()).unwrap()
619 }
620
621 fn category_span<'a>(policy: &'a TestPolicy, category: &CategorySpan) -> CategoryItem<'a> {
622 CategoryItem {
623 low: category_name(policy, category.low),
624 high: category_name(policy, category.high),
625 }
626 }
627
628 fn category_spans<'a>(
629 policy: &'a TestPolicy,
630 categories: &Vec<CategorySpan>,
631 ) -> Vec<CategoryItem<'a>> {
632 categories.iter().map(|x| category_span(policy, x)).collect()
633 }
634
635 fn cat(low: u32, high: u32) -> CategorySpan {
637 CategorySpan {
638 low: CategoryId(NonZeroU32::new(low).expect("category ids are nonzero")),
639 high: CategoryId(NonZeroU32::new(high).expect("category ids are nonzero")),
640 }
641 }
642
643 fn compare(lhs: &[CategorySpan], rhs: &[CategorySpan]) -> Option<Ordering> {
645 CategoryIterator::new(lhs.iter()).compare(&CategoryIterator::new(rhs.iter()))
646 }
647
648 #[test]
649 fn category_compare() {
650 let cat_1 = cat(1, 1);
651 let cat_2 = cat(1, 3);
652 let cat_3 = cat(2, 3);
653 assert_eq!(cat_1.compare(&cat_1), Some(Ordering::Equal));
654 assert_eq!(cat_1.compare(&cat_2), Some(Ordering::Less));
655 assert_eq!(cat_1.compare(&cat_3), None);
656 assert_eq!(cat_2.compare(&cat_1), Some(Ordering::Greater));
657 assert_eq!(cat_2.compare(&cat_3), Some(Ordering::Greater));
658 }
659
660 #[test]
661 fn categories_compare_empty_iter() {
662 let cats_0 = &[];
663 let cats_1 = &[cat(1, 1)];
664 assert_eq!(compare(cats_0, cats_0), Some(Ordering::Equal));
665 assert_eq!(compare(cats_0, cats_1), Some(Ordering::Less));
666 assert_eq!(compare(cats_1, cats_0), Some(Ordering::Greater));
667 }
668
669 #[test]
670 fn categories_compare_same_length() {
671 let cats_1 = &[cat(1, 1), cat(3, 3)];
672 let cats_2 = &[cat(1, 1), cat(4, 4)];
673 let cats_3 = &[cat(1, 2), cat(4, 4)];
674 let cats_4 = &[cat(1, 2), cat(4, 5)];
675
676 assert_eq!(compare(cats_1, cats_1), Some(Ordering::Equal));
677 assert_eq!(compare(cats_1, cats_2), None);
678 assert_eq!(compare(cats_1, cats_3), None);
679 assert_eq!(compare(cats_1, cats_4), None);
680
681 assert_eq!(compare(cats_2, cats_1), None);
682 assert_eq!(compare(cats_2, cats_2), Some(Ordering::Equal));
683 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Less));
684 assert_eq!(compare(cats_2, cats_4), Some(Ordering::Less));
685
686 assert_eq!(compare(cats_3, cats_1), None);
687 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Greater));
688 assert_eq!(compare(cats_3, cats_3), Some(Ordering::Equal));
689 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
690
691 assert_eq!(compare(cats_4, cats_1), None);
692 assert_eq!(compare(cats_4, cats_2), Some(Ordering::Greater));
693 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
694 assert_eq!(compare(cats_4, cats_4), Some(Ordering::Equal));
695 }
696
697 #[test]
698 fn categories_compare_different_lengths() {
699 let cats_1 = &[cat(1, 1)];
700 let cats_2 = &[cat(1, 4)];
701 let cats_3 = &[cat(1, 1), cat(4, 4)];
702 let cats_4 = &[cat(1, 2), cat(4, 5), cat(7, 7)];
703
704 assert_eq!(compare(cats_1, cats_3), Some(Ordering::Less));
705 assert_eq!(compare(cats_1, cats_4), Some(Ordering::Less));
706
707 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Greater));
708 assert_eq!(compare(cats_2, cats_4), None);
709
710 assert_eq!(compare(cats_3, cats_1), Some(Ordering::Greater));
711 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Less));
712 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
713
714 assert_eq!(compare(cats_4, cats_1), Some(Ordering::Greater));
715 assert_eq!(compare(cats_4, cats_2), None);
716 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
717 }
718
719 #[test]
720 fn categories_compare_with_gaps() {
723 let cats_1 = &[cat(1, 2), cat(4, 5)];
724 let cats_2 = &[cat(4, 5)];
725 let cats_3 = &[cat(2, 5), cat(10, 11)];
726 let cats_4 = &[cat(2, 5), cat(7, 8), cat(10, 11)];
727
728 assert_eq!(compare(cats_1, cats_2), Some(Ordering::Greater));
729 assert_eq!(compare(cats_1, cats_3), None);
730 assert_eq!(compare(cats_1, cats_4), None);
731
732 assert_eq!(compare(cats_2, cats_1), Some(Ordering::Less));
733 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Less));
734 assert_eq!(compare(cats_2, cats_4), Some(Ordering::Less));
735
736 assert_eq!(compare(cats_3, cats_1), None);
737 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Greater));
738 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
739
740 assert_eq!(compare(cats_4, cats_1), None);
741 assert_eq!(compare(cats_4, cats_2), Some(Ordering::Greater));
742 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
743 }
744
745 #[test]
746 fn parse_security_context_single_sensitivity() {
747 let policy = test_policy();
748 let security_context = policy
749 .parse_security_context(b"user0:object_r:type0:s0".into())
750 .expect("creating security context should succeed");
751 assert_eq!(user_name(&policy, security_context.user), "user0");
752 assert_eq!(role_name(&policy, security_context.role), "object_r");
753 assert_eq!(type_name(&policy, security_context.type_), "type0");
754 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s0");
755 assert_eq!(security_context.low_level.categories, Vec::new());
756 assert_eq!(security_context.high_level, None);
757 }
758
759 #[test]
760 fn parse_security_context_with_sensitivity_range() {
761 let policy = test_policy();
762 let security_context = policy
763 .parse_security_context(b"user0:object_r:type0:s0-s1".into())
764 .expect("creating security context should succeed");
765 assert_eq!(user_name(&policy, security_context.user), "user0");
766 assert_eq!(role_name(&policy, security_context.role), "object_r");
767 assert_eq!(type_name(&policy, security_context.type_), "type0");
768 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s0");
769 assert_eq!(security_context.low_level.categories, Vec::new());
770 let high_level = security_context.high_level.as_ref().unwrap();
771 assert_eq!(sensitivity_name(&policy, high_level.sensitivity), "s1");
772 assert_eq!(high_level.categories, Vec::new());
773 }
774
775 #[test]
776 fn parse_security_context_with_single_sensitivity_and_categories_interval() {
777 let policy = test_policy();
778 let security_context = policy
779 .parse_security_context(b"user0:object_r:type0:s1:c0.c4".into())
780 .expect("creating security context should succeed");
781 assert_eq!(user_name(&policy, security_context.user), "user0");
782 assert_eq!(role_name(&policy, security_context.role), "object_r");
783 assert_eq!(type_name(&policy, security_context.type_), "type0");
784 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s1");
785 assert_eq!(
786 category_spans(&policy, &security_context.low_level.categories),
787 [CategoryItem { low: "c0", high: "c4" }]
788 );
789 assert_eq!(security_context.high_level, None);
790 }
791
792 #[test]
793 fn parse_security_context_and_normalize_categories() {
794 let policy = &test_policy();
795 let normalize = {
796 |security_context: &str| -> String {
797 String::from_utf8(
798 policy.serialize_security_context(
799 &policy
800 .parse_security_context(security_context.into())
801 .expect("creating security context should succeed"),
802 ),
803 )
804 .unwrap()
805 }
806 };
807 assert_eq!(normalize("user0:object_r:type0:s1:c0.c1,c1"), "user0:object_r:type0:s1:c0.c1");
809 assert_eq!(
810 normalize("user0:object_r:type0:s1:c0.c2,c1.c2"),
811 "user0:object_r:type0:s1:c0.c2"
812 );
813 assert_eq!(
814 normalize("user0:object_r:type0:s1:c0.c2,c1.c3"),
815 "user0:object_r:type0:s1:c0.c3"
816 );
817 assert_eq!(normalize("user0:object_r:type0:s1:c0.c1,c2"), "user0:object_r:type0:s1:c0.c2");
819 assert_eq!(
821 normalize("user0:object_r:type0:s1:c2.c3,c0"),
822 "user0:object_r:type0:s1:c0,c2.c3"
823 );
824 }
825
826 #[test]
827 fn parse_security_context_with_sensitivity_range_and_category_interval() {
828 let policy = test_policy();
829 let security_context = policy
830 .parse_security_context(b"user0:object_r:type0:s0-s1:c0.c4".into())
831 .expect("creating security context should succeed");
832 assert_eq!(user_name(&policy, security_context.user), "user0");
833 assert_eq!(role_name(&policy, security_context.role), "object_r");
834 assert_eq!(type_name(&policy, security_context.type_), "type0");
835 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s0");
836 assert_eq!(security_context.low_level.categories, Vec::new());
837 let high_level = security_context.high_level.as_ref().unwrap();
838 assert_eq!(sensitivity_name(&policy, high_level.sensitivity), "s1");
839 assert_eq!(
840 category_spans(&policy, &high_level.categories),
841 [CategoryItem { low: "c0", high: "c4" }]
842 );
843 }
844
845 #[test]
846 fn parse_security_context_with_sensitivity_range_with_categories() {
847 let policy = test_policy();
848 let security_context = policy
849 .parse_security_context(b"user0:object_r:type0:s0:c0-s1:c0.c4".into())
850 .expect("creating security context should succeed");
851 assert_eq!(user_name(&policy, security_context.user), "user0");
852 assert_eq!(role_name(&policy, security_context.role), "object_r");
853 assert_eq!(type_name(&policy, security_context.type_), "type0");
854 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s0");
855 assert_eq!(
856 category_spans(&policy, &security_context.low_level.categories),
857 [CategoryItem { low: "c0", high: "c0" }]
858 );
859
860 let high_level = security_context.high_level.as_ref().unwrap();
861 assert_eq!(sensitivity_name(&policy, high_level.sensitivity), "s1");
862 assert_eq!(
863 category_spans(&policy, &high_level.categories),
864 [CategoryItem { low: "c0", high: "c4" }]
865 );
866 }
867
868 #[test]
869 fn parse_security_context_with_single_sensitivity_and_category_list() {
870 let policy = test_policy();
871 let security_context = policy
872 .parse_security_context(b"user0:object_r:type0:s1:c0,c4".into())
873 .expect("creating security context should succeed");
874 assert_eq!(user_name(&policy, security_context.user), "user0");
875 assert_eq!(role_name(&policy, security_context.role), "object_r");
876 assert_eq!(type_name(&policy, security_context.type_), "type0");
877 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s1");
878 assert_eq!(
879 category_spans(&policy, &security_context.low_level.categories),
880 [CategoryItem { low: "c0", high: "c0" }, CategoryItem { low: "c4", high: "c4" }]
881 );
882 assert_eq!(security_context.high_level, None);
883 }
884
885 #[test]
886 fn parse_security_context_with_single_sensitivity_and_category_list_and_range() {
887 let policy = test_policy();
888 let security_context = policy
889 .parse_security_context(b"user0:object_r:type0:s1:c0,c3.c4".into())
890 .expect("creating security context should succeed");
891 assert_eq!(user_name(&policy, security_context.user), "user0");
892 assert_eq!(role_name(&policy, security_context.role), "object_r");
893 assert_eq!(type_name(&policy, security_context.type_), "type0");
894 assert_eq!(sensitivity_name(&policy, security_context.low_level.sensitivity), "s1");
895 assert_eq!(
896 category_spans(&policy, &security_context.low_level.categories),
897 [CategoryItem { low: "c0", high: "c0" }, CategoryItem { low: "c3", high: "c4" }]
898 );
899 assert_eq!(security_context.high_level, None);
900 }
901
902 #[test]
903 fn parse_invalid_syntax() {
904 let policy = test_policy();
905 for invalid_label in [
906 "user0",
907 "user0:object_r",
908 "user0:object_r:type0",
909 "user0:object_r:type0:s0-",
910 "user0:object_r:type0:s0:s0:s0",
911 "user0:object_r:type0:s0:c0.c0", "user0:object_r:type0:s0:c1.c0", ] {
914 assert_eq!(
915 policy.parse_security_context(invalid_label.as_bytes().into()),
916 Err(SecurityContextError::InvalidSyntax),
917 "validating {:?}",
918 invalid_label
919 );
920 }
921 }
922
923 #[test]
924 fn parse_invalid_sensitivity() {
925 let policy = test_policy();
926 for invalid_label in ["user0:object_r:type0:s_invalid", "user0:object_r:type0:s0-s_invalid"]
927 {
928 assert_eq!(
929 policy.parse_security_context(invalid_label.as_bytes().into()),
930 Err(SecurityContextError::UnknownSensitivity { name: "s_invalid".into() }),
931 "validating {:?}",
932 invalid_label
933 );
934 }
935 }
936
937 #[test]
938 fn parse_invalid_category() {
939 let policy = test_policy();
940 for invalid_label in
941 ["user0:object_r:type0:s1:c_invalid", "user0:object_r:type0:s1:c0.c_invalid"]
942 {
943 assert_eq!(
944 policy.parse_security_context(invalid_label.as_bytes().into()),
945 Err(SecurityContextError::UnknownCategory { name: "c_invalid".into() }),
946 "validating {:?}",
947 invalid_label
948 );
949 }
950 }
951
952 #[test]
953 fn invalid_security_context_fields() {
954 let policy = test_policy();
955
956 let context = policy
959 .parse_security_context(b"user0:object_r:type0:s1:c0,c3.c4-s1".into())
960 .expect("successfully parsed");
961 assert_eq!(
962 policy.validate_security_context(&context),
963 Err(SecurityContextError::InvalidSecurityRange {
964 low: "s1:c0,c3.c4".into(),
965 high: "s1".into()
966 })
967 );
968
969 let context = policy
972 .parse_security_context(b"user0:object_r:type0:s1:c0-s1:c1".into())
973 .expect("successfully parsed");
974 assert_eq!(
975 policy.validate_security_context(&context),
976 Err(SecurityContextError::InvalidSecurityRange {
977 low: "s1:c0".into(),
978 high: "s1:c1".into()
979 })
980 );
981
982 let context = policy
985 .parse_security_context(b"user0:object_r:type0:s1:c0-s0:c0.c1".into())
986 .expect("successfully parsed");
987 assert_eq!(
988 policy.validate_security_context(&context),
989 Err(SecurityContextError::InvalidSecurityRange {
990 low: "s1:c0".into(),
991 high: "s0:c0.c1".into()
992 })
993 );
994
995 let context = policy
999 .parse_security_context(b"user1:subject_r:type0:s1-s1:c3".into())
1000 .expect("successfully parsed");
1001 assert_eq!(
1002 policy.validate_security_context(&context),
1003 Err(SecurityContextError::InvalidLevelForUser {
1004 level: "s1:c3".into(),
1005 user: "user1".into(),
1006 })
1007 );
1008
1009 let context = policy
1013 .parse_security_context(b"user1:object_r:type0:s0".into())
1014 .expect("successfully parsed");
1015 assert_eq!(
1016 policy.validate_security_context(&context),
1017 Err(SecurityContextError::InvalidLevelForUser {
1018 level: "s0".into(),
1019 user: "user1".into(),
1020 })
1021 );
1022
1023 let context = policy
1025 .parse_security_context(b"user1:object_r:type0:s0".into())
1026 .expect("successfully parsed");
1027 assert!(policy.validate_security_context(&context).is_err());
1028
1029 let context = policy
1031 .parse_security_context(b"user0:subject_r:type0:s0".into())
1032 .expect("successfully parsed");
1033 assert!(policy.validate_security_context(&context).is_err());
1034
1035 let context = policy
1038 .parse_security_context(b"user1:object_r:type0:s1".into())
1039 .expect("successfully parsed");
1040 assert!(policy.validate_security_context(&context).is_ok());
1041 }
1042
1043 #[test]
1044 fn format_security_contexts() {
1045 let policy = test_policy();
1046 for label in [
1047 "user0:object_r:type0:s0",
1048 "user0:object_r:type0:s0-s1",
1049 "user0:object_r:type0:s1:c0.c4",
1050 "user0:object_r:type0:s0-s1:c0.c4",
1051 "user0:object_r:type0:s1:c0,c3",
1052 "user0:object_r:type0:s0-s1:c0,c2,c4",
1053 "user0:object_r:type0:s1:c0,c3.c4-s1:c0,c2.c4",
1054 ] {
1055 let security_context =
1056 policy.parse_security_context(label.as_bytes().into()).expect("should succeed");
1057 assert_eq!(policy.serialize_security_context(&security_context), label.as_bytes());
1058 }
1059 }
1060}