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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-License-Identifier: Apache-2.0 or MIT
//
// Copyright 2021 Sony Group Corporation
//

use super::cvt;
use crate::error::{Result, SeccompError};
use crate::version::ensure_supported_version;
use crate::{check_version, ScmpVersion};
use libseccomp_sys::*;

/// Sets the API level forcibly.
///
/// General use of this function is strongly discouraged.
/// See the [`seccomp_api_get(3)`] man page for details on available API levels.
///
/// [`seccomp_api_get(3)`]: https://www.man7.org/linux/man-pages/man3/seccomp_api_get.3.html
///
/// This function corresponds to
/// [`seccomp_api_set`](https://www.man7.org/linux/man-pages/man3/seccomp_api_set.3.html).
///
/// # Arguments
///
/// * `level` - The API level
///
/// # Errors
///
/// If the API level can not be detected due to the library being older than v2.4.0,
/// an error will be returned.
///
/// # Examples
///
/// ```
/// # use libseccomp::*;
/// set_api(1)?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn set_api(level: u32) -> Result<()> {
    cvt(unsafe { seccomp_api_set(level) })?;

    Ok(())
}

/// Gets the API level supported by the system.
///
/// See the [`seccomp_api_get(3)`] man page for details on available API levels.
///
/// [`seccomp_api_get(3)`]: https://www.man7.org/linux/man-pages/man3/seccomp_api_get.3.html
///
/// This function corresponds to
/// [`seccomp_api_get`](https://www.man7.org/linux/man-pages/man3/seccomp_api_get.3.html).
///
/// # Examples
///
/// ```
/// # use libseccomp::*;
/// set_api(1)?;
/// assert_eq!(get_api(), 1);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn get_api() -> u32 {
    unsafe { seccomp_api_get() }
}

/// Checks that both the libseccomp API level and the libseccomp version being
/// used are equal to or greater than the specified API level and version.
///
/// This function returns `Ok(true)` if both the libseccomp API level and the
/// libseccomp version are equal to or greater than the specified API level and
/// version, `Ok(false)` otherwise.
///
/// # Arguments
///
/// * `min_level` - The libseccomp API level you want to check
/// * `expected` - The libseccomp version you want to check
///
/// # Errors
///
/// If an issue is encountered getting the current API level or version,
/// an error will be returned.
///
/// # Examples
///
/// ```
/// # use libseccomp::*;
/// assert!(check_api(3, ScmpVersion::from((2, 4, 0)))?);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn check_api(min_level: u32, expected: ScmpVersion) -> Result<bool> {
    let level = get_api();

    if level >= min_level && check_version(expected)? {
        Ok(true)
    } else {
        Ok(false)
    }
}

/// Ensures that both the libseccomp API level and the libseccomp version are
/// equal to or greater than the specified API level and version.
///
/// # Arguments
///
/// * `msg` - An arbitrary non-empty operation description, used as a part
/// of the error message returned.
/// * `min_level` - The libseccomp API level you want to check
/// * `expected` - The libseccomp version you want to check
///
/// # Errors
///
/// If the libseccomp API level and the libseccomp version being used are less than
/// the specified version, an error will be returned.
pub(crate) fn ensure_supported_api(msg: &str, min_level: u32, expected: ScmpVersion) -> Result<()> {
    let level = get_api();

    if level >= min_level {
        ensure_supported_version(msg, expected)
    } else {
        let current = ScmpVersion::current()?;
        Err(SeccompError::with_msg(format!(
            "{} requires libseccomp >= {} and API level >= {} (current version: {}, API level: {})",
            msg, expected, min_level, current, level
        )))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ensure_supported_api() {
        assert!(ensure_supported_api("test", 3, ScmpVersion::from((2, 4, 0))).is_ok());
        assert!(ensure_supported_api("test", 100, ScmpVersion::from((2, 4, 0))).is_err());
    }
}