1use super::extensible_bitmap::ExtensibleBitmap;
6use super::security_context::{Level, SecurityContext, SecurityLevel};
7use super::symbols::{
8 CONSTRAINT_EXPR_OPERAND_TYPE_H1_H2, CONSTRAINT_EXPR_OPERAND_TYPE_H1_L2,
9 CONSTRAINT_EXPR_OPERAND_TYPE_L1_H1, CONSTRAINT_EXPR_OPERAND_TYPE_L1_H2,
10 CONSTRAINT_EXPR_OPERAND_TYPE_L1_L2, CONSTRAINT_EXPR_OPERAND_TYPE_L2_H2,
11 CONSTRAINT_EXPR_OPERAND_TYPE_ROLE, CONSTRAINT_EXPR_OPERAND_TYPE_TYPE,
12 CONSTRAINT_EXPR_OPERAND_TYPE_USER, CONSTRAINT_EXPR_OPERATOR_TYPE_DOM,
13 CONSTRAINT_EXPR_OPERATOR_TYPE_DOMBY, CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
14 CONSTRAINT_EXPR_OPERATOR_TYPE_INCOMP, CONSTRAINT_EXPR_OPERATOR_TYPE_NE,
15 CONSTRAINT_EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK, CONSTRAINT_TERM_TYPE_AND_OPERATOR,
16 CONSTRAINT_TERM_TYPE_EXPR, CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES,
17 CONSTRAINT_TERM_TYPE_NOT_OPERATOR, CONSTRAINT_TERM_TYPE_OR_OPERATOR, ConstraintExpr,
18 ConstraintTerm,
19};
20use super::{RoleId, TypeId, UserId};
21
22use std::cmp::Ordering;
23use std::collections::HashSet;
24use std::num::NonZeroU32;
25use thiserror::Error;
26
27#[derive(Clone, Debug, Error, Eq, PartialEq)]
28pub(super) enum ConstraintError {
29 #[error("missing names for constraint term")]
30 MissingNames,
31 #[error("invalid constraint term type {type_:?}")]
32 InvalidTermType { type_: u32 },
33 #[error("invalid operator type for context expression: {type_:?}")]
34 InvalidContextOperatorType { type_: u32 },
35 #[error("invalid operand type for context expression: {type_:?}")]
36 InvalidContextOperandType { type_: u32 },
37 #[error("invalid operand type for context expression with names: {type_:?}")]
38 InvalidContextWithNamesOperandType { type_: u32 },
39 #[error("invalid operator type {operator:?} for operands ({left:?}, {right:?})")]
40 InvalidContextOperatorForOperands {
41 operator: ContextOperator,
42 left: ContextOperand,
43 right: ContextOperand,
44 },
45 #[error("invalid pair of context operands: ({left:?}, {right:?})")]
46 InvalidContextOperands { left: ContextOperand, right: ContextOperand },
47 #[error("invalid constraint term sequence")]
48 InvalidTermSequence,
49}
50
51pub(super) fn evaluate_constraint(
63 constraint_expr: &ConstraintExpr,
64 source: &SecurityContext,
65 target: &SecurityContext,
66) -> Result<bool, ConstraintError> {
67 let nodes = constraint_expr
68 .constraint_terms()
69 .iter()
70 .map(|term| ConstraintNode::try_from_constraint_term(term, source, target))
71 .collect::<Result<Vec<_>, _>>()?;
72 let mut stack = Vec::new();
73 for node in nodes.iter() {
74 match node {
75 ConstraintNode::Leaf(expr) => stack.push(expr.evaluate()?),
76 ConstraintNode::Branch(op) => match op {
77 BooleanOperator::Not => {
78 let arg = stack.last_mut().ok_or(ConstraintError::InvalidTermSequence)?;
79 *arg = !*arg;
80 }
81 BooleanOperator::And => {
82 let right = stack.pop().ok_or(ConstraintError::InvalidTermSequence)?;
83 let left = stack.last_mut().ok_or(ConstraintError::InvalidTermSequence)?;
84 *left = *left && right;
85 }
86 BooleanOperator::Or => {
87 let right = stack.pop().ok_or(ConstraintError::InvalidTermSequence)?;
88 let left = stack.last_mut().ok_or(ConstraintError::InvalidTermSequence)?;
89 *left = *left || right;
90 }
91 },
92 }
93 }
94 let result = stack.pop().ok_or(ConstraintError::InvalidTermSequence)?;
95 if !stack.is_empty() {
96 return Err(ConstraintError::InvalidTermSequence);
97 }
98 Ok(result)
99}
100
101#[derive(Debug)]
103enum ConstraintNode<'a> {
104 Branch(BooleanOperator),
105 Leaf(ContextExpression<'a>),
106}
107
108impl<'a> ConstraintNode<'a> {
109 fn try_from_constraint_term(
110 value: &'a ConstraintTerm,
111 source: &SecurityContext,
112 target: &SecurityContext,
113 ) -> Result<ConstraintNode<'a>, ConstraintError> {
114 if let Ok(op) = BooleanOperator::try_from_constraint_term(value) {
115 Ok(ConstraintNode::Branch(op))
116 } else {
117 Ok(ConstraintNode::Leaf(ContextExpression::try_from_constraint_term(
118 value, source, target,
119 )?))
120 }
121 }
122}
123
124#[derive(Debug, Eq, PartialEq)]
128enum BooleanOperator {
129 Not,
130 And,
131 Or,
132}
133
134impl BooleanOperator {
135 fn try_from_constraint_term(
136 value: &ConstraintTerm,
137 ) -> Result<BooleanOperator, ConstraintError> {
138 match value.constraint_term_type() {
139 CONSTRAINT_TERM_TYPE_NOT_OPERATOR => Ok(BooleanOperator::Not),
140 CONSTRAINT_TERM_TYPE_AND_OPERATOR => Ok(BooleanOperator::And),
141 CONSTRAINT_TERM_TYPE_OR_OPERATOR => Ok(BooleanOperator::Or),
142 _ => Err(ConstraintError::InvalidTermType { type_: value.constraint_term_type() }),
143 }
144 }
145}
146
147#[derive(Clone, Debug, Eq, PartialEq)]
150pub(super) enum ContextOperator {
151 Equal, NotEqual, Dominates, DominatedBy, Incomparable, }
157
158#[derive(Clone, Debug, Eq, PartialEq)]
160pub(super) enum ContextOperand {
161 UserId(UserId),
162 RoleId(RoleId),
163 TypeId(TypeId),
164 Level(SecurityLevel),
165 UserIds(HashSet<UserId>),
166 RoleIds(HashSet<RoleId>),
167 TypeIds(HashSet<TypeId>),
168}
169
170#[derive(Clone, Debug)]
171pub(super) struct TypeIds<'a> {
172 underlying: &'a ExtensibleBitmap,
173}
174
175impl<'a> TypeIds<'a> {
176 fn contains(&self, id: &TypeId) -> bool {
177 self.underlying.is_set(id.0.get() - 1)
178 }
179}
180
181#[derive(Clone, Debug)]
183enum Operand<'a> {
184 UserId(UserId),
185 RoleId(RoleId),
186 TypeId(TypeId),
187 Level(SecurityLevel),
188 UserIds(HashSet<UserId>),
189 RoleIds(HashSet<RoleId>),
190 TypeIds(TypeIds<'a>),
191}
192
193impl From<&Operand<'_>> for ContextOperand {
194 fn from(value: &Operand<'_>) -> Self {
195 match value {
196 Operand::UserId(user_id) => Self::UserId(user_id.clone()),
197 Operand::RoleId(role_id) => Self::RoleId(role_id.clone()),
198 Operand::TypeId(type_id) => Self::TypeId(type_id.clone()),
199 Operand::Level(security_level) => Self::Level(security_level.clone()),
200 Operand::UserIds(user_ids) => Self::UserIds(user_ids.clone()),
201 Operand::RoleIds(role_ids) => Self::RoleIds(role_ids.clone()),
202 Operand::TypeIds(type_ids) => Self::TypeIds(
203 type_ids
204 .underlying
205 .indices_of_set_bits()
206 .map(|i| TypeId(NonZeroU32::new(i + 1).unwrap()))
207 .collect(),
208 ),
209 }
210 }
211}
212
213#[derive(Debug)]
217struct ContextExpression<'a> {
218 left: Operand<'a>,
219 right: Operand<'a>,
220 operator: ContextOperator,
221}
222
223impl<'a> ContextExpression<'a> {
224 fn evaluate(&self) -> Result<bool, ConstraintError> {
225 match (&self.left, &self.right) {
226 (Operand::UserId(left_id), Operand::UserId(right_id)) => match self.operator {
227 ContextOperator::Equal => Ok(left_id == right_id),
228 ContextOperator::NotEqual => Ok(left_id != right_id),
229 _ => Err(ConstraintError::InvalidContextOperatorForOperands {
230 operator: self.operator.clone(),
231 left: ContextOperand::from(&self.left),
232 right: ContextOperand::from(&self.right),
233 }),
234 },
235 (Operand::RoleId(left_id), Operand::RoleId(right_id)) => match self.operator {
236 ContextOperator::Equal => Ok(left_id == right_id),
237 ContextOperator::NotEqual => Ok(left_id != right_id),
238 _ => Err(ConstraintError::InvalidContextOperatorForOperands {
239 operator: self.operator.clone(),
240 left: ContextOperand::from(&self.left),
241 right: ContextOperand::from(&self.right),
242 }),
243 },
244 (Operand::TypeId(left_id), Operand::TypeId(right_id)) => match self.operator {
245 ContextOperator::Equal => Ok(left_id == right_id),
246 ContextOperator::NotEqual => Ok(left_id != right_id),
247 _ => Err(ConstraintError::InvalidContextOperatorForOperands {
248 operator: self.operator.clone(),
249 left: ContextOperand::from(&self.left),
250 right: ContextOperand::from(&self.right),
251 }),
252 },
253 (Operand::UserId(id), Operand::UserIds(ids)) => match self.operator {
254 ContextOperator::Equal => Ok(ids.contains(id)),
255 ContextOperator::NotEqual => Ok(!ids.contains(id)),
256 _ => Err(ConstraintError::InvalidContextOperatorForOperands {
257 operator: self.operator.clone(),
258 left: ContextOperand::from(&self.left),
259 right: ContextOperand::from(&self.right),
260 }),
261 },
262 (Operand::RoleId(id), Operand::RoleIds(ids)) => match self.operator {
263 ContextOperator::Equal => Ok(ids.contains(id)),
264 ContextOperator::NotEqual => Ok(!ids.contains(id)),
265 _ => Err(ConstraintError::InvalidContextOperatorForOperands {
266 operator: self.operator.clone(),
267 left: ContextOperand::from(&self.left),
268 right: ContextOperand::from(&self.right),
269 }),
270 },
271 (Operand::TypeId(id), Operand::TypeIds(ids)) => match self.operator {
272 ContextOperator::Equal => Ok(ids.contains(id)),
273 ContextOperator::NotEqual => Ok(!ids.contains(id)),
274 _ => Err(ConstraintError::InvalidContextOperatorForOperands {
275 operator: self.operator.clone(),
276 left: ContextOperand::from(&self.left),
277 right: ContextOperand::from(&self.right),
278 }),
279 },
280 (Operand::Level(left), Operand::Level(right)) => match self.operator {
281 ContextOperator::Equal => Ok(left.compare(right) == Some(Ordering::Equal)),
282 ContextOperator::NotEqual => Ok(left.compare(right) != Some(Ordering::Equal)),
283 ContextOperator::Dominates => Ok(left.dominates(right)),
284 ContextOperator::DominatedBy => Ok(right.dominates(left)),
285 ContextOperator::Incomparable => Ok(left.compare(right).is_none()),
286 },
287 _ => Err(ConstraintError::InvalidContextOperands {
288 left: ContextOperand::from(&self.left),
289 right: ContextOperand::from(&self.right),
290 }),
291 }
292 }
293
294 fn try_from_constraint_term(
295 value: &'a ConstraintTerm,
296 source: &SecurityContext,
297 target: &SecurityContext,
298 ) -> Result<ContextExpression<'a>, ConstraintError> {
299 let (left, right) = match value.constraint_term_type() {
300 CONSTRAINT_TERM_TYPE_EXPR => {
301 ContextExpression::operands_from_expr(value.expr_operand_type(), source, target)
302 }
303 CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES => {
304 if let Some(names) = value.names() {
305 ContextExpression::operands_from_expr_with_names(
306 value.expr_operand_type(),
307 names,
308 source,
309 target,
310 )
311 } else {
312 Err(ConstraintError::MissingNames)
313 }
314 }
315 _ => Err(ConstraintError::InvalidTermType { type_: value.constraint_term_type() }),
316 }?;
317 let operator = match value.expr_operator_type() {
318 CONSTRAINT_EXPR_OPERATOR_TYPE_EQ => Ok(ContextOperator::Equal),
319 CONSTRAINT_EXPR_OPERATOR_TYPE_NE => Ok(ContextOperator::NotEqual),
320 CONSTRAINT_EXPR_OPERATOR_TYPE_DOM => Ok(ContextOperator::Dominates),
321 CONSTRAINT_EXPR_OPERATOR_TYPE_DOMBY => Ok(ContextOperator::DominatedBy),
322 CONSTRAINT_EXPR_OPERATOR_TYPE_INCOMP => Ok(ContextOperator::Incomparable),
323 _ => Err(ConstraintError::InvalidContextOperatorType {
324 type_: value.expr_operator_type(),
325 }),
326 }?;
327 Ok(ContextExpression { left, right, operator })
328 }
329
330 fn operands_from_expr(
331 operand_type: u32,
332 source: &SecurityContext,
333 target: &SecurityContext,
334 ) -> Result<(Operand<'a>, Operand<'a>), ConstraintError> {
335 match operand_type {
336 CONSTRAINT_EXPR_OPERAND_TYPE_USER => {
337 Ok((Operand::UserId(source.user()), Operand::UserId(target.user())))
338 }
339 CONSTRAINT_EXPR_OPERAND_TYPE_ROLE => {
340 Ok((Operand::RoleId(source.role()), Operand::RoleId(target.role())))
341 }
342 CONSTRAINT_EXPR_OPERAND_TYPE_TYPE => {
343 Ok((Operand::TypeId(source.type_()), Operand::TypeId(target.type_())))
344 }
345 CONSTRAINT_EXPR_OPERAND_TYPE_L1_L2 => Ok((
346 Operand::Level(source.low_level().clone()),
347 Operand::Level(target.low_level().clone()),
348 )),
349 CONSTRAINT_EXPR_OPERAND_TYPE_L1_H2 => Ok((
350 Operand::Level(source.low_level().clone()),
351 Operand::Level(target.effective_high_level().clone()),
352 )),
353 CONSTRAINT_EXPR_OPERAND_TYPE_H1_L2 => Ok((
354 Operand::Level(source.effective_high_level().clone()),
355 Operand::Level(target.low_level().clone()),
356 )),
357 CONSTRAINT_EXPR_OPERAND_TYPE_H1_H2 => Ok((
358 Operand::Level(source.effective_high_level().clone()),
359 Operand::Level(target.effective_high_level().clone()),
360 )),
361 CONSTRAINT_EXPR_OPERAND_TYPE_L1_H1 => Ok((
362 Operand::Level(source.low_level().clone()),
363 Operand::Level(source.effective_high_level().clone()),
364 )),
365 CONSTRAINT_EXPR_OPERAND_TYPE_L2_H2 => Ok((
366 Operand::Level(target.low_level().clone()),
367 Operand::Level(target.effective_high_level().clone()),
368 )),
369 _ => Err(ConstraintError::InvalidContextOperandType { type_: operand_type }),
370 }
371 }
372
373 fn operands_from_expr_with_names(
374 operand_type: u32,
375 names: &'a ExtensibleBitmap,
376 source: &SecurityContext,
377 target: &SecurityContext,
378 ) -> Result<(Operand<'a>, Operand<'a>), ConstraintError> {
379 let ids = names.indices_of_set_bits().map(|i| NonZeroU32::new(i + 1).unwrap());
380
381 if operand_type & CONSTRAINT_EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK == 0 {
382 match operand_type {
383 CONSTRAINT_EXPR_OPERAND_TYPE_USER => Ok((
384 Operand::UserId(source.user()),
385 Operand::UserIds(ids.map(|id| UserId(id)).collect()),
386 )),
387 CONSTRAINT_EXPR_OPERAND_TYPE_ROLE => Ok((
388 Operand::RoleId(source.role()),
389 Operand::RoleIds(ids.map(|id| RoleId(id)).collect()),
390 )),
391 CONSTRAINT_EXPR_OPERAND_TYPE_TYPE => Ok((
392 Operand::TypeId(source.type_()),
393 Operand::TypeIds(TypeIds { underlying: names }),
394 )),
395 _ => {
396 Err(ConstraintError::InvalidContextWithNamesOperandType { type_: operand_type })
397 }
398 }
399 } else {
400 match operand_type ^ CONSTRAINT_EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK {
401 CONSTRAINT_EXPR_OPERAND_TYPE_USER => Ok((
402 Operand::UserId(target.user()),
403 Operand::UserIds(ids.map(|id| UserId(id)).collect()),
404 )),
405 CONSTRAINT_EXPR_OPERAND_TYPE_ROLE => Ok((
406 Operand::RoleId(target.role()),
407 Operand::RoleIds(ids.map(|id| RoleId(id)).collect()),
408 )),
409 CONSTRAINT_EXPR_OPERAND_TYPE_TYPE => Ok((
410 Operand::TypeId(target.type_()),
411 Operand::TypeIds(TypeIds { underlying: names }),
412 )),
413 _ => {
414 Err(ConstraintError::InvalidContextWithNamesOperandType { type_: operand_type })
415 }
416 }
417 }
418 }
419}
420
421#[cfg(test)]
422mod tests {
423 use super::*;
424 use crate::policy::{find_class_by_name, parse_policy_by_value};
425
426 impl PartialEq for Operand<'_> {
427 fn eq(&self, other: &Self) -> bool {
428 ContextOperand::from(self) == ContextOperand::from(other)
429 }
430 }
431
432 impl Eq for Operand<'_> {}
433
434 impl PartialEq for ContextExpression<'_> {
435 fn eq(&self, other: &Self) -> bool {
436 self.operator == other.operator && self.left == other.left && self.right == other.right
437 }
438 }
439
440 impl Eq for ContextExpression<'_> {}
441
442 impl PartialEq for ConstraintNode<'_> {
443 fn eq(&self, other: &Self) -> bool {
444 match (self, other) {
445 (Self::Branch(self_operator), Self::Branch(other_operator)) => {
446 self_operator == other_operator
447 }
448 (Self::Leaf(self_expression), Self::Leaf(other_expression)) => {
449 self_expression == other_expression
450 }
451 _ => false,
452 }
453 }
454 }
455
456 impl Eq for ConstraintNode<'_> {}
457
458 fn normalize_context_expr<'a>(expr: ContextExpression<'a>) -> ContextExpression<'a> {
459 let (left, right) = match expr.operator {
460 ContextOperator::Dominates | ContextOperator::DominatedBy => (expr.left, expr.right),
461 ContextOperator::Equal | ContextOperator::NotEqual | ContextOperator::Incomparable => {
462 match (&expr.left, &expr.right) {
463 (Operand::UserId(left), Operand::UserId(right)) => (
464 Operand::UserId(std::cmp::min(*left, *right)),
465 Operand::UserId(std::cmp::max(*left, *right)),
466 ),
467 (Operand::TypeId(left), Operand::TypeId(right)) => (
468 Operand::TypeId(std::cmp::min(*left, *right)),
469 Operand::TypeId(std::cmp::max(*left, *right)),
470 ),
471 (Operand::RoleId(left), Operand::RoleId(right)) => (
472 Operand::RoleId(std::cmp::min(*left, *right)),
473 Operand::RoleId(std::cmp::max(*left, *right)),
474 ),
475 _ => (expr.left, expr.right),
476 }
477 }
478 };
479 ContextExpression { operator: expr.operator, left, right }
480 }
481
482 fn normalize<'a>(expr: Vec<ConstraintNode<'a>>) -> Vec<ConstraintNode<'a>> {
483 expr.into_iter()
484 .map(|node| match node {
485 ConstraintNode::Leaf(context_expr) => {
486 ConstraintNode::Leaf(normalize_context_expr(context_expr))
487 }
488 ConstraintNode::Branch(_) => node,
489 })
490 .collect()
491 }
492
493 #[test]
494 fn decode_constraint_expr() {
495 let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy.pp");
496 let policy = parse_policy_by_value(policy_bytes.to_vec())
497 .expect("parse policy")
498 .validate()
499 .expect("validate policy");
500 let parsed_policy = policy.0.parsed_policy();
501
502 let source = policy
503 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
504 .expect("valid source security context");
505 let target = policy
506 .parse_security_context(b"user1:object_r:security_t:s0:c0-s0:c0".into())
507 .expect("valid target security context");
508
509 let class = find_class_by_name(parsed_policy.classes(), "class_constraint_nested")
510 .expect("look up class");
511 let constraints = class.constraints();
512 assert_eq!(constraints.len(), 1);
513 let constraint = &constraints[0].constraint_expr();
514 let result: Result<Vec<ConstraintNode<'_>>, ConstraintError> = constraint
515 .constraint_terms()
516 .iter()
517 .map(|x| ConstraintNode::try_from_constraint_term(x, &source, &target))
518 .collect();
519 let constraint_nodes = normalize(result.expect("decode constraint terms"));
520 let expected = vec![
521 ConstraintNode::Leaf(ContextExpression {
523 left: Operand::UserId(UserId(NonZeroU32::new(2).unwrap())),
524 right: Operand::UserIds(HashSet::from([
525 UserId(NonZeroU32::new(1).unwrap()),
526 UserId(NonZeroU32::new(2).unwrap()),
527 ])),
528 operator: ContextOperator::Equal,
529 }),
530 ConstraintNode::Leaf(ContextExpression {
532 left: Operand::RoleId(RoleId(NonZeroU32::new(1).unwrap())),
533 right: Operand::RoleId(RoleId(NonZeroU32::new(1).unwrap())),
534 operator: ContextOperator::Equal,
535 }),
536 ConstraintNode::Branch(BooleanOperator::And),
538 ConstraintNode::Leaf(ContextExpression {
540 left: Operand::UserId(UserId(NonZeroU32::new(1).unwrap())),
541 right: Operand::UserId(UserId(NonZeroU32::new(2).unwrap())),
542 operator: ContextOperator::Equal,
543 }),
544 ConstraintNode::Leaf(ContextExpression {
546 left: Operand::TypeId(TypeId(NonZeroU32::new(1).unwrap())),
547 right: Operand::TypeId(TypeId(NonZeroU32::new(2).unwrap())),
548 operator: ContextOperator::Equal,
549 }),
550 ConstraintNode::Branch(BooleanOperator::Not),
552 ConstraintNode::Branch(BooleanOperator::And),
554 ConstraintNode::Branch(BooleanOperator::Or),
556 ];
557
558 assert_eq!(constraint_nodes, expected)
559 }
560
561 #[test]
562 fn evaluate_constraint_expr() {
563 let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy.pp");
564 let policy = parse_policy_by_value(policy_bytes.to_vec())
565 .expect("parse policy")
566 .validate()
567 .expect("validate policy");
568 let parsed_policy = policy.0.parsed_policy();
569
570 let source = policy
571 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
572 .expect("valid source security context");
573 let target = policy
574 .parse_security_context(b"user1:object_r:security_t:s0:c0-s0:c0".into())
575 .expect("valid target security context");
576
577 let class_constraint_eq =
578 find_class_by_name(parsed_policy.classes(), "class_constraint_eq")
579 .expect("look up class");
580 let class_constraint_eq_constraints = class_constraint_eq.constraints();
581 assert_eq!(class_constraint_eq_constraints.len(), 1);
582 let constraint_eq = &class_constraint_eq_constraints[0].constraint_expr();
584 assert_eq!(
585 evaluate_constraint(constraint_eq, &source, &target).expect("evaluate constraint"),
586 false
587 );
588
589 let class_constraint_with_and =
590 find_class_by_name(parsed_policy.classes(), "class_constraint_with_and")
591 .expect("look up class");
592 let class_constraint_with_and_constraints = class_constraint_with_and.constraints();
593 assert_eq!(class_constraint_with_and_constraints.len(), 1);
594 let constraint_with_and = &class_constraint_with_and_constraints[0].constraint_expr();
596 assert_eq!(
597 evaluate_constraint(constraint_with_and, &source, &target)
598 .expect("evaluate constraint"),
599 false
600 );
601
602 let class_constraint_with_not =
603 find_class_by_name(parsed_policy.classes(), "class_constraint_with_not")
604 .expect("look up class");
605 let class_constraint_with_not_constraints = class_constraint_with_not.constraints();
606 assert_eq!(class_constraint_with_not_constraints.len(), 1);
607 let constraint_with_not = &class_constraint_with_not_constraints[0].constraint_expr();
609 assert_eq!(
610 evaluate_constraint(constraint_with_not, &source, &target)
611 .expect("evaluate constraint"),
612 true
613 );
614
615 let class_constraint_with_names =
616 find_class_by_name(parsed_policy.classes(), "class_constraint_with_names")
617 .expect("look up class");
618 let class_constraint_with_names_constraints = class_constraint_with_names.constraints();
619 assert_eq!(class_constraint_with_names_constraints.len(), 1);
620 let constraint_with_names = &class_constraint_with_names_constraints[0].constraint_expr();
622 assert_eq!(
623 evaluate_constraint(constraint_with_names, &source, &target)
624 .expect("evaluate constraint"),
625 false
626 );
627
628 let class_constraint_nested =
629 find_class_by_name(parsed_policy.classes(), "class_constraint_nested")
630 .expect("look up class");
631 let class_constraint_nested_constraints = class_constraint_nested.constraints();
632 assert_eq!(class_constraint_nested_constraints.len(), 1);
633 let constraint_nested = &class_constraint_nested_constraints[0].constraint_expr();
635 assert_eq!(
636 evaluate_constraint(constraint_nested, &source, &target).expect("evaluate constraint"),
637 true
638 )
639 }
640
641 #[test]
642 fn evaluate_mls_constraint_expr() {
643 let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy.pp");
644 let policy = parse_policy_by_value(policy_bytes.to_vec())
645 .expect("parse policy")
646 .validate()
647 .expect("validate policy");
648 let parsed_policy = policy.0.parsed_policy();
649
650 let source = policy
651 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
652 .expect("valid source security context");
653 let target = policy
654 .parse_security_context(b"user1:object_r:security_t:s0:c0-s0:c0".into())
655 .expect("valid target security context");
656
657 let class = find_class_by_name(parsed_policy.classes(), "class_mls_constraints")
658 .expect("look up class");
659 let constraints = class.constraints();
660 let expected = vec![
662 false, false, true, false, false, false, ];
669 for (i, constraint) in constraints.iter().enumerate() {
670 assert_eq!(
671 evaluate_constraint(constraint.constraint_expr(), &source, &target)
672 .expect("evaluate constraint",),
673 expected[i],
674 "constraint {}",
675 i
676 );
677 }
678 }
679}