diff options
author | Chirantan Ekbote <chirantan@chromium.org> | 2018-05-31 15:31:31 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-06-12 00:36:27 -0700 |
commit | 5f787217cc48e526c6244cd39db4f944fadfcd88 (patch) | |
tree | 8d3160c83c19c3ef3356502a3b18603b1de05ec3 /src/linux.rs | |
parent | 92068bca00d7499dc789527b90efdf3daed2e927 (diff) | |
download | crosvm-5f787217cc48e526c6244cd39db4f944fadfcd88.tar crosvm-5f787217cc48e526c6244cd39db4f944fadfcd88.tar.gz crosvm-5f787217cc48e526c6244cd39db4f944fadfcd88.tar.bz2 crosvm-5f787217cc48e526c6244cd39db4f944fadfcd88.tar.lz crosvm-5f787217cc48e526c6244cd39db4f944fadfcd88.tar.xz crosvm-5f787217cc48e526c6244cd39db4f944fadfcd88.tar.zst crosvm-5f787217cc48e526c6244cd39db4f944fadfcd88.zip |
net: Allow passing in a configured tap fd on the command line
Allow the process that spawned crosvm to pass in a configured tap file descriptor for networking. If this option is provided then crosvm will ignore the other networking related command line flags (like mac address, netmask, etc). Passing in a configured tap device allows us to run crosvm without having to give it CAP_NET_ADMIN. BUG=none TEST=Start a container and verify that networking still works Change-Id: I70b9e6ae030d66c4882e4e48804dc2f29d9874ba Signed-off-by: Chirantan Ekbote <chirantan@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1081394 Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'src/linux.rs')
-rw-r--r-- | src/linux.rs | 60 |
1 files changed, 41 insertions, 19 deletions
diff --git a/src/linux.rs b/src/linux.rs index eb85659..8950dfc 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -191,6 +191,27 @@ impl Drop for UnlinkUnixDatagram { } } +// Verifies that |raw_fd| is actually owned by this process and duplicates it to ensure that +// we have a unique handle to it. +fn validate_raw_fd(raw_fd: RawFd) -> Result<RawFd> { + // Checking that close-on-exec isn't set helps filter out FDs that were opened by + // crosvm as all crosvm FDs are close on exec. + // Safe because this doesn't modify any memory and we check the return value. + let flags = unsafe { libc::fcntl(raw_fd, libc::F_GETFD) }; + if flags < 0 || (flags & libc::FD_CLOEXEC) != 0 { + return Err(Error::FailedCLOEXECCheck); + } + + // Duplicate the fd to ensure that we don't accidentally close an fd previously + // opened by another subsystem. Safe because this doesn't modify any memory and + // we check the return value. + let dup_fd = unsafe { libc::fcntl(raw_fd, libc::F_DUPFD_CLOEXEC, 0) }; + if dup_fd < 0 { + return Err(Error::FailedToDupFd); + } + Ok(dup_fd as RawFd) +} + fn create_base_minijail(root: &Path, seccomp_policy: &Path) -> Result<Minijail> { // All child jails run in a new user namespace without any users mapped, // they run as nobody unless otherwise configured. @@ -248,24 +269,8 @@ fn setup_mmio_bus(cfg: &Config, .and_then(|fd_osstr| fd_osstr.to_str()) .and_then(|fd_str| fd_str.parse::<c_int>().ok()) .ok_or(Error::InvalidFdPath)?; - unsafe { - // The FD is valid and this process owns it because it exists in /proc/self/fd. - // Ensure |raw_image| is the only owner by first duping it then closing the - // original. - // Checking that close-on-exec isn't set helps filter out FDs that were opened by - // crosvm as all crosvm FDs are close on exec. - let flags = libc::fcntl(raw_fd, libc::F_GETFD); - if flags < 0 || (flags & libc::FD_CLOEXEC) != 0 { - return Err(Error::FailedCLOEXECCheck); - } - - let dup_fd = libc::fcntl(raw_fd, libc::F_DUPFD_CLOEXEC, 0) as RawFd; - if dup_fd < 0 { - return Err(Error::FailedToDupFd); - } - libc::close(raw_fd); - File::from_raw_fd(dup_fd) - } + // Safe because we will validate |raw_fd|. + unsafe { File::from_raw_fd(validate_raw_fd(raw_fd)?) } } else { OpenOptions::new() .read(true) @@ -329,7 +334,24 @@ fn setup_mmio_bus(cfg: &Config, .map_err(Error::RegisterBalloon)?; // We checked above that if the IP is defined, then the netmask is, too. - if let Some(host_ip) = cfg.host_ip { + if let Some(tap_fd) = cfg.tap_fd { + // Safe because we ensure that we get a unique handle to the fd. + let tap = unsafe { Tap::from_raw_fd(validate_raw_fd(tap_fd)?) }; + let net_box = Box::new(devices::virtio::Net::from(tap) + .map_err(|e| Error::NetDeviceNew(e))?); + + let jail = if cfg.multiprocess { + let policy_path: PathBuf = cfg.seccomp_policy_dir.join("net_device.policy"); + + Some(create_base_minijail(empty_root_path, &policy_path)?) + } else { + None + }; + + device_manager + .register_mmio(net_box, jail, cmdline) + .map_err(Error::RegisterNet)?; + } else if let Some(host_ip) = cfg.host_ip { if let Some(netmask) = cfg.netmask { if let Some(mac_address) = cfg.mac_address { let net_box: Box<devices::virtio::VirtioDevice> = if cfg.vhost_net { |