summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDavid Riley <davidriley@chromium.org>2018-08-20 08:11:42 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-09-17 13:18:06 -0700
commitb22b6137aa398223daf54b66f8229119c301225b (patch)
tree74b0a58b44a5adb75fccc8b493c55bdc61bd57e4 /src
parent9fbac2cf59eb87bff7ab423076d63a6b89c91bd8 (diff)
downloadcrosvm-b22b6137aa398223daf54b66f8229119c301225b.tar
crosvm-b22b6137aa398223daf54b66f8229119c301225b.tar.gz
crosvm-b22b6137aa398223daf54b66f8229119c301225b.tar.bz2
crosvm-b22b6137aa398223daf54b66f8229119c301225b.tar.lz
crosvm-b22b6137aa398223daf54b66f8229119c301225b.tar.xz
crosvm-b22b6137aa398223daf54b66f8229119c301225b.tar.zst
crosvm-b22b6137aa398223daf54b66f8229119c301225b.zip
gpu: add sandboxing via minijail for virtio gpu device.
Sandboxing only works when started as chronos via concierge client.  If
started directly via crosvm as root, the jail will not have proper group
permissions to access the Wayland socket.

BUG=chromium:837073
TEST=build with --features=gpu; null_platform_test without --disable-sandbox
CQ-DEPEND=CL:1213779

Change-Id: I6331f7ae1f5b99d31ad44cf158f72337294771f0
Reviewed-on: https://chromium-review.googlesource.com/1181168
Commit-Ready: David Riley <davidriley@chromium.org>
Tested-by: David Riley <davidriley@chromium.org>
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'src')
-rw-r--r--src/linux.rs90
1 files changed, 79 insertions, 11 deletions
diff --git a/src/linux.rs b/src/linux.rs
index a858129..a142d1d 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -441,17 +441,85 @@ fn create_virtio_devs(cfg: VirtIoDeviceInfo,
     #[cfg(feature = "gpu")]
     {
         if cfg.gpu {
-            let gpu_box =
-                Box::new(devices::virtio::Gpu::new(_exit_evt
-                                                       .try_clone()
-                                                       .map_err(Error::CloneEventFd)?));
-            let jail = if cfg.multiprocess {
-                error!("jail for virtio-gpu is unimplemented");
-                unimplemented!();
-            } else {
-                None
-            };
-            devs.push(VirtioDeviceStub {dev: gpu_box, jail});
+            if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() {
+                let jailed_wayland_path = Path::new("/wayland-0");
+
+                let gpu_box =
+                    Box::new(devices::virtio::Gpu::new(_exit_evt
+                                                        .try_clone()
+                                                        .map_err(Error::CloneEventFd)?,
+                                                    if cfg.multiprocess {
+                                                        &jailed_wayland_path
+                                                    } else {
+                                                        wayland_socket_path.as_path()
+                                                    }));
+
+                let jail = if cfg.multiprocess {
+                    let policy_path: PathBuf = cfg.seccomp_policy_dir.join("gpu_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
+                    // dri 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();
+
+                    // Device nodes required for DRM.
+                    let sys_dev_char_path = Path::new("/sys/dev/char");
+                    jail.mount_bind(sys_dev_char_path, sys_dev_char_path, false)
+                        .unwrap();
+                    let sys_devices_path = Path::new("/sys/devices");
+                    jail.mount_bind(sys_devices_path, sys_devices_path, false)
+                        .unwrap();
+                    let drm_dri_path = Path::new("/dev/dri");
+                    jail.mount_bind(drm_dri_path, drm_dri_path, false)
+                        .unwrap();
+
+                    // Libraries that are required when mesa drivers are dynamically loaded.
+                    let lib_path = Path::new("/lib64");
+                    jail.mount_bind(lib_path, lib_path, false)
+                        .unwrap();
+                    let usr_lib_path = Path::new("/usr/lib64");
+                    jail.mount_bind(usr_lib_path, usr_lib_path, false)
+                        .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)
+                        .unwrap();
+
+                    // Set the uid/gid for the jailed process, and give a basic id map. This
+                    // is required for the above bind mount to work.
+                    let crosvm_user_group = CStr::from_bytes_with_nul(b"crosvm\0").unwrap();
+                    let crosvm_uid = match get_user_id(&crosvm_user_group) {
+                        Ok(u) => u,
+                        Err(e) => {
+                            warn!("falling back to current user id for gpu: {:?}", e);
+                            geteuid()
+                        }
+                    };
+                    let crosvm_gid = match get_group_id(&crosvm_user_group) {
+                        Ok(u) => u,
+                        Err(e) => {
+                            warn!("falling back to current group id for gpu: {:?}", e);
+                            getegid()
+                        }
+                    };
+                    jail.change_uid(crosvm_uid);
+                    jail.change_gid(crosvm_gid);
+                    jail.uidmap(&format!("{0} {0} 1", crosvm_uid))
+                        .map_err(Error::SettingUidMap)?;
+                    jail.gidmap(&format!("{0} {0} 1", crosvm_gid))
+                        .map_err(Error::SettingGidMap)?;
+
+                    Some(jail)
+                } else {
+                    None
+                };
+                devs.push(VirtioDeviceStub {dev: gpu_box, jail});
+            }
         }
     }