1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// SPDX-License-Identifier: Apache-2.0 or MIT
//
// Copyright 2021 Sony Group Corporation
//
use crate::error::ErrorKind::*;
use crate::error::{Result, SeccompError};
use libseccomp_sys::*;
use std::str::FromStr;
/// Represents a comparison operator which can be used in a filter rule.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ScmpCompareOp {
/// Not equal
NotEqual,
/// Less than
Less,
/// Less than or equal
LessOrEqual,
/// Equal
Equal,
/// Greater than or equal
GreaterEqual,
/// Greater than
Greater,
/// Masked equality
///
/// This works like `Equal` with the exception that the syscall argument is
/// masked with `mask` via an bitwise AND (i.e. you can check specific bits in the
/// argument).
MaskedEqual(#[doc = "mask"] u64),
}
impl ScmpCompareOp {
pub(crate) const fn to_sys(self) -> scmp_compare {
match self {
Self::NotEqual => scmp_compare::SCMP_CMP_NE,
Self::Less => scmp_compare::SCMP_CMP_LT,
Self::LessOrEqual => scmp_compare::SCMP_CMP_LE,
Self::Equal => scmp_compare::SCMP_CMP_EQ,
Self::GreaterEqual => scmp_compare::SCMP_CMP_GE,
Self::Greater => scmp_compare::SCMP_CMP_GT,
Self::MaskedEqual(_) => scmp_compare::SCMP_CMP_MASKED_EQ,
}
}
}
impl FromStr for ScmpCompareOp {
type Err = SeccompError;
/// Converts string seccomp comparison operator to `ScmpCompareOp`.
///
/// # Arguments
///
/// * `cmp_op` - A string comparison operator, e.g. `SCMP_CMP_*`.
///
/// See the [`seccomp_rule_add(3)`] man page for details on valid comparison operator values.
///
/// [`seccomp_rule_add(3)`]: https://www.man7.org/linux/man-pages/man3/seccomp_rule_add.3.html
///
/// # Errors
///
/// If an invalid comparison operator is specified, an error will be returned.
fn from_str(cmp_op: &str) -> Result<Self> {
match cmp_op {
"SCMP_CMP_NE" => Ok(Self::NotEqual),
"SCMP_CMP_LT" => Ok(Self::Less),
"SCMP_CMP_LE" => Ok(Self::LessOrEqual),
"SCMP_CMP_EQ" => Ok(Self::Equal),
"SCMP_CMP_GE" => Ok(Self::GreaterEqual),
"SCMP_CMP_GT" => Ok(Self::Greater),
"SCMP_CMP_MASKED_EQ" => Ok(Self::MaskedEqual(u64::default())),
_ => Err(SeccompError::new(FromStr(cmp_op.to_string()))),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_compare_op() {
let test_data = &[
("SCMP_CMP_NE", ScmpCompareOp::NotEqual),
("SCMP_CMP_LT", ScmpCompareOp::Less),
("SCMP_CMP_LE", ScmpCompareOp::LessOrEqual),
("SCMP_CMP_EQ", ScmpCompareOp::Equal),
("SCMP_CMP_GE", ScmpCompareOp::GreaterEqual),
("SCMP_CMP_GT", ScmpCompareOp::Greater),
(
"SCMP_CMP_MASKED_EQ",
ScmpCompareOp::MaskedEqual(u64::default()),
),
];
for data in test_data {
assert_eq!(
ScmpCompareOp::from_str(data.0).unwrap().to_sys(),
data.1.to_sys()
);
}
assert!(ScmpCompareOp::from_str("SCMP_INVALID_FLAG").is_err());
}
}