1use super::index::PolicyIndex;
6use super::new::{CategorySetBuilder, Context, IdSpan, MlsLevel, MlsRange};
7use super::{CategoryId, RoleId, TypeId, UserId};
8use crate::NullessByteStr;
9use crate::new_policy::NewPolicy;
10use crate::new_policy::traits::{HasName, HasPolicyId, PolicyId as _};
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(super) 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(super) 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_index: &PolicyIndex,
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_index
119 .users()
120 .get_by_name(user.as_bytes())
121 .ok_or_else(|| SecurityContextError::UnknownUser { name: user.into() })?
122 .id();
123 let role = policy_index
124 .roles()
125 .get_by_name(role.as_bytes())
126 .ok_or_else(|| SecurityContextError::UnknownRole { name: role.into() })?
127 .id();
128 let type_ = policy_index
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_index, low_level)?;
135 let high_level = high_level.map(|x| MlsLevel::from_string(policy_index, x)).transpose()?;
136
137 Ok(Self::new(user, role, type_, low_level, high_level))
138 }
139
140 pub(super) fn to_string(&self, policy_index: &PolicyIndex) -> Vec<u8> {
142 let mut levels = self.low_level().to_string(policy_index);
143 if let Some(high_level) = self.high_level() {
144 levels.push(b'-');
145 levels.extend(high_level.to_string(policy_index));
146 }
147 let type_ = policy_index.types().get_by_id(self.type_()).unwrap();
148 let parts: [&[u8]; 4] = [
149 policy_index.users().get_by_id(self.user()).unwrap().name(),
150 policy_index.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_index: &PolicyIndex) -> Result<(), SecurityContextError> {
160 let user = policy_index.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_index).into(),
169 high: high_level.to_string(policy_index).into(),
170 });
171 }
172 }
173
174 if self.role() == policy_index.object_role() {
177 return Ok(());
178 }
179
180 if !user.roles().contains(self.role()) {
182 return Err(SecurityContextError::InvalidRoleForUser {
183 role: policy_index.roles().get_by_id(self.role()).unwrap().name().into(),
184 user: user.name().into(),
185 });
186 }
187
188 let role = policy_index.roles().get_by_id(self.role()).unwrap();
190 if !role.types().contains(self.type_()) {
191 return Err(SecurityContextError::InvalidTypeForRole {
192 type_: policy_index.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_index).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_index).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_index: &PolicyIndex,
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_index
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_index, low_str)?;
253 let high = Self::category_id_by_name(policy_index, 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_index, 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_index: &PolicyIndex,
270 name: &str,
271 ) -> Result<CategoryId, SecurityContextError> {
272 Ok(policy_index
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::new::CategorySet;
348 use super::super::{Policy, PolicyId, SensitivityId, parse_policy_by_value};
349 use super::*;
350 use std::cmp::Ordering;
351
352 fn test_policy() -> Policy {
353 const TEST_POLICY: &[u8] =
354 include_bytes!("../../testdata/micro_policies/security_context_tests_policy");
355 parse_policy_by_value(TEST_POLICY.to_vec()).unwrap().validate().unwrap()
356 }
357
358 #[derive(Debug, Eq, PartialEq)]
360 struct CategoryItem {
361 low: String,
362 high: String,
363 }
364
365 fn user_name(policy: &Policy, id: UserId) -> &str {
366 std::str::from_utf8(policy.users().get_by_id(id).unwrap().name()).unwrap()
367 }
368
369 fn role_name(policy: &Policy, id: RoleId) -> &str {
370 std::str::from_utf8(policy.roles().get_by_id(id).unwrap().name()).unwrap()
371 }
372
373 fn type_name(policy: &Policy, id: TypeId) -> &str {
374 std::str::from_utf8(policy.types().get_by_id(id).unwrap().name()).unwrap()
375 }
376
377 fn sensitivity_name(policy: &Policy, id: SensitivityId) -> &str {
378 std::str::from_utf8(policy.sensitivities().get_by_id(id).unwrap().name()).unwrap()
379 }
380
381 fn category_name(policy: &Policy, id: CategoryId) -> &str {
382 std::str::from_utf8(policy.categories().get_by_id(id).unwrap().name()).unwrap()
383 }
384
385 fn category_span(policy: &Policy, category: &CategorySpan) -> CategoryItem {
386 CategoryItem {
387 low: category_name(policy, category.low()).into(),
388 high: category_name(policy, category.high()).into(),
389 }
390 }
391
392 fn category_spans(
393 policy: &Policy,
394 iter: impl Iterator<Item = CategorySpan>,
395 ) -> Vec<CategoryItem> {
396 iter.map(|x| category_span(policy, &x)).collect()
397 }
398
399 fn cat(low: u32, high: u32) -> CategorySpan {
401 CategorySpan::new(
402 CategoryId::from_u32(low).expect("category ids are nonzero"),
403 CategoryId::from_u32(high).expect("category ids are nonzero"),
404 )
405 }
406
407 fn compare(lhs: &[CategorySpan], rhs: &[CategorySpan]) -> Option<Ordering> {
409 let lhs_set = CategorySet::from_ids(lhs.iter().flat_map(|span| {
410 (span.low().as_u32()..=span.high().as_u32()).map(|i| CategoryId::from_u32(i).unwrap())
411 }));
412 let rhs_set = CategorySet::from_ids(rhs.iter().flat_map(|span| {
413 (span.low().as_u32()..=span.high().as_u32()).map(|i| CategoryId::from_u32(i).unwrap())
414 }));
415 lhs_set.compare(&rhs_set)
416 }
417
418 #[test]
419 fn category_compare() {
420 let cat_1 = cat(1, 1);
421 let cat_2 = cat(1, 3);
422 let cat_3 = cat(2, 3);
423 assert_eq!(compare(&[cat_1.clone()], &[cat_1.clone()]), Some(Ordering::Equal));
424 assert_eq!(compare(&[cat_1.clone()], &[cat_2.clone()]), Some(Ordering::Less));
425 assert_eq!(compare(&[cat_1.clone()], &[cat_3.clone()]), None);
426 assert_eq!(compare(&[cat_2.clone()], &[cat_1.clone()]), Some(Ordering::Greater));
427 assert_eq!(compare(&[cat_2.clone()], &[cat_3.clone()]), Some(Ordering::Greater));
428 }
429
430 #[test]
431 fn categories_compare_empty_iter() {
432 let cats_0 = &[];
433 let cats_1 = &[cat(1, 1)];
434 assert_eq!(compare(cats_0, cats_0), Some(Ordering::Equal));
435 assert_eq!(compare(cats_0, cats_1), Some(Ordering::Less));
436 assert_eq!(compare(cats_1, cats_0), Some(Ordering::Greater));
437 }
438
439 #[test]
440 fn categories_compare_same_length() {
441 let cats_1 = &[cat(1, 1), cat(3, 3)];
442 let cats_2 = &[cat(1, 1), cat(4, 4)];
443 let cats_3 = &[cat(1, 2), cat(4, 4)];
444 let cats_4 = &[cat(1, 2), cat(4, 5)];
445
446 assert_eq!(compare(cats_1, cats_1), Some(Ordering::Equal));
447 assert_eq!(compare(cats_1, cats_2), None);
448 assert_eq!(compare(cats_1, cats_3), None);
449 assert_eq!(compare(cats_1, cats_4), None);
450
451 assert_eq!(compare(cats_2, cats_1), None);
452 assert_eq!(compare(cats_2, cats_2), Some(Ordering::Equal));
453 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Less));
454 assert_eq!(compare(cats_2, cats_4), Some(Ordering::Less));
455
456 assert_eq!(compare(cats_3, cats_1), None);
457 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Greater));
458 assert_eq!(compare(cats_3, cats_3), Some(Ordering::Equal));
459 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
460
461 assert_eq!(compare(cats_4, cats_1), None);
462 assert_eq!(compare(cats_4, cats_2), Some(Ordering::Greater));
463 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
464 assert_eq!(compare(cats_4, cats_4), Some(Ordering::Equal));
465 }
466
467 #[test]
468 fn categories_compare_different_lengths() {
469 let cats_1 = &[cat(1, 1)];
470 let cats_2 = &[cat(1, 4)];
471 let cats_3 = &[cat(1, 1), cat(4, 4)];
472 let cats_4 = &[cat(1, 2), cat(4, 5), cat(7, 7)];
473
474 assert_eq!(compare(cats_1, cats_3), Some(Ordering::Less));
475 assert_eq!(compare(cats_1, cats_4), Some(Ordering::Less));
476
477 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Greater));
478 assert_eq!(compare(cats_2, cats_4), None);
479
480 assert_eq!(compare(cats_3, cats_1), Some(Ordering::Greater));
481 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Less));
482 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
483
484 assert_eq!(compare(cats_4, cats_1), Some(Ordering::Greater));
485 assert_eq!(compare(cats_4, cats_2), None);
486 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
487 }
488
489 #[test]
490 fn categories_compare_with_gaps() {
493 let cats_1 = &[cat(1, 2), cat(4, 5)];
494 let cats_2 = &[cat(4, 5)];
495 let cats_3 = &[cat(2, 5), cat(10, 11)];
496 let cats_4 = &[cat(2, 5), cat(7, 8), cat(10, 11)];
497
498 assert_eq!(compare(cats_1, cats_2), Some(Ordering::Greater));
499 assert_eq!(compare(cats_1, cats_3), None);
500 assert_eq!(compare(cats_1, cats_4), None);
501
502 assert_eq!(compare(cats_2, cats_1), Some(Ordering::Less));
503 assert_eq!(compare(cats_2, cats_3), Some(Ordering::Less));
504 assert_eq!(compare(cats_2, cats_4), Some(Ordering::Less));
505
506 assert_eq!(compare(cats_3, cats_1), None);
507 assert_eq!(compare(cats_3, cats_2), Some(Ordering::Greater));
508 assert_eq!(compare(cats_3, cats_4), Some(Ordering::Less));
509
510 assert_eq!(compare(cats_4, cats_1), None);
511 assert_eq!(compare(cats_4, cats_2), Some(Ordering::Greater));
512 assert_eq!(compare(cats_4, cats_3), Some(Ordering::Greater));
513 }
514
515 #[test]
516 fn parse_security_context_single_sensitivity() {
517 let policy = test_policy();
518 let security_context = policy
519 .parse_security_context(b"user0:object_r:type0:s0".into())
520 .expect("creating security context should succeed");
521 assert_eq!(user_name(&policy, security_context.user()), "user0");
522 assert_eq!(role_name(&policy, security_context.role()), "object_r");
523 assert_eq!(type_name(&policy, security_context.type_()), "type0");
524 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s0");
525 assert!(category_spans(&policy, security_context.low_level().category_spans()).is_empty());
526 assert_eq!(security_context.high_level(), None);
527 }
528
529 #[test]
530 fn parse_security_context_with_sensitivity_range() {
531 let policy = test_policy();
532 let security_context = policy
533 .parse_security_context(b"user0:object_r:type0:s0-s1".into())
534 .expect("creating security context should succeed");
535 assert_eq!(user_name(&policy, security_context.user()), "user0");
536 assert_eq!(role_name(&policy, security_context.role()), "object_r");
537 assert_eq!(type_name(&policy, security_context.type_()), "type0");
538 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s0");
539 assert!(category_spans(&policy, security_context.low_level().category_spans()).is_empty());
540 let high_level = security_context.high_level().unwrap();
541 assert_eq!(sensitivity_name(&policy, high_level.sensitivity()), "s1");
542 assert!(category_spans(&policy, high_level.category_spans()).is_empty());
543 }
544
545 #[test]
546 fn parse_security_context_with_single_sensitivity_and_categories_interval() {
547 let policy = test_policy();
548 let security_context = policy
549 .parse_security_context(b"user0:object_r:type0:s1:c0.c4".into())
550 .expect("creating security context should succeed");
551 assert_eq!(user_name(&policy, security_context.user()), "user0");
552 assert_eq!(role_name(&policy, security_context.role()), "object_r");
553 assert_eq!(type_name(&policy, security_context.type_()), "type0");
554 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s1");
555 assert_eq!(
556 category_spans(&policy, security_context.low_level().category_spans()),
557 [CategoryItem { low: "c0".to_string(), high: "c4".to_string() }]
558 );
559 assert_eq!(security_context.high_level(), None);
560 }
561
562 #[test]
563 fn parse_security_context_and_normalize_categories() {
564 let policy = &test_policy();
565 let normalize = {
566 |security_context: &str| -> String {
567 String::from_utf8(
568 policy.serialize_security_context(
569 &policy
570 .parse_security_context(security_context.into())
571 .expect("creating security context should succeed"),
572 ),
573 )
574 .unwrap()
575 }
576 };
577 assert_eq!(normalize("user0:object_r:type0:s1:c0.c1,c1"), "user0:object_r:type0:s1:c0,c1");
579 assert_eq!(
580 normalize("user0:object_r:type0:s1:c0.c2,c1.c2"),
581 "user0:object_r:type0:s1:c0.c2"
582 );
583 assert_eq!(
584 normalize("user0:object_r:type0:s1:c0.c2,c1.c3"),
585 "user0:object_r:type0:s1:c0.c3"
586 );
587 assert_eq!(normalize("user0:object_r:type0:s1:c0.c1,c2"), "user0:object_r:type0:s1:c0.c2");
589 assert_eq!(
591 normalize("user0:object_r:type0:s1:c2.c3,c0"),
592 "user0:object_r:type0:s1:c0,c2,c3"
593 );
594 }
595
596 #[test]
597 fn parse_security_context_with_sensitivity_range_and_category_interval() {
598 let policy = test_policy();
599 let security_context = policy
600 .parse_security_context(b"user0:object_r:type0:s0-s1:c0.c4".into())
601 .expect("creating security context should succeed");
602 assert_eq!(user_name(&policy, security_context.user()), "user0");
603 assert_eq!(role_name(&policy, security_context.role()), "object_r");
604 assert_eq!(type_name(&policy, security_context.type_()), "type0");
605 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s0");
606 assert!(category_spans(&policy, security_context.low_level().category_spans()).is_empty());
607 let high_level = security_context.high_level().unwrap();
608 assert_eq!(sensitivity_name(&policy, high_level.sensitivity()), "s1");
609 assert_eq!(
610 category_spans(&policy, high_level.category_spans()),
611 [CategoryItem { low: "c0".to_string(), high: "c4".to_string() }]
612 );
613 }
614
615 #[test]
616 fn parse_security_context_with_sensitivity_range_with_categories() {
617 let policy = test_policy();
618 let security_context = policy
619 .parse_security_context(b"user0:object_r:type0:s0:c0-s1:c0.c4".into())
620 .expect("creating security context should succeed");
621 assert_eq!(user_name(&policy, security_context.user()), "user0");
622 assert_eq!(role_name(&policy, security_context.role()), "object_r");
623 assert_eq!(type_name(&policy, security_context.type_()), "type0");
624 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s0");
625 assert_eq!(
626 category_spans(&policy, security_context.low_level().category_spans()),
627 [CategoryItem { low: "c0".to_string(), high: "c0".to_string() }]
628 );
629
630 let high_level = security_context.high_level().unwrap();
631 assert_eq!(sensitivity_name(&policy, high_level.sensitivity()), "s1");
632 assert_eq!(
633 category_spans(&policy, high_level.category_spans()),
634 [CategoryItem { low: "c0".to_string(), high: "c4".to_string() }]
635 );
636 }
637
638 #[test]
639 fn parse_security_context_with_single_sensitivity_and_category_list() {
640 let policy = test_policy();
641 let security_context = policy
642 .parse_security_context(b"user0:object_r:type0:s1:c0,c4".into())
643 .expect("creating security context should succeed");
644 assert_eq!(user_name(&policy, security_context.user()), "user0");
645 assert_eq!(role_name(&policy, security_context.role()), "object_r");
646 assert_eq!(type_name(&policy, security_context.type_()), "type0");
647 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s1");
648 assert_eq!(
649 category_spans(&policy, security_context.low_level().category_spans()),
650 [
651 CategoryItem { low: "c0".to_string(), high: "c0".to_string() },
652 CategoryItem { low: "c4".to_string(), high: "c4".to_string() }
653 ]
654 );
655 assert_eq!(security_context.high_level(), None);
656 }
657
658 #[test]
659 fn parse_security_context_with_single_sensitivity_and_category_list_and_range() {
660 let policy = test_policy();
661 let security_context = policy
662 .parse_security_context(b"user0:object_r:type0:s1:c0,c3.c4".into())
663 .expect("creating security context should succeed");
664 assert_eq!(user_name(&policy, security_context.user()), "user0");
665 assert_eq!(role_name(&policy, security_context.role()), "object_r");
666 assert_eq!(type_name(&policy, security_context.type_()), "type0");
667 assert_eq!(sensitivity_name(&policy, security_context.low_level().sensitivity()), "s1");
668 assert_eq!(
669 category_spans(&policy, security_context.low_level().category_spans()),
670 [
671 CategoryItem { low: "c0".to_string(), high: "c0".to_string() },
672 CategoryItem { low: "c3".to_string(), high: "c4".to_string() }
673 ]
674 );
675 assert_eq!(security_context.high_level(), None);
676 }
677
678 #[test]
679 fn parse_invalid_syntax() {
680 let policy = test_policy();
681 for invalid_label in [
682 "user0",
683 "user0:object_r",
684 "user0:object_r:type0",
685 "user0:object_r:type0:s0-",
686 "user0:object_r:type0:s0:s0:s0",
687 "user0:object_r:type0:s0:c0.c0", "user0:object_r:type0:s0:c1.c0", ] {
690 assert_eq!(
691 policy.parse_security_context(invalid_label.as_bytes().into()),
692 Err(SecurityContextError::InvalidSyntax),
693 "validating {:?}",
694 invalid_label
695 );
696 }
697 }
698
699 #[test]
700 fn parse_invalid_sensitivity() {
701 let policy = test_policy();
702 for invalid_label in ["user0:object_r:type0:s_invalid", "user0:object_r:type0:s0-s_invalid"]
703 {
704 assert_eq!(
705 policy.parse_security_context(invalid_label.as_bytes().into()),
706 Err(SecurityContextError::UnknownSensitivity { name: "s_invalid".into() }),
707 "validating {:?}",
708 invalid_label
709 );
710 }
711 }
712
713 #[test]
714 fn parse_invalid_category() {
715 let policy = test_policy();
716 for invalid_label in
717 ["user0:object_r:type0:s1:c_invalid", "user0:object_r:type0:s1:c0.c_invalid"]
718 {
719 assert_eq!(
720 policy.parse_security_context(invalid_label.as_bytes().into()),
721 Err(SecurityContextError::UnknownCategory { name: "c_invalid".into() }),
722 "validating {:?}",
723 invalid_label
724 );
725 }
726 }
727
728 #[test]
729 fn invalid_security_context_fields() {
730 let policy = test_policy();
731
732 let context = policy
735 .parse_security_context(b"user0:object_r:type0:s1:c0,c3.c4-s1".into())
736 .expect("successfully parsed");
737 assert_eq!(
738 policy.validate_security_context(&context),
739 Err(SecurityContextError::InvalidSecurityRange {
740 low: "s1:c0,c3,c4".into(),
741 high: "s1".into()
742 })
743 );
744
745 let context = policy
748 .parse_security_context(b"user0:object_r:type0:s1:c0-s1:c1".into())
749 .expect("successfully parsed");
750 assert_eq!(
751 policy.validate_security_context(&context),
752 Err(SecurityContextError::InvalidSecurityRange {
753 low: "s1:c0".into(),
754 high: "s1:c1".into()
755 })
756 );
757
758 let context = policy
761 .parse_security_context(b"user0:object_r:type0:s1:c0-s0:c0.c1".into())
762 .expect("successfully parsed");
763 assert_eq!(
764 policy.validate_security_context(&context),
765 Err(SecurityContextError::InvalidSecurityRange {
766 low: "s1:c0".into(),
767 high: "s0:c0,c1".into()
768 })
769 );
770
771 let context = policy
775 .parse_security_context(b"user1:subject_r:type0:s1-s1:c3".into())
776 .expect("successfully parsed");
777 assert_eq!(
778 policy.validate_security_context(&context),
779 Err(SecurityContextError::InvalidLevelForUser {
780 level: "s1:c3".into(),
781 user: "user1".into(),
782 })
783 );
784
785 let context = policy
789 .parse_security_context(b"user1:subject_r:type0:s0".into())
790 .expect("successfully parsed");
791 assert_eq!(
792 policy.validate_security_context(&context),
793 Err(SecurityContextError::InvalidLevelForUser {
794 level: "s0".into(),
795 user: "user1".into(),
796 })
797 );
798
799 let context = policy
802 .parse_security_context(b"user1:object_r:type0:s0".into())
803 .expect("successfully parsed");
804 assert!(policy.validate_security_context(&context).is_ok());
805
806 let context = policy
808 .parse_security_context(b"user0:subject_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"user1:subject_r:non_subject_t:s1".into())
815 .expect("successfully parsed");
816 assert!(policy.validate_security_context(&context).is_err());
817
818 let context = policy
821 .parse_security_context(b"user1:object_r:type0:s1".into())
822 .expect("successfully parsed");
823 assert!(policy.validate_security_context(&context).is_ok());
824 }
825
826 #[test]
827 fn format_security_contexts() {
828 let policy = test_policy();
829 for label in [
830 "user0:object_r:type0:s0",
831 "user0:object_r:type0:s0-s1",
832 "user0:object_r:type0:s1:c0.c4",
833 "user0:object_r:type0:s0-s1:c0.c4",
834 "user0:object_r:type0:s1:c0,c3",
835 "user0:object_r:type0:s0-s1:c0,c2,c4",
836 "user0:object_r:type0:s1:c0,c3,c4-s1:c0,c2.c4",
837 ] {
838 let security_context =
839 policy.parse_security_context(label.as_bytes().into()).expect("should succeed");
840 assert_eq!(policy.serialize_security_context(&security_context), label.as_bytes());
841 }
842 }
843}