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