Skip to content

Commit

Permalink
Support recursive mount attrs by using mount_setattr(2).
Browse files Browse the repository at this point in the history
Signed-off-by: higuruchi <[email protected]>
  • Loading branch information
higuruchi committed Dec 6, 2022
1 parent 3a6d105 commit 7e886ad
Show file tree
Hide file tree
Showing 9 changed files with 507 additions and 201 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/libcontainer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ rust-criu = "0.2.0"
wasmer = { version = "2.2.0", optional = true }
wasmer-wasi = { version = "2.3.0", optional = true }
wasmedge-sdk = { version = "0.7.1", optional = true }
openat = "0.1.21"

[dev-dependencies]
oci-spec = { version = "0.5.8", features = ["proptests", "runtime"] }
Expand Down
113 changes: 84 additions & 29 deletions crates/libcontainer/src/rootfs/mount.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#[cfg(feature = "v1")]
use super::symlink::Symlink;
use super::utils::{find_parent_mount, parse_mount};
use super::utils::{find_parent_mount, parse_mount, MountOptionConfig};
use crate::{
syscall::{syscall::create_syscall, Syscall},
syscall::{linux, syscall::create_syscall, Syscall},
utils,
utils::PathBufExt,
};
Expand All @@ -14,9 +14,13 @@ use libcgroups::common::CgroupSetup::{Hybrid, Legacy, Unified};
use libcgroups::common::DEFAULT_CGROUP_ROOT;
use nix::{errno::Errno, mount::MsFlags};
use oci_spec::runtime::{Mount as SpecMount, MountBuilder as SpecMountBuilder};
use openat::Dir;
use procfs::process::{MountInfo, MountOptFields, Process};
use std::fs::{canonicalize, create_dir_all, OpenOptions};
use std::mem;
use std::os::unix::io::AsRawFd;
use std::path::{Path, PathBuf};

#[cfg(feature = "v1")]
use std::{borrow::Cow, collections::HashMap};

Expand Down Expand Up @@ -46,7 +50,7 @@ impl Mount {

pub fn setup_mount(&self, mount: &SpecMount, options: &MountOptions) -> Result<()> {
log::debug!("Mounting {:?}", mount);
let (flags, data) = parse_mount(mount);
let mut mount_option_config = parse_mount(mount);

match mount.typ().as_deref() {
Some("cgroup") => {
Expand All @@ -64,24 +68,29 @@ impl Mount {
#[cfg(not(feature = "v2"))]
panic!("libcontainer can't run in a Unified cgroup setup without the v2 feature");
#[cfg(feature = "v2")]
self.mount_cgroup_v2(mount, options, flags, &data)
self.mount_cgroup_v2(mount, options, &mount_option_config)
.context("failed to mount cgroup v2")?
}
}
}
_ => {
if *mount.destination() == PathBuf::from("/dev") {
mount_option_config.flags &= !MsFlags::MS_RDONLY;
self.mount_into_container(
mount,
options.root,
flags & !MsFlags::MS_RDONLY,
&data,
&mount_option_config,
options.label,
)
.with_context(|| format!("failed to mount /dev: {:?}", mount))?;
} else {
self.mount_into_container(mount, options.root, flags, &data, options.label)
.with_context(|| format!("failed to mount: {:?}", mount))?;
self.mount_into_container(
mount,
options.root,
&mount_option_config,
options.label,
)
.with_context(|| format!("failed to mount: {:?}", mount))?;
}
}
}
Expand Down Expand Up @@ -197,11 +206,16 @@ impl Mount {
subsystem_name.into()
};

let mount_options_config = MountOptionConfig {
flags: MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID | MsFlags::MS_NODEV,
data: data.to_string(),
rec_attr: None,
};

self.mount_into_container(
&subsystem_mount,
options.root,
MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID | MsFlags::MS_NODEV,
&data,
&mount_options_config,
options.label,
)
.with_context(|| format!("failed to mount {:?}", subsystem_mount))
Expand Down Expand Up @@ -271,8 +285,7 @@ impl Mount {
&self,
cgroup_mount: &SpecMount,
options: &MountOptions,
flags: MsFlags,
data: &str,
mount_option_config: &MountOptionConfig,
) -> Result<()> {
log::debug!("Mounting cgroup v2 filesystem");

Expand All @@ -285,7 +298,12 @@ impl Mount {
log::debug!("{:?}", cgroup_mount);

if self
.mount_into_container(&cgroup_mount, options.root, flags, data, options.label)
.mount_into_container(
&cgroup_mount,
options.root,
mount_option_config,
options.label,
)
.context("failed to mount into container")
.is_err()
{
Expand All @@ -309,11 +327,12 @@ impl Mount {
.context("failed to build cgroup bind mount")?;
log::debug!("{:?}", bind_mount);

let mut mount_option_config = (*mount_option_config).clone();
mount_option_config.flags |= MsFlags::MS_BIND;
self.mount_into_container(
&bind_mount,
options.root,
flags | MsFlags::MS_BIND,
data,
&mount_option_config,
options.label,
)
.context("failed to bind mount cgroup hierarchy")?;
Expand Down Expand Up @@ -351,18 +370,17 @@ impl Mount {
&self,
m: &SpecMount,
rootfs: &Path,
flags: MsFlags,
data: &str,
mount_option_config: &MountOptionConfig,
label: Option<&str>,
) -> Result<()> {
let typ = m.typ().as_deref();
let mut d = data.to_string();
let mut d = mount_option_config.data.to_string();

if let Some(l) = label {
if typ != Some("proc") && typ != Some("sysfs") {
match data.is_empty() {
match mount_option_config.data.is_empty() {
true => d = format!("context=\"{}\"", l),
false => d = format!("{},context=\"{}\"", data, l),
false => d = format!("{},context=\"{}\"", mount_option_config.data, l),
}
}
}
Expand Down Expand Up @@ -402,20 +420,29 @@ impl Mount {
PathBuf::from(source)
};

if let Err(err) = self.syscall.mount(Some(&*src), dest, typ, flags, Some(&*d)) {
if let Err(err) =
self.syscall
.mount(Some(&*src), dest, typ, mount_option_config.flags, Some(&*d))
{
if let Some(errno) = err.downcast_ref() {
if !matches!(errno, Errno::EINVAL) {
bail!("mount of {:?} failed. {}", m.destination(), errno);
}
}

self.syscall
.mount(Some(&*src), dest, typ, flags, Some(data))
.mount(
Some(&*src),
dest,
typ,
mount_option_config.flags,
Some(&mount_option_config.data),
)
.with_context(|| format!("failed to mount {:?} to {:?}", src, dest))?;
}

if typ == Some("bind")
&& flags.intersects(
&& mount_option_config.flags.intersects(
!(MsFlags::MS_REC
| MsFlags::MS_REMOUNT
| MsFlags::MS_BIND
Expand All @@ -425,10 +452,28 @@ impl Mount {
)
{
self.syscall
.mount(Some(dest), dest, None, flags | MsFlags::MS_REMOUNT, None)
.mount(
Some(dest),
dest,
None,
mount_option_config.flags | MsFlags::MS_REMOUNT,
None,
)
.with_context(|| format!("Failed to remount: {:?}", dest))?;
}

if let Some(mount_attr) = &mount_option_config.rec_attr {
let open_dir = Dir::open(dest)?;
let dir_fd_pathbuf = PathBuf::from(format!("/proc/self/fd/{}", open_dir.as_raw_fd()));
self.syscall.mount_setattr(
-1,
&dir_fd_pathbuf,
linux::AT_RECURSIVE,
mount_attr,
mem::size_of::<linux::MountAttr>(),
)?;
}

Ok(())
}
}
Expand Down Expand Up @@ -462,10 +507,15 @@ mod tests {
])
.build()
.unwrap();
let (flags, data) = parse_mount(mount);
let mount_option_config = parse_mount(mount);

assert!(m
.mount_into_container(mount, tmp_dir.path(), flags, &data, Some("defaults"))
.mount_into_container(
mount,
tmp_dir.path(),
&mount_option_config,
Some("defaults")
)
.is_ok());

let want = vec![MountArgs {
Expand Down Expand Up @@ -495,15 +545,15 @@ mod tests {
.options(vec!["ro".to_string()])
.build()
.unwrap();
let (flags, data) = parse_mount(mount);
let mount_option_config = parse_mount(mount);
OpenOptions::new()
.create(true)
.write(true)
.open(tmp_dir.path().join("null"))
.unwrap();

assert!(m
.mount_into_container(mount, tmp_dir.path(), flags, &data, None)
.mount_into_container(mount, tmp_dir.path(), &mount_option_config, None)
.is_ok());

let want = vec![
Expand Down Expand Up @@ -768,8 +818,13 @@ mod tests {
let flags = MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID | MsFlags::MS_NODEV;

// act
let mount_option_config = MountOptionConfig {
flags,
data: String::new(),
rec_attr: None,
};
mounter
.mount_cgroup_v2(&spec_cgroup_mount, &mount_opts, flags, "")
.mount_cgroup_v2(&spec_cgroup_mount, &mount_opts, &mount_option_config)
.context("failed to mount cgroup v2")?;

// assert
Expand Down
Loading

0 comments on commit 7e886ad

Please sign in to comment.