mirror of
https://github.com/containers/youki
synced 2024-06-09 00:06:18 +02:00
Support 'shared' and 'unbindable' rootfs propagations
This commit is contained in:
parent
825088992a
commit
c1281066ad
|
@ -47,7 +47,7 @@ test_cases=(
|
|||
"linux_ns_path_type/linux_ns_path_type.t"
|
||||
# "linux_process_apparmor_profile/linux_process_apparmor_profile.t"
|
||||
"linux_readonly_paths/linux_readonly_paths.t"
|
||||
# "linux_rootfs_propagation/linux_rootfs_propagation.t"
|
||||
"linux_rootfs_propagation/linux_rootfs_propagation.t"
|
||||
"linux_seccomp/linux_seccomp.t"
|
||||
"linux_sysctl/linux_sysctl.t"
|
||||
"linux_uid_mappings/linux_uid_mappings.t"
|
||||
|
|
|
@ -248,6 +248,8 @@ pub fn container_init(
|
|||
.with_context(|| format!("Failed to chroot to {:?}", rootfs))?;
|
||||
}
|
||||
|
||||
rootfs::adjust_root_mount_propagation(spec)?;
|
||||
|
||||
if let Some(kernel_params) = &linux.sysctl {
|
||||
sysctl(kernel_params)
|
||||
.with_context(|| format!("Failed to sysctl: {:?}", kernel_params))?;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//! Most systems mount another filesystem over it
|
||||
|
||||
use crate::utils::PathBufExt;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::{open, OFlag};
|
||||
use nix::mount::mount as nix_mount;
|
||||
|
@ -11,7 +11,9 @@ use nix::sys::stat::{mknod, umask};
|
|||
use nix::sys::stat::{Mode, SFlag};
|
||||
use nix::unistd::{chown, close};
|
||||
use nix::unistd::{Gid, Uid};
|
||||
use nix::NixPath;
|
||||
use oci_spec::runtime::{LinuxDevice, LinuxDeviceType, Mount, Spec};
|
||||
use procfs::process::{MountInfo, MountOptFields, Process};
|
||||
use std::fs::OpenOptions;
|
||||
use std::fs::{canonicalize, create_dir_all, remove_file};
|
||||
use std::os::unix::fs::symlink;
|
||||
|
@ -26,6 +28,7 @@ pub fn prepare_rootfs(spec: &Spec, rootfs: &Path, bind_devices: bool) -> Result<
|
|||
"shared" => flags |= MsFlags::MS_SHARED,
|
||||
"private" => flags |= MsFlags::MS_PRIVATE,
|
||||
"slave" => flags |= MsFlags::MS_SLAVE,
|
||||
"unbindable" => flags |= MsFlags::MS_SLAVE, // set unbindable after pivot_root
|
||||
uknown => bail!("unknown rootfs_propagation: {}", uknown),
|
||||
}
|
||||
} else {
|
||||
|
@ -35,6 +38,8 @@ pub fn prepare_rootfs(spec: &Spec, rootfs: &Path, bind_devices: bool) -> Result<
|
|||
nix_mount(None::<&str>, "/", None::<&str>, flags, None::<&str>)
|
||||
.context("Failed to mount rootfs")?;
|
||||
|
||||
make_parent_mount_private(rootfs)?;
|
||||
|
||||
log::debug!("mount root fs {:?}", rootfs);
|
||||
nix_mount::<Path, Path, str, str>(
|
||||
Some(rootfs),
|
||||
|
@ -387,3 +392,55 @@ fn parse_mount(m: &Mount) -> (MsFlags, String) {
|
|||
}
|
||||
(flags, data.join(","))
|
||||
}
|
||||
|
||||
fn get_parent_mount(rootfs: &Path) -> Result<MountInfo> {
|
||||
let mount_infos = Process::myself()?.mountinfo()?;
|
||||
// find the longest mount point
|
||||
let parent_mount_info = mount_infos
|
||||
.into_iter()
|
||||
.filter(|mi| rootfs.starts_with(&mi.mount_point))
|
||||
.max_by(|mi1, mi2| mi1.mount_point.len().cmp(&mi2.mount_point.len()))
|
||||
.ok_or_else(|| anyhow!("couldn't find parent mount of {}", rootfs.display()))?;
|
||||
Ok(parent_mount_info)
|
||||
}
|
||||
|
||||
/// Make parent mount of rootfs private if it was shared, which is required by pivot_root.
|
||||
/// It also makes sure following bind mount does not propagate in other namespaces.
|
||||
fn make_parent_mount_private(rootfs: &Path) -> Result<()> {
|
||||
let parent_mount = get_parent_mount(rootfs)?;
|
||||
|
||||
// check parent mount has 'shared' propagation type
|
||||
if parent_mount
|
||||
.opt_fields
|
||||
.iter()
|
||||
.any(|field| matches!(field, MountOptFields::Shared(_)))
|
||||
{
|
||||
nix_mount(
|
||||
None::<&str>,
|
||||
&parent_mount.mount_point,
|
||||
None::<&str>,
|
||||
MsFlags::MS_PRIVATE,
|
||||
None::<&str>,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Change propagation type of rootfs as specified in spec.
|
||||
pub fn adjust_root_mount_propagation(spec: &Spec) -> Result<()> {
|
||||
let linux = spec.linux.as_ref().context("no linux in spec")?;
|
||||
let rootfs_propagation = linux.rootfs_propagation.as_deref();
|
||||
let flags = match rootfs_propagation {
|
||||
Some("shared") => Some(MsFlags::MS_SHARED),
|
||||
Some("unbindable") => Some(MsFlags::MS_UNBINDABLE),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(flags) = flags {
|
||||
log::debug!("make root mount {:?}", flags);
|
||||
nix_mount(None::<&str>, "/", None::<&str>, flags, None::<&str>)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use nix::{
|
|||
unistd::{Gid, Uid},
|
||||
};
|
||||
use nix::{
|
||||
mount::{umount2, MntFlags},
|
||||
mount::{mount, umount2, MntFlags, MsFlags},
|
||||
unistd,
|
||||
};
|
||||
use nix::{sched::unshare, sys::stat::Mode};
|
||||
|
@ -68,6 +68,16 @@ impl Syscall for LinuxSyscall {
|
|||
// directory to put original root directory.
|
||||
pivot_root(path, path)?;
|
||||
|
||||
// Make the original root directory rslave to avoid propagating unmount event to the host mount namespace.
|
||||
// We should use MS_SLAVE not MS_PRIVATE according to https://github.com/opencontainers/runc/pull/1500.
|
||||
mount(
|
||||
None::<&str>,
|
||||
"/",
|
||||
None::<&str>,
|
||||
MsFlags::MS_SLAVE | MsFlags::MS_REC,
|
||||
None::<&str>,
|
||||
)?;
|
||||
|
||||
// Unmount the original root directory which was stacked on top of new root directory
|
||||
// MNT_DETACH makes the mount point unavailable to new accesses, but waits till the original mount point
|
||||
// to be free of activity to actually unmount
|
||||
|
|
Loading…
Reference in New Issue