mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-28 19:54:35 +00:00
rustjail: fix the issue of missing set propagation for bind mount
When do bind mount for container's volumes, the propagation flags should be mount/set after bind mount. Fixes: #530 Signed-off-by: fupan.lfp <fupan.lfp@antfin.com>
This commit is contained in:
parent
50c76b696f
commit
58dfd50317
@ -32,6 +32,7 @@ use crate::log_child;
|
|||||||
|
|
||||||
// Info reveals information about a particular mounted filesystem. This
|
// Info reveals information about a particular mounted filesystem. This
|
||||||
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
||||||
|
#[derive(std::fmt::Debug)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
id: i32,
|
id: i32,
|
||||||
parent: i32,
|
parent: i32,
|
||||||
@ -51,9 +52,12 @@ const MOUNTINFOFORMAT: &'static str = "{d} {d} {d}:{d} {} {} {} {}";
|
|||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref PROPAGATION: HashMap<&'static str, MsFlags> = {
|
static ref PROPAGATION: HashMap<&'static str, MsFlags> = {
|
||||||
let mut m = HashMap::new();
|
let mut m = HashMap::new();
|
||||||
m.insert("shared", MsFlags::MS_SHARED | MsFlags::MS_REC);
|
m.insert("shared", MsFlags::MS_SHARED);
|
||||||
m.insert("private", MsFlags::MS_PRIVATE | MsFlags::MS_REC);
|
m.insert("rshared", MsFlags::MS_SHARED | MsFlags::MS_REC);
|
||||||
m.insert("slave", MsFlags::MS_SLAVE | MsFlags::MS_REC);
|
m.insert("private", MsFlags::MS_PRIVATE);
|
||||||
|
m.insert("rprivate", MsFlags::MS_PRIVATE | MsFlags::MS_REC);
|
||||||
|
m.insert("slave", MsFlags::MS_SLAVE);
|
||||||
|
m.insert("rslave", MsFlags::MS_SLAVE | MsFlags::MS_REC);
|
||||||
m
|
m
|
||||||
};
|
};
|
||||||
static ref OPTIONS: HashMap<&'static str, (bool, MsFlags)> = {
|
static ref OPTIONS: HashMap<&'static str, (bool, MsFlags)> = {
|
||||||
@ -121,6 +125,9 @@ pub fn init_rootfs(
|
|||||||
let rootfs = root.to_str().unwrap();
|
let rootfs = root.to_str().unwrap();
|
||||||
|
|
||||||
mount::mount(None::<&str>, "/", None::<&str>, flags, None::<&str>)?;
|
mount::mount(None::<&str>, "/", None::<&str>, flags, None::<&str>)?;
|
||||||
|
|
||||||
|
rootfs_parent_mount_private(rootfs)?;
|
||||||
|
|
||||||
mount::mount(
|
mount::mount(
|
||||||
Some(rootfs),
|
Some(rootfs),
|
||||||
rootfs,
|
rootfs,
|
||||||
@ -142,6 +149,18 @@ pub fn init_rootfs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mount_from(cfd_log, &m, &rootfs, flags, &data, "")?;
|
mount_from(cfd_log, &m, &rootfs, flags, &data, "")?;
|
||||||
|
// bind mount won't change mount options, we need remount to make mount options
|
||||||
|
// effective.
|
||||||
|
// first check that we have non-default options required before attempting a
|
||||||
|
// remount
|
||||||
|
if m.r#type == "bind" {
|
||||||
|
for o in &m.options {
|
||||||
|
if let Some(fl) = PROPAGATION.get(o.as_str()) {
|
||||||
|
let dest = format!("{}{}", &rootfs, &m.destination);
|
||||||
|
mount::mount(None::<&str>, dest.as_str(), None::<&str>, *fl, None::<&str>)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,18 +281,71 @@ fn mount_cgroups(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pivot_rootfs<P: ?Sized + NixPath>(path: &P) -> Result<()> {
|
pub fn pivot_rootfs<P: ?Sized + NixPath + std::fmt::Debug>(path: &P) -> Result<()> {
|
||||||
let oldroot = fcntl::open("/", OFlag::O_DIRECTORY | OFlag::O_RDONLY, Mode::empty())?;
|
let oldroot = fcntl::open("/", OFlag::O_DIRECTORY | OFlag::O_RDONLY, Mode::empty())?;
|
||||||
defer!(unistd::close(oldroot).unwrap());
|
defer!(unistd::close(oldroot).unwrap());
|
||||||
let newroot = fcntl::open(path, OFlag::O_DIRECTORY | OFlag::O_RDONLY, Mode::empty())?;
|
let newroot = fcntl::open(path, OFlag::O_DIRECTORY | OFlag::O_RDONLY, Mode::empty())?;
|
||||||
defer!(unistd::close(newroot).unwrap());
|
defer!(unistd::close(newroot).unwrap());
|
||||||
unistd::pivot_root(path, path)?;
|
|
||||||
mount::umount2("/", MntFlags::MNT_DETACH)?;
|
// Change to the new root so that the pivot_root actually acts on it.
|
||||||
unistd::fchdir(newroot)?;
|
unistd::fchdir(newroot)?;
|
||||||
|
unistd::pivot_root(".", ".").chain_err(|| format!("failed to pivot_root on {:?}", path))?;
|
||||||
|
|
||||||
|
// Currently our "." is oldroot (according to the current kernel code).
|
||||||
|
// However, purely for safety, we will fchdir(oldroot) since there isn't
|
||||||
|
// really any guarantee from the kernel what /proc/self/cwd will be after a
|
||||||
|
// pivot_root(2).
|
||||||
|
unistd::fchdir(oldroot)?;
|
||||||
|
|
||||||
|
// Make oldroot rslave to make sure our unmounts don't propagate to the
|
||||||
|
// host. We don't use rprivate because this is known to cause issues due
|
||||||
|
// to races where we still have a reference to a mount while a process in
|
||||||
|
// the host namespace are trying to operate on something they think has no
|
||||||
|
// mounts (devicemapper in particular).
|
||||||
|
mount::mount(
|
||||||
|
Some("none"),
|
||||||
|
".",
|
||||||
|
Some(""),
|
||||||
|
MsFlags::MS_SLAVE | MsFlags::MS_REC,
|
||||||
|
Some(""),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd.
|
||||||
|
mount::umount2(".", MntFlags::MNT_DETACH).chain_err(|| "failed to do umount2")?;
|
||||||
|
|
||||||
|
// Switch back to our shiny new root.
|
||||||
|
unistd::chdir("/")?;
|
||||||
stat::umask(Mode::from_bits_truncate(0o022));
|
stat::umask(Mode::from_bits_truncate(0o022));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rootfs_parent_mount_private(path: &str) -> Result<()> {
|
||||||
|
let mount_infos = parse_mount_table()?;
|
||||||
|
|
||||||
|
let mut max_len = 0;
|
||||||
|
let mut mount_point = String::from("");
|
||||||
|
let mut options = String::from("");
|
||||||
|
for i in mount_infos {
|
||||||
|
if path.starts_with(&i.mount_point) && i.mount_point.len() > max_len {
|
||||||
|
max_len = i.mount_point.len();
|
||||||
|
mount_point = i.mount_point;
|
||||||
|
options = i.optional;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.contains("shared:") {
|
||||||
|
mount::mount(
|
||||||
|
None::<&str>,
|
||||||
|
mount_point.as_str(),
|
||||||
|
None::<&str>,
|
||||||
|
MsFlags::MS_PRIVATE,
|
||||||
|
None::<&str>,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
||||||
// bind mounts
|
// bind mounts
|
||||||
fn parse_mount_table() -> Result<Vec<Info>> {
|
fn parse_mount_table() -> Result<Vec<Info>> {
|
||||||
|
Loading…
Reference in New Issue
Block a user