linux: bind wayland directory in virtio-wayland sandbox

For example, if the wayland socket is given as /run/wayland-0, the
entire /run/ directory will be bind mounted into the sandbox as
/wayland/. The wayland device will then be told to open the socket at
/wayland/wayland-0. If the /run/wayland-0 file is removed and a new
socket is opened in its place, as in a chrome crash, the
/wayland/wayland-0 socket will open the new socket rather than the one
belonging to the expire process.

TEST=vmc start termina; chrome://inducebrowsercrashforrealz;
    vsh termina; start wayland application
BUG=chromium:884398

Change-Id: I259eb2f7e29ee6b61836133ec1c3a110c5575957
Reviewed-on: https://chromium-review.googlesource.com/1227063
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
This commit is contained in:
Zach Reizner 2018-09-14 15:43:33 -07:00 committed by chrome-bot
parent a99954cb7c
commit 579bd2cf0e

View file

@ -65,6 +65,7 @@ pub enum Error {
FailedCLOEXECCheck,
FailedToDupFd,
InvalidFdPath,
InvalidWaylandPath,
NetDeviceNew(devices::virtio::NetError),
NoVarEmpty,
OpenKernel(PathBuf, io::Error),
@ -119,6 +120,9 @@ impl fmt::Display for Error {
}
&Error::FailedToDupFd => write!(f, "failed to dup fd from /proc/self/fd"),
&Error::InvalidFdPath => write!(f, "failed parsing a /proc/self/fd/*"),
&Error::InvalidWaylandPath => {
write!(f, "wayland socket path has no parent or file name")
}
&Error::NetDeviceNew(ref e) => write!(f, "failed to set up virtio networking: {:?}", e),
&Error::NoVarEmpty => write!(f, "/var/empty doesn't exist, can't jail devices."),
&Error::OpenKernel(ref p, ref e) => {
@ -363,7 +367,10 @@ fn create_virtio_devs(cfg: VirtIoDeviceInfo,
}
if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() {
let jailed_wayland_path = Path::new("/wayland-0");
let wayland_socket_dir = wayland_socket_path.parent().ok_or(Error::InvalidWaylandPath)?;
let wayland_socket_name = wayland_socket_path.file_name().ok_or(Error::InvalidWaylandPath)?;
let jailed_wayland_dir = Path::new("/wayland");
let jailed_wayland_path = jailed_wayland_dir.join(wayland_socket_name);
let wl_box = Box::new(devices::virtio::Wl::new(if cfg.multiprocess {
&jailed_wayland_path
@ -377,16 +384,18 @@ fn create_virtio_devs(cfg: VirtIoDeviceInfo,
let policy_path: PathBuf = cfg.seccomp_policy_dir.join("wl_device.policy");
let mut jail = create_base_minijail(empty_root_path, &policy_path)?;
// Create a tmpfs in the device's root directory so that we can bind mount the
// wayland socket into it. The size=67108864 is size=64*1024*1024 or size=64MB.
// Create a tmpfs in the device's root directory so that we can bind mount the wayland
// socket directory into it. The size=67108864 is size=64*1024*1024 or size=64MB.
jail.mount_with_data(Path::new("none"), Path::new("/"), "tmpfs",
(libc::MS_NOSUID | libc::MS_NODEV | libc::MS_NOEXEC) as usize,
"size=67108864")
.unwrap();
// Bind mount the wayland socket into jail's root. This is necessary since each
// new wayland context must open() the socket.
jail.mount_bind(wayland_socket_path.as_path(), jailed_wayland_path, true)
// Bind mount the wayland socket's directory into jail's root. This is necessary since
// each new wayland context must open() the socket. If the wayland socket is ever
// destroyed and remade in the same host directory, new connections will be possible
// without restarting the wayland device.
jail.mount_bind(wayland_socket_dir, jailed_wayland_dir, true)
.unwrap();
// Set the uid/gid for the jailed process, and give a basic id map. This