oci_spec/runtime/
miscellaneous.rs

1use crate::error::OciSpecError;
2use derive_builder::Builder;
3use getset::{CopyGetters, Getters, MutGetters, Setters};
4use serde::{Deserialize, Serialize};
5use std::path::PathBuf;
6
7#[derive(
8    Builder, Clone, CopyGetters, Debug, Deserialize, Eq, Getters, Setters, PartialEq, Serialize,
9)]
10#[builder(
11    default,
12    pattern = "owned",
13    setter(into, strip_option),
14    build_fn(error = "OciSpecError")
15)]
16/// Root contains information about the container's root filesystem on the
17/// host.
18pub struct Root {
19    /// Path is the absolute path to the container's root filesystem.
20    #[serde(default)]
21    #[getset(get = "pub", set = "pub")]
22    path: PathBuf,
23
24    /// Readonly makes the root filesystem for the container readonly before
25    /// the process is executed.
26    #[serde(default, skip_serializing_if = "Option::is_none")]
27    #[getset(get_copy = "pub", set = "pub")]
28    readonly: Option<bool>,
29}
30
31/// Default path for container root is "./rootfs" from config.json, with
32/// readonly true
33impl Default for Root {
34    fn default() -> Self {
35        Root {
36            path: PathBuf::from("rootfs"),
37            readonly: true.into(),
38        }
39    }
40}
41
42#[derive(
43    Builder,
44    Clone,
45    Debug,
46    Default,
47    Deserialize,
48    Eq,
49    Getters,
50    MutGetters,
51    Setters,
52    PartialEq,
53    Serialize,
54)]
55#[builder(
56    default,
57    pattern = "owned",
58    setter(into, strip_option),
59    build_fn(error = "OciSpecError")
60)]
61#[getset(get_mut = "pub", get = "pub", set = "pub")]
62/// Mount specifies a mount for a container.
63pub struct Mount {
64    /// Destination is the absolute path where the mount will be placed in
65    /// the container.
66    destination: PathBuf,
67
68    #[serde(default, skip_serializing_if = "Option::is_none", rename = "type")]
69    /// Type specifies the mount kind.
70    typ: Option<String>,
71
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    /// Source specifies the source path of the mount.
74    source: Option<PathBuf>,
75
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    /// Options are fstab style mount options.
78    options: Option<Vec<String>>,
79}
80
81/// utility function to generate default config for mounts.
82pub fn get_default_mounts() -> Vec<Mount> {
83    vec![
84        Mount {
85            destination: PathBuf::from("/proc"),
86            typ: "proc".to_string().into(),
87            source: PathBuf::from("proc").into(),
88            options: None,
89        },
90        Mount {
91            destination: PathBuf::from("/dev"),
92            typ: "tmpfs".to_string().into(),
93            source: PathBuf::from("tmpfs").into(),
94            options: vec![
95                "nosuid".into(),
96                "strictatime".into(),
97                "mode=755".into(),
98                "size=65536k".into(),
99            ]
100            .into(),
101        },
102        Mount {
103            destination: PathBuf::from("/dev/pts"),
104            typ: "devpts".to_string().into(),
105            source: PathBuf::from("devpts").into(),
106            options: vec![
107                "nosuid".into(),
108                "noexec".into(),
109                "newinstance".into(),
110                "ptmxmode=0666".into(),
111                "mode=0620".into(),
112                "gid=5".into(),
113            ]
114            .into(),
115        },
116        Mount {
117            destination: PathBuf::from("/dev/shm"),
118            typ: "tmpfs".to_string().into(),
119            source: PathBuf::from("shm").into(),
120            options: vec![
121                "nosuid".into(),
122                "noexec".into(),
123                "nodev".into(),
124                "mode=1777".into(),
125                "size=65536k".into(),
126            ]
127            .into(),
128        },
129        Mount {
130            destination: PathBuf::from("/dev/mqueue"),
131            typ: "mqueue".to_string().into(),
132            source: PathBuf::from("mqueue").into(),
133            options: vec!["nosuid".into(), "noexec".into(), "nodev".into()].into(),
134        },
135        Mount {
136            destination: PathBuf::from("/sys"),
137            typ: "sysfs".to_string().into(),
138            source: PathBuf::from("sysfs").into(),
139            options: vec![
140                "nosuid".into(),
141                "noexec".into(),
142                "nodev".into(),
143                "ro".into(),
144            ]
145            .into(),
146        },
147        Mount {
148            destination: PathBuf::from("/sys/fs/cgroup"),
149            typ: "cgroup".to_string().into(),
150            source: PathBuf::from("cgroup").into(),
151            options: vec![
152                "nosuid".into(),
153                "noexec".into(),
154                "nodev".into(),
155                "relatime".into(),
156                "ro".into(),
157            ]
158            .into(),
159        },
160    ]
161}
162
163/// utility function to generate default rootless config for mounts.
164// TODO(saschagrunert): remove once clippy does not report this false positive any more. We cannot
165// use `inspect` instead of `map` because we need to mutate the mounts.
166// Ref: https://github.com/rust-lang/rust-clippy/issues/13185
167#[allow(clippy::manual_inspect)]
168pub fn get_rootless_mounts() -> Vec<Mount> {
169    let mut mounts = get_default_mounts();
170    mounts
171        .iter_mut()
172        .find(|m| m.destination.to_string_lossy() == "/dev/pts")
173        .map(|m| {
174            if let Some(opts) = &mut m.options {
175                opts.retain(|o| o != "gid=5")
176            }
177            m
178        });
179    mounts
180        .iter_mut()
181        .find(|m| m.destination.to_string_lossy() == "/sys")
182        .map(|m| {
183            m.typ = Some("none".to_string());
184            m.source = Some("/sys".into());
185            if let Some(o) = m.options.as_mut() {
186                o.push("rbind".to_string())
187            }
188            m
189        });
190    mounts
191}