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
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::path::PathBuf;

use serde::Deserialize;
use serde::Serialize;
use serde_keyvalue::FromKeyValues;

fn jail_config_default_pivot_root() -> PathBuf {
    PathBuf::from(option_env!("DEFAULT_PIVOT_ROOT").unwrap_or("/var/empty"))
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, FromKeyValues)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub struct JailConfig {
    #[serde(default = "jail_config_default_pivot_root")]
    pub pivot_root: PathBuf,
    #[cfg(any(target_os = "android", target_os = "linux"))]
    #[serde(default)]
    pub seccomp_policy_dir: Option<PathBuf>,
    #[serde(default)]
    pub seccomp_log_failures: bool,
}

impl Default for JailConfig {
    fn default() -> Self {
        JailConfig {
            pivot_root: jail_config_default_pivot_root(),
            #[cfg(any(target_os = "android", target_os = "linux"))]
            seccomp_policy_dir: None,
            seccomp_log_failures: false,
        }
    }
}

#[cfg(test)]
mod tests {
    use serde_keyvalue::from_key_values;

    use super::*;

    #[test]
    fn parse_jailconfig() {
        let config: JailConfig = Default::default();
        assert_eq!(
            config,
            JailConfig {
                pivot_root: jail_config_default_pivot_root(),
                #[cfg(any(target_os = "android", target_os = "linux"))]
                seccomp_policy_dir: None,
                seccomp_log_failures: false,
            }
        );

        let config: JailConfig = from_key_values("").unwrap();
        assert_eq!(config, Default::default());

        let config: JailConfig = from_key_values("pivot-root=/path/to/pivot/root").unwrap();
        assert_eq!(
            config,
            JailConfig {
                pivot_root: "/path/to/pivot/root".into(),
                ..Default::default()
            }
        );

        cfg_if::cfg_if! {
            if #[cfg(any(target_os = "android", target_os = "linux"))] {
                let config: JailConfig =
                    from_key_values("seccomp-policy-dir=/path/to/seccomp/dir").unwrap();
                assert_eq!(config, JailConfig {
                    seccomp_policy_dir: Some("/path/to/seccomp/dir".into()),
                    ..Default::default()
                });
            }
        }

        let config: JailConfig = from_key_values("seccomp-log-failures").unwrap();
        assert_eq!(
            config,
            JailConfig {
                seccomp_log_failures: true,
                ..Default::default()
            }
        );

        let config: JailConfig = from_key_values("seccomp-log-failures=false").unwrap();
        assert_eq!(
            config,
            JailConfig {
                seccomp_log_failures: false,
                ..Default::default()
            }
        );

        let config: JailConfig =
            from_key_values("pivot-root=/path/to/pivot/root,seccomp-log-failures=true").unwrap();
        #[allow(clippy::needless_update)]
        let expected = JailConfig {
            pivot_root: "/path/to/pivot/root".into(),
            seccomp_log_failures: true,
            ..Default::default()
        };
        assert_eq!(config, expected);

        let config: std::result::Result<JailConfig, _> =
            from_key_values("seccomp-log-failures,invalid-arg=value");
        assert!(config.is_err());
    }
}