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