1use super::index::PolicyIndex;
6use super::new::{CategorySetBuilder, Context, IdSpan, MlsLevel, MlsRange};
7use super::parser::PolicyCursor;
8use super::{CategoryId, Parse, PolicyValidationContext, RoleId, TypeId, UserId, Validate};
9use crate::NullessByteStr;
10use crate::new_policy::NewPolicy;
11use crate::new_policy::traits::{HasName, HasPolicyId};
12
13use bstr::BString;
14
15use thiserror::Error;
16
17#[derive(Clone, Debug, Eq, PartialEq)]
24pub struct SecurityContext {
25 inner: Context,
26}
27
28impl SecurityContext {
29 pub(super) fn new(
33 user: UserId,
34 role: RoleId,
35 type_: TypeId,
36 low_level: MlsLevel,
37 high_level: Option<MlsLevel>,
38 ) -> Self {
39 let inner = Context::new(user, role, type_, MlsRange::new(low_level, high_level));
40 Self { inner }
41 }
42
43 pub(super) fn new_from_policy_context(context: &super::arrays::Context) -> SecurityContext {
44 let low = context.low_level().clone();
45 let high = context.high_level().clone();
46 let mls_range = MlsRange::new(low, high);
47 let inner =
48 Context::new(context.user_id(), context.role_id(), context.type_id(), mls_range);
49 SecurityContext { inner }
50 }
51
52 pub fn user(&self) -> UserId {
54 self.inner.user_id()
55 }
56
57 pub fn role(&self) -> RoleId {
59 self.inner.role_id()
60 }
61
62 pub fn type_(&self) -> TypeId {
64 self.inner.type_id()
65 }
66
67 pub fn low_level(&self) -> &MlsLevel {
69 self.inner.low_level()
70 }
71
72 pub fn high_level(&self) -> Option<&MlsLevel> {
74 self.inner.high_level().as_ref()
75 }
76
77 pub fn effective_high_level(&self) -> &MlsLevel {
80 self.high_level().unwrap_or_else(|| self.low_level())
81 }
82
83 pub(super) fn from_string(
112 policy_index: &PolicyIndex,
113 security_context: NullessByteStr<'_>,
114 ) -> Result<Self, SecurityContextError> {
115 let as_str = std::str::from_utf8(security_context.as_bytes())
116 .map_err(|_| SecurityContextError::InvalidSyntax)?;
117
118 let mut items = as_str.splitn(4, ":");
120 let user = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
121 let role = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
122 let type_ = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
123
124 let mut levels = items.next().ok_or(SecurityContextError::InvalidSyntax)?.split("-");
126 let low_level = levels.next().ok_or(SecurityContextError::InvalidSyntax)?;
127 if low_level.is_empty() {
128 return Err(SecurityContextError::InvalidSyntax);
129 }
130 let high_level = levels.next();
131 if let Some(high_level) = high_level {
132 if high_level.is_empty() {
133 return Err(SecurityContextError::InvalidSyntax);
134 }
135 }
136 if levels.next() != None {
137 return Err(SecurityContextError::InvalidSyntax);
138 }
139
140 let user = policy_index
142 .users()
143 .get_by_name(user.as_bytes())
144 .ok_or_else(|| SecurityContextError::UnknownUser { name: user.into() })?
145 .id();
146 let role = policy_index
147 .roles()
148 .get_by_name(role.as_bytes())
149 .ok_or_else(|| SecurityContextError::UnknownRole { name: role.into() })?
150 .id();
151 let type_ = policy_index
152 .types()
153 .get_by_name(type_.as_bytes())
154 .ok_or_else(|| SecurityContextError::UnknownType { name: type_.into() })?
155 .id();
156
157 let low_level = MlsLevel::from_string(policy_index, low_level)?;
158 let high_level = high_level.map(|x| MlsLevel::from_string(policy_index, x)).transpose()?;
159
160 Ok(Self::new(user, role, type_, low_level, high_level))
161 }
162
163 pub(super) fn to_string(&self, policy_index: &PolicyIndex) -> Vec<u8> {
165 let mut levels = self.low_level().to_string(policy_index);
166 if let Some(high_level) = self.high_level() {
167 levels.push(b'-');
168 levels.extend(high_level.to_string(policy_index));
169 }
170 let type_ = policy_index.types().get_by_id(self.type_()).unwrap();
171 let parts: [&[u8]; 4] = [
172 policy_index.users().get_by_id(self.user()).unwrap().name(),
173 policy_index.roles().get_by_id(self.role()).unwrap().name(),
174 type_.name(),
175 levels.as_slice(),
176 ];
177 parts.join(b":".as_ref())
178 }
179
180 pub(super) fn validate(&self, policy_index: &PolicyIndex) -> Result<(), SecurityContextError> {
183 let user = policy_index.users().get_by_id(self.user()).unwrap();
184
185 if self.role() != policy_index.object_role() {
188 if !user.roles().contains(self.role()) {
190 return Err(SecurityContextError::InvalidRoleForUser {
191 role: policy_index.roles().get_by_id(self.role()).unwrap().name().into(),
192 user: user.name().into(),
193 });
194 }
195
196 let role = policy_index.roles().get_by_id(self.role()).unwrap();
198 if !role.types().contains(self.type_()) {
199 return Err(SecurityContextError::InvalidTypeForRole {
200 type_: policy_index.types().get_by_id(self.type_()).unwrap().name().into(),
201 role: role.name().into(),
202 });
203 }
204 }
205
206 let valid_low = user.mls_range().low();
209 let valid_high = user.mls_range().high().as_ref().unwrap_or(valid_low);
210
211 if !(self.low_level().dominates(valid_low) && valid_high.dominates(self.low_level())) {
213 return Err(SecurityContextError::InvalidLevelForUser {
214 level: self.low_level().to_string(policy_index).into(),
215 user: user.name().into(),
216 });
217 }
218 if let Some(high_level) = self.high_level() {
219 if !(valid_high.dominates(high_level) && high_level.dominates(valid_low)) {
221 return Err(SecurityContextError::InvalidLevelForUser {
222 level: high_level.to_string(policy_index).into(),
223 user: user.name().into(),
224 });
225 }
226
227 if !high_level.dominates(self.low_level()) {
230 return Err(SecurityContextError::InvalidSecurityRange {
231 low: self.low_level().to_string(policy_index).into(),
232 high: high_level.to_string(policy_index).into(),
233 });
234 }
235 }
236 Ok(())
237 }
238}
239
240impl MlsLevel {
241 pub(super) fn from_string(
243 policy_index: &PolicyIndex,
244 level: &str,
245 ) -> Result<Self, SecurityContextError> {
246 if level.is_empty() {
247 return Err(SecurityContextError::InvalidSyntax);
248 }
249
250 let mut items = level.split(":");
252 let sensitivity = items.next().ok_or(SecurityContextError::InvalidSyntax)?;
253 let categories_item = items.next();
254 if items.next() != None {
255 return Err(SecurityContextError::InvalidSyntax);
256 }
257
258 let sensitivity = policy_index
260 .sensitivities()
261 .get_by_name(sensitivity.as_bytes())
262 .ok_or_else(|| SecurityContextError::UnknownSensitivity { name: sensitivity.into() })?
263 .id();
264
265 let mut categories = CategorySetBuilder::new();
266 if let Some(categories_str) = categories_item {
267 for entry in categories_str.split(",") {
268 if let Some((low_str, high_str)) = entry.split_once(".") {
269 let low = Self::category_id_by_name(policy_index, low_str)?;
270 let high = Self::category_id_by_name(policy_index, high_str)?;
271 if high <= low {
272 return Err(SecurityContextError::InvalidSyntax);
273 }
274 categories.insert_range(low, high);
275 } else {
276 let id = Self::category_id_by_name(policy_index, entry)?;
277 categories.insert(id);
278 };
279 }
280 }
281
282 Ok(Self::new(sensitivity, categories.build()))
283 }
284
285 fn category_id_by_name(
286 policy_index: &PolicyIndex,
287 name: &str,
288 ) -> Result<CategoryId, SecurityContextError> {
289 Ok(policy_index
290 .categories()
291 .get_by_name(name.as_bytes())
292 .ok_or_else(|| SecurityContextError::UnknownCategory { name: name.into() })?
293 .id())
294 }
295
296 pub fn category_spans(&self) -> impl Iterator<Item = CategorySpan> + '_ {
297 self.categories().spans()
298 }
299
300 pub fn to_string(&self, policy: &NewPolicy) -> Vec<u8> {
301 let sensitivity = policy.sensitivities().get_by_id(self.sensitivity()).unwrap().name();
302 let categories = self
303 .category_spans()
304 .map(|x| x.to_string(policy))
305 .collect::<Vec<Vec<u8>>>()
306 .join(b",".as_ref());
307
308 if categories.is_empty() {
309 sensitivity.to_vec()
310 } else {
311 [sensitivity, categories.as_slice()].join(b":".as_ref())
312 }
313 }
314}
315
316pub type CategorySpan = IdSpan<CategoryId>;
320
321impl IdSpan<CategoryId> {
322 fn to_string(&self, policy: &NewPolicy) -> Vec<u8> {
324 match self.low() == self.high() {
325 true => policy.categories().get_by_id(self.low()).unwrap().name().into(),
326 false => [
327 policy.categories().get_by_id(self.low()).unwrap().name(),
328 policy.categories().get_by_id(self.high()).unwrap().name(),
329 ]
330 .join(b".".as_ref()),
331 }
332 }
333}
334
335impl Parse for MlsLevel {
337 type Error = anyhow::Error;
338
339 fn parse<'a>(cursor: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
340 let offset = cursor.offset() as usize;
341 let slice = &cursor.data().as_ref()[offset..];
342 let mut new_cursor = crate::new_policy::parser::PolicyCursor::new(slice);
343 let level = <Self as crate::new_policy::traits::Parse>::parse(&mut new_cursor)
344 .map_err(|e| anyhow::anyhow!("Parse error: {:?}", e))?;
345 let bytes_parsed = new_cursor.offset();
346 let new_offset = cursor.offset() + bytes_parsed as u32;
347 Ok((level, PolicyCursor::new_at(cursor.data(), new_offset)))
348 }
349}
350
351impl Validate for MlsLevel {
353 type Error = anyhow::Error;
354
355 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
356 crate::new_policy::traits::Validate::validate(self, &context.new_policy).map_err(Into::into)
357 }
358}
359
360impl Parse for MlsRange {
362 type Error = anyhow::Error;
363
364 fn parse<'a>(cursor: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
365 let offset = cursor.offset() as usize;
366 let slice = &cursor.data().as_ref()[offset..];
367 let mut new_cursor = crate::new_policy::parser::PolicyCursor::new(slice);
368 let range = <Self as crate::new_policy::traits::Parse>::parse(&mut new_cursor)
369 .map_err(|e| anyhow::anyhow!("Parse error: {:?}", e))?;
370 let bytes_parsed = new_cursor.offset();
371 let new_offset = cursor.offset() + bytes_parsed as u32;
372 Ok((range, PolicyCursor::new_at(cursor.data(), new_offset)))
373 }
374}
375
376impl Validate for MlsRange {
378 type Error = anyhow::Error;
379
380 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
381 crate::new_policy::traits::Validate::validate(self, &context.new_policy).map_err(Into::into)
382 }
383}
384
385#[derive(Clone, Debug, Error, Eq, PartialEq)]
387pub enum SecurityContextError {
388 #[error("security context syntax is invalid")]
389 InvalidSyntax,
390 #[error("sensitivity {name:?} not defined by policy")]
391 UnknownSensitivity { name: BString },
392 #[error("category {name:?} not defined by policy")]
393 UnknownCategory { name: BString },
394 #[error("user {name:?} not defined by policy")]
395 UnknownUser { name: BString },
396 #[error("role {name:?} not defined by policy")]
397 UnknownRole { name: BString },
398 #[error("type {name:?} not defined by policy")]
399 UnknownType { name: BString },
400 #[error("role {role:?} not valid for {user:?}")]
401 InvalidRoleForUser { role: BString, user: BString },
402 #[error("type {type_:?} not valid for {role:?}")]
403 InvalidTypeForRole { role: BString, type_: BString },
404 #[error("security level {level:?} not valid for {user:?}")]
405 InvalidLevelForUser { level: BString, user: BString },
406 #[error("high security level {high:?} lower than low level {low:?}")]
407 InvalidSecurityRange { low: BString, high: BString },
408}
409
410#[cfg(test)]
411mod tests {
412 use super::super::new::CategorySet;
413 use super::super::{Policy, PolicyId, SensitivityId, parse_policy_by_value};
414 use super::*;
415 use std::cmp::Ordering;
416
417 fn test_policy() -> Policy {
418 const TEST_POLICY: &[u8] =
419 include_bytes!("../../testdata/micro_policies/security_context_tests_policy");
420 parse_policy_by_value(TEST_POLICY.to_vec()).unwrap().validate().unwrap()
421 }
422
423 #[derive(Debug, Eq, PartialEq)]
425 struct CategoryItem {
426 low: String,
427 high: String,
428 }
429
430 fn user_name(policy: &Policy, id: UserId) -> &str {
431 std::str::from_utf8(policy.users().get_by_id(id).unwrap().name()).unwrap()
432 }
433
434 fn role_name(policy: &Policy, id: RoleId) -> &str {
435 std::str::from_utf8(policy.roles().get_by_id(id).unwrap().name()).unwrap()
436 }
437
438 fn type_name(policy: &Policy, id: TypeId) -> &str {
439 std::str::from_utf8(policy.types().get_by_id(id).unwrap().name()).unwrap()
440 }
441
442 fn sensitivity_name(policy: &Policy, id: SensitivityId) -> &str {
443 std::str::from_utf8(policy.sensitivities().get_by_id(id).unwrap().name()).unwrap()
444 }
445
446 fn category_name(policy: &Policy, id: CategoryId) -> &str {
447 std::str::from_utf8(policy.categories().get_by_id(id).unwrap().name()).unwrap()
448 }
449
450 fn category_span(policy: &Policy, category: &CategorySpan) -> CategoryItem {
451 CategoryItem {
452 low: category_name(policy, category.low()).into(),
453 high: category_name(policy, category.high()).into(),
454 }
455 }
456
457 fn category_spans(
458 policy: &Policy,
459 iter: impl Iterator<Item = CategorySpan>,
460 ) -> Vec<CategoryItem> {
461 iter.map(|x| category_span(policy, &x)).collect()
462 }
463
464 fn cat(low: u32, high: u32) -> CategorySpan {
466 CategorySpan::new(
467 CategoryId::from_u32(low).expect("category ids are nonzero"),
468 CategoryId::from_u32(high).expect("category ids are nonzero"),
469 )
470 }
471
472 fn compare(lhs: &[CategorySpan], rhs: &[CategorySpan]) -> Option<Ordering> {
474 let lhs_set = CategorySet::from_ids(lhs.iter().flat_map(|span| {
475 (span.low().as_u32()..=span.high().as_u32()).map(|i| CategoryId::from_u32(i).unwrap())
476 }));
477 let rhs_set = CategorySet::from_ids(rhs.iter().flat_map(|span| {
478 (span.low().as_u32()..=span.high().as_u32()).map(|i| CategoryId::from_u32(i).unwrap())
479 }));
480 lhs_set.compare(&rhs_set)
481 }
482
483 #[test]
484 fn category_compare() {
485 let cat_1 = cat(1, 1);
486 let cat_2 = cat(1, 3);
487 let cat_3 = cat(2, 3);
488 assert_eq!(compare(&[cat_1.clone()], &[cat_1.clone()]), Some(Ordering::Equal));
489 assert_eq!(compare(&[cat_1.clone()], &[cat_2.clone()]), Some(Ordering::Less));
490 assert_eq!(compare(&[cat_1.clone()], &[cat_3.clone()]), None);
491 assert_eq!(compare(&[cat_2.clone()], &[cat_1.clone()]), Some(Ordering::Greater));
492 assert_eq!(compare(&[cat_2.clone()], &[cat_3.clone()]), Some(Ordering::Greater));
493 }
494
495 #[test]
496 fn categories_compare_empty_iter() {
497 let cats_0 = &[];
498 let cats_1 = &[cat(1, 1)];
499 assert_eq!(compare(cats_0, cats_0), Some(Ordering::Equal));
500 assert_eq!(compare(cats_0, cats_1), Some(Ordering::Less));
501 assert_eq!(compare(cats_1, cats_0), Some(Ordering::Greater));
502 }
503
504 #[test]
505 fn categories_compare_same_length() {
506 let cats_1 = &[cat(1, 1), cat(3, 3)];
507 let cats_2 = &[cat(1, 1), cat(4, 4)];
508 let cats_3 = &[cat(1, 2), cat(4, 4)];
509 let cats_4 = &[cat(1, 2), cat(4, 5)];
510
511 assert_eq!(compare(cats_1, cats_1), Some(Ordering::Equal));
512 assert_eq!(compare(cats_1, cats_2), None);
513 assert_eq!(compare(cats_1, cats_3), None);
514 assert_eq!(compare(cats_1, cats_4), None);
515
516 assert_eq!(compare(cats_2, cats_1), None);
517 assert_eq!(compare(cats_2, cats_2), Some(Ordering::Equal));
518 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Less));
519 assert_eq!(compare(cats_2, cats_4), Some(Ordering::Less));
520
521 assert_eq!(compare(cats_3, cats_1), None);
522 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Greater));
523 assert_eq!(compare(cats_3, cats_3), Some(Ordering::Equal));
524 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
525
526 assert_eq!(compare(cats_4, cats_1), None);
527 assert_eq!(compare(cats_4, cats_2), Some(Ordering::Greater));
528 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
529 assert_eq!(compare(cats_4, cats_4), Some(Ordering::Equal));
530 }
531
532 #[test]
533 fn categories_compare_different_lengths() {
534 let cats_1 = &[cat(1, 1)];
535 let cats_2 = &[cat(1, 4)];
536 let cats_3 = &[cat(1, 1), cat(4, 4)];
537 let cats_4 = &[cat(1, 2), cat(4, 5), cat(7, 7)];
538
539 assert_eq!(compare(cats_1, cats_3), Some(Ordering::Less));
540 assert_eq!(compare(cats_1, cats_4), Some(Ordering::Less));
541
542 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Greater));
543 assert_eq!(compare(cats_2, cats_4), None);
544
545 assert_eq!(compare(cats_3, cats_1), Some(Ordering::Greater));
546 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Less));
547 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
548
549 assert_eq!(compare(cats_4, cats_1), Some(Ordering::Greater));
550 assert_eq!(compare(cats_4, cats_2), None);
551 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
552 }
553
554 #[test]
555 fn categories_compare_with_gaps() {
558 let cats_1 = &[cat(1, 2), cat(4, 5)];
559 let cats_2 = &[cat(4, 5)];
560 let cats_3 = &[cat(2, 5), cat(10, 11)];
561 let cats_4 = &[cat(2, 5), cat(7, 8), cat(10, 11)];
562
563 assert_eq!(compare(cats_1, cats_2), Some(Ordering::Greater));
564 assert_eq!(compare(cats_1, cats_3), None);
565 assert_eq!(compare(cats_1, cats_4), None);
566
567 assert_eq!(compare(cats_2, cats_1), Some(Ordering::Less));
568 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Less));
569 assert_eq!(compare(cats_2, cats_4), Some(Ordering::Less));
570
571 assert_eq!(compare(cats_3, cats_1), None);
572 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Greater));
573 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
574
575 assert_eq!(compare(cats_4, cats_1), None);
576 assert_eq!(compare(cats_4, cats_2), Some(Ordering::Greater));
577 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
578 }
579
580 #[test]
581 fn parse_security_context_single_sensitivity() {
582 let policy = test_policy();
583 let security_context = policy
584 .parse_security_context(b"user0:object_r:type0:s0".into())
585 .expect("creating security context should succeed");
586 assert_eq!(user_name(&policy, security_context.user()), "user0");
587 assert_eq!(role_name(&policy, security_context.role()), "object_r");
588 assert_eq!(type_name(&policy, security_context.type_()), "type0");
589 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s0");
590 assert!(category_spans(&policy, security_context.low_level().category_spans()).is_empty());
591 assert_eq!(security_context.high_level(), None);
592 }
593
594 #[test]
595 fn parse_security_context_with_sensitivity_range() {
596 let policy = test_policy();
597 let security_context = policy
598 .parse_security_context(b"user0:object_r:type0:s0-s1".into())
599 .expect("creating security context should succeed");
600 assert_eq!(user_name(&policy, security_context.user()), "user0");
601 assert_eq!(role_name(&policy, security_context.role()), "object_r");
602 assert_eq!(type_name(&policy, security_context.type_()), "type0");
603 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s0");
604 assert!(category_spans(&policy, security_context.low_level().category_spans()).is_empty());
605 let high_level = security_context.high_level().unwrap();
606 assert_eq!(sensitivity_name(&policy, high_level.sensitivity()), "s1");
607 assert!(category_spans(&policy, high_level.category_spans()).is_empty());
608 }
609
610 #[test]
611 fn parse_security_context_with_single_sensitivity_and_categories_interval() {
612 let policy = test_policy();
613 let security_context = policy
614 .parse_security_context(b"user0:object_r:type0:s1:c0.c4".into())
615 .expect("creating security context should succeed");
616 assert_eq!(user_name(&policy, security_context.user()), "user0");
617 assert_eq!(role_name(&policy, security_context.role()), "object_r");
618 assert_eq!(type_name(&policy, security_context.type_()), "type0");
619 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s1");
620 assert_eq!(
621 category_spans(&policy, security_context.low_level().category_spans()),
622 [CategoryItem { low: "c0".to_string(), high: "c4".to_string() }]
623 );
624 assert_eq!(security_context.high_level(), None);
625 }
626
627 #[test]
628 fn parse_security_context_and_normalize_categories() {
629 let policy = &test_policy();
630 let normalize = {
631 |security_context: &str| -> String {
632 String::from_utf8(
633 policy.serialize_security_context(
634 &policy
635 .parse_security_context(security_context.into())
636 .expect("creating security context should succeed"),
637 ),
638 )
639 .unwrap()
640 }
641 };
642 assert_eq!(normalize("user0:object_r:type0:s1:c0.c1,c1"), "user0:object_r:type0:s1:c0.c1");
644 assert_eq!(
645 normalize("user0:object_r:type0:s1:c0.c2,c1.c2"),
646 "user0:object_r:type0:s1:c0.c2"
647 );
648 assert_eq!(
649 normalize("user0:object_r:type0:s1:c0.c2,c1.c3"),
650 "user0:object_r:type0:s1:c0.c3"
651 );
652 assert_eq!(normalize("user0:object_r:type0:s1:c0.c1,c2"), "user0:object_r:type0:s1:c0.c2");
654 assert_eq!(
656 normalize("user0:object_r:type0:s1:c2.c3,c0"),
657 "user0:object_r:type0:s1:c0,c2.c3"
658 );
659 }
660
661 #[test]
662 fn parse_security_context_with_sensitivity_range_and_category_interval() {
663 let policy = test_policy();
664 let security_context = policy
665 .parse_security_context(b"user0:object_r:type0:s0-s1:c0.c4".into())
666 .expect("creating security context should succeed");
667 assert_eq!(user_name(&policy, security_context.user()), "user0");
668 assert_eq!(role_name(&policy, security_context.role()), "object_r");
669 assert_eq!(type_name(&policy, security_context.type_()), "type0");
670 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s0");
671 assert!(category_spans(&policy, security_context.low_level().category_spans()).is_empty());
672 let high_level = security_context.high_level().unwrap();
673 assert_eq!(sensitivity_name(&policy, high_level.sensitivity()), "s1");
674 assert_eq!(
675 category_spans(&policy, high_level.category_spans()),
676 [CategoryItem { low: "c0".to_string(), high: "c4".to_string() }]
677 );
678 }
679
680 #[test]
681 fn parse_security_context_with_sensitivity_range_with_categories() {
682 let policy = test_policy();
683 let security_context = policy
684 .parse_security_context(b"user0:object_r:type0:s0:c0-s1:c0.c4".into())
685 .expect("creating security context should succeed");
686 assert_eq!(user_name(&policy, security_context.user()), "user0");
687 assert_eq!(role_name(&policy, security_context.role()), "object_r");
688 assert_eq!(type_name(&policy, security_context.type_()), "type0");
689 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s0");
690 assert_eq!(
691 category_spans(&policy, security_context.low_level().category_spans()),
692 [CategoryItem { low: "c0".to_string(), high: "c0".to_string() }]
693 );
694
695 let high_level = security_context.high_level().unwrap();
696 assert_eq!(sensitivity_name(&policy, high_level.sensitivity()), "s1");
697 assert_eq!(
698 category_spans(&policy, high_level.category_spans()),
699 [CategoryItem { low: "c0".to_string(), high: "c4".to_string() }]
700 );
701 }
702
703 #[test]
704 fn parse_security_context_with_single_sensitivity_and_category_list() {
705 let policy = test_policy();
706 let security_context = policy
707 .parse_security_context(b"user0:object_r:type0:s1:c0,c4".into())
708 .expect("creating security context should succeed");
709 assert_eq!(user_name(&policy, security_context.user()), "user0");
710 assert_eq!(role_name(&policy, security_context.role()), "object_r");
711 assert_eq!(type_name(&policy, security_context.type_()), "type0");
712 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s1");
713 assert_eq!(
714 category_spans(&policy, security_context.low_level().category_spans()),
715 [
716 CategoryItem { low: "c0".to_string(), high: "c0".to_string() },
717 CategoryItem { low: "c4".to_string(), high: "c4".to_string() }
718 ]
719 );
720 assert_eq!(security_context.high_level(), None);
721 }
722
723 #[test]
724 fn parse_security_context_with_single_sensitivity_and_category_list_and_range() {
725 let policy = test_policy();
726 let security_context = policy
727 .parse_security_context(b"user0:object_r:type0:s1:c0,c3.c4".into())
728 .expect("creating security context should succeed");
729 assert_eq!(user_name(&policy, security_context.user()), "user0");
730 assert_eq!(role_name(&policy, security_context.role()), "object_r");
731 assert_eq!(type_name(&policy, security_context.type_()), "type0");
732 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s1");
733 assert_eq!(
734 category_spans(&policy, security_context.low_level().category_spans()),
735 [
736 CategoryItem { low: "c0".to_string(), high: "c0".to_string() },
737 CategoryItem { low: "c3".to_string(), high: "c4".to_string() }
738 ]
739 );
740 assert_eq!(security_context.high_level(), None);
741 }
742
743 #[test]
744 fn parse_invalid_syntax() {
745 let policy = test_policy();
746 for invalid_label in [
747 "user0",
748 "user0:object_r",
749 "user0:object_r:type0",
750 "user0:object_r:type0:s0-",
751 "user0:object_r:type0:s0:s0:s0",
752 "user0:object_r:type0:s0:c0.c0", "user0:object_r:type0:s0:c1.c0", ] {
755 assert_eq!(
756 policy.parse_security_context(invalid_label.as_bytes().into()),
757 Err(SecurityContextError::InvalidSyntax),
758 "validating {:?}",
759 invalid_label
760 );
761 }
762 }
763
764 #[test]
765 fn parse_invalid_sensitivity() {
766 let policy = test_policy();
767 for invalid_label in ["user0:object_r:type0:s_invalid", "user0:object_r:type0:s0-s_invalid"]
768 {
769 assert_eq!(
770 policy.parse_security_context(invalid_label.as_bytes().into()),
771 Err(SecurityContextError::UnknownSensitivity { name: "s_invalid".into() }),
772 "validating {:?}",
773 invalid_label
774 );
775 }
776 }
777
778 #[test]
779 fn parse_invalid_category() {
780 let policy = test_policy();
781 for invalid_label in
782 ["user0:object_r:type0:s1:c_invalid", "user0:object_r:type0:s1:c0.c_invalid"]
783 {
784 assert_eq!(
785 policy.parse_security_context(invalid_label.as_bytes().into()),
786 Err(SecurityContextError::UnknownCategory { name: "c_invalid".into() }),
787 "validating {:?}",
788 invalid_label
789 );
790 }
791 }
792
793 #[test]
794 fn invalid_security_context_fields() {
795 let policy = test_policy();
796
797 let context = policy
800 .parse_security_context(b"user0:object_r:type0:s1:c0,c3.c4-s1".into())
801 .expect("successfully parsed");
802 assert_eq!(
803 policy.validate_security_context(&context),
804 Err(SecurityContextError::InvalidSecurityRange {
805 low: "s1:c0,c3.c4".into(),
806 high: "s1".into()
807 })
808 );
809
810 let context = policy
813 .parse_security_context(b"user0:object_r:type0:s1:c0-s1:c1".into())
814 .expect("successfully parsed");
815 assert_eq!(
816 policy.validate_security_context(&context),
817 Err(SecurityContextError::InvalidSecurityRange {
818 low: "s1:c0".into(),
819 high: "s1:c1".into()
820 })
821 );
822
823 let context = policy
826 .parse_security_context(b"user0:object_r:type0:s1:c0-s0:c0.c1".into())
827 .expect("successfully parsed");
828 assert_eq!(
829 policy.validate_security_context(&context),
830 Err(SecurityContextError::InvalidSecurityRange {
831 low: "s1:c0".into(),
832 high: "s0:c0.c1".into()
833 })
834 );
835
836 let context = policy
840 .parse_security_context(b"user1:subject_r:type0:s1-s1:c3".into())
841 .expect("successfully parsed");
842 assert_eq!(
843 policy.validate_security_context(&context),
844 Err(SecurityContextError::InvalidLevelForUser {
845 level: "s1:c3".into(),
846 user: "user1".into(),
847 })
848 );
849
850 let context = policy
854 .parse_security_context(b"user1:object_r:type0:s0".into())
855 .expect("successfully parsed");
856 assert_eq!(
857 policy.validate_security_context(&context),
858 Err(SecurityContextError::InvalidLevelForUser {
859 level: "s0".into(),
860 user: "user1".into(),
861 })
862 );
863
864 let context = policy
866 .parse_security_context(b"user1:object_r:type0:s0".into())
867 .expect("successfully parsed");
868 assert!(policy.validate_security_context(&context).is_err());
869
870 let context = policy
872 .parse_security_context(b"user0:subject_r:type0:s0".into())
873 .expect("successfully parsed");
874 assert!(policy.validate_security_context(&context).is_err());
875
876 let context = policy
878 .parse_security_context(b"user1:subject_r:non_subject_t:s1".into())
879 .expect("successfully parsed");
880 assert!(policy.validate_security_context(&context).is_err());
881
882 let context = policy
885 .parse_security_context(b"user1:object_r:type0:s1".into())
886 .expect("successfully parsed");
887 assert!(policy.validate_security_context(&context).is_ok());
888 }
889
890 #[test]
891 fn format_security_contexts() {
892 let policy = test_policy();
893 for label in [
894 "user0:object_r:type0:s0",
895 "user0:object_r:type0:s0-s1",
896 "user0:object_r:type0:s1:c0.c4",
897 "user0:object_r:type0:s0-s1:c0.c4",
898 "user0:object_r:type0:s1:c0,c3",
899 "user0:object_r:type0:s0-s1:c0,c2,c4",
900 "user0:object_r:type0:s1:c0,c3.c4-s1:c0,c2.c4",
901 ] {
902 let security_context =
903 policy.parse_security_context(label.as_bytes().into()).expect("should succeed");
904 assert_eq!(policy.serialize_security_context(&security_context), label.as_bytes());
905 }
906 }
907}