diff options
-rw-r--r-- | devices/src/virtio/wl.rs | 87 | ||||
-rw-r--r-- | seccomp/aarch64/wl_device.policy | 4 | ||||
-rw-r--r-- | seccomp/x86_64/wl_device.policy | 8 |
3 files changed, 94 insertions, 5 deletions
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs index 956163e..dc736de 100644 --- a/devices/src/virtio/wl.rs +++ b/devices/src/virtio/wl.rs @@ -38,6 +38,8 @@ use std::fmt; use std::fs::File; use std::io::{self, Seek, SeekFrom, Read}; use std::mem::{size_of, size_of_val}; +#[cfg(feature = "wl-dmabuf")] +use std::os::raw::{c_uint, c_ulonglong}; use std::os::unix::io::{AsRawFd, RawFd}; #[cfg(feature = "wl-dmabuf")] use std::os::unix::io::FromRawFd; @@ -51,7 +53,7 @@ use std::thread; use std::time::Duration; #[cfg(feature = "wl-dmabuf")] -use libc::dup; +use libc::{dup, EBADF, EINVAL}; use data_model::*; use data_model::VolatileMemoryError; @@ -59,6 +61,9 @@ use data_model::VolatileMemoryError; use sys_util::{Error, Result, EventFd, Scm, SharedMemory, GuestAddress, GuestMemory, GuestMemoryError, PollContext, PollToken, FileFlags, pipe}; +#[cfg(feature = "wl-dmabuf")] +use sys_util::ioctl_with_ref; + use vm_control::{VmControlError, VmRequest, VmResponse, MaybeOwnedFd, GpuMemoryDesc}; use super::{VirtioDevice, Queue, DescriptorChain, INTERRUPT_STATUS_USED_RING, TYPE_WL}; @@ -72,6 +77,8 @@ const VIRTIO_WL_CMD_VFD_NEW_PIPE: u32 = 261; const VIRTIO_WL_CMD_VFD_HUP: u32 = 262; #[cfg(feature = "wl-dmabuf")] const VIRTIO_WL_CMD_VFD_NEW_DMABUF: u32 = 263; +#[cfg(feature = "wl-dmabuf")] +const VIRTIO_WL_CMD_VFD_DMABUF_SYNC: u32 = 264; const VIRTIO_WL_RESP_OK: u32 = 4096; const VIRTIO_WL_RESP_VFD_NEW: u32 = 4097; #[cfg(feature = "wl-dmabuf")] @@ -95,6 +102,22 @@ const NEXT_VFD_ID_BASE: u32 = 0x40000000; const VFD_ID_HOST_MASK: u32 = NEXT_VFD_ID_BASE; const IN_BUFFER_LEN: usize = 4080; +#[cfg(feature = "wl-dmabuf")] +const VIRTIO_WL_VFD_DMABUF_SYNC_VALID_FLAG_MASK: u32 = 0x7; + +#[cfg(feature = "wl-dmabuf")] +const DMA_BUF_IOCTL_BASE: c_uint = 0x62; + +#[cfg(feature = "wl-dmabuf")] +#[repr(C)] +#[derive(Copy, Clone)] +struct dma_buf_sync { + flags: c_ulonglong, +} + +#[cfg(feature = "wl-dmabuf")] +ioctl_iow_nr!(DMA_BUF_IOCTL_SYNC, DMA_BUF_IOCTL_BASE, 0, dma_buf_sync); + const PAGE_MASK: u64 = 0x0fff; fn round_to_page_size(v: u64) -> u64 { @@ -158,6 +181,20 @@ fn parse_new_dmabuf(addr: GuestAddress, mem: &GuestMemory) -> WlResult<WlOp> { }) } +#[cfg(feature = "wl-dmabuf")] +fn parse_dmabuf_sync(addr: GuestAddress, mem: &GuestMemory) -> WlResult<WlOp> { + const ID_OFFSET: u64 = 8; + const FLAGS_OFFSET: u64 = 12; + let id: Le32 = mem.read_obj_from_addr(mem.checked_offset(addr, ID_OFFSET) + .ok_or(WlError::CheckedOffset)?)?; + let flags: Le32 = + mem.read_obj_from_addr(mem.checked_offset(addr, FLAGS_OFFSET) + .ok_or(WlError::CheckedOffset)?)?; + Ok(WlOp::DmabufSync { + id: id.into(), + flags: flags.into(), + }) +} fn parse_send(addr: GuestAddress, len: u32, mem: &GuestMemory) -> WlResult<WlOp> { const ID_OFFSET: u64 = 8; @@ -200,6 +237,8 @@ fn parse_desc(desc: &DescriptorChain, mem: &GuestMemory) -> WlResult<WlOp> { VIRTIO_WL_CMD_VFD_NEW_PIPE => parse_new_pipe(desc.addr, mem), #[cfg(feature = "wl-dmabuf")] VIRTIO_WL_CMD_VFD_NEW_DMABUF => parse_new_dmabuf(desc.addr, mem), + #[cfg(feature = "wl-dmabuf")] + VIRTIO_WL_CMD_VFD_DMABUF_SYNC => parse_dmabuf_sync(desc.addr, mem), v => Ok(WlOp::InvalidCommand { op_type: v }), } } @@ -350,6 +389,7 @@ enum WlError { RecvVfd(Error), ReadPipe(io::Error), PollContextAdd(Error), + DmabufSync(io::Error), } impl fmt::Display for WlError { @@ -376,6 +416,7 @@ impl error::Error for WlError { WlError::RecvVfd(_) => "Failed to recv on a socket", WlError::ReadPipe(_) => "Failed to read a pipe", WlError::PollContextAdd(_) => "Failed to listen to FD on poll context", + WlError::DmabufSync(_) => "Failed to synchronize DMABuf access", } } } @@ -490,6 +531,8 @@ enum WlOp { NewPipe { id: u32, flags: u32 }, #[cfg(feature = "wl-dmabuf")] NewDmabuf { id: u32, width: u32, height: u32, format: u32 }, + #[cfg(feature = "wl-dmabuf")] + DmabufSync { id: u32, flags: u32 }, InvalidCommand { op_type: u32 }, } @@ -560,6 +603,8 @@ struct WlVfd { remote_pipe: Option<File>, local_pipe: Option<(u32 /* flags */, File)>, slot: Option<(u32 /* slot */, u64 /* pfn */, VmRequester)>, + #[cfg(feature = "wl-dmabuf")] + is_dmabuf: bool, } impl fmt::Debug for WlVfd { @@ -630,12 +675,35 @@ impl WlVfd { let vfd_shm = SharedMemory::from_raw_fd(raw_fd).map_err(WlError::NewAlloc)?; vfd.guest_shared_memory = Some((vfd_shm.size(), vfd_shm.into())); vfd.slot = Some((slot, pfn, vm)); + vfd.is_dmabuf = true; Ok((vfd, desc)) } _ => Err(WlError::VmBadResponse), } } + #[cfg(feature = "wl-dmabuf")] + fn dmabuf_sync(&self, flags: u32) -> WlResult<()> { + if !self.is_dmabuf { + return Err(WlError::DmabufSync(io::Error::from_raw_os_error(EINVAL))); + } + + match self.guest_shared_memory.as_ref() { + Some(&(_, ref fd)) => { + let sync = dma_buf_sync { + flags: flags as u64, + }; + // Safe as fd is a valid dmabuf and incorrect flags will return an error. + if unsafe { ioctl_with_ref(fd, DMA_BUF_IOCTL_SYNC(), &sync) } < 0 { + Err(WlError::DmabufSync(io::Error::last_os_error())) + } else { + Ok(()) + } + } + None => Err(WlError::DmabufSync(io::Error::from_raw_os_error(EBADF))) + } + } + fn pipe_remote_read_local_write() -> WlResult<WlVfd> { let (read_pipe, write_pipe) = pipe(true).map_err(WlError::NewPipe)?; let mut vfd = WlVfd::default(); @@ -949,6 +1017,21 @@ impl WlState { } } + #[cfg(feature = "wl-dmabuf")] + fn dmabuf_sync(&mut self, vfd_id: u32, flags: u32) -> WlResult<WlResp> { + if flags & !(VIRTIO_WL_VFD_DMABUF_SYNC_VALID_FLAG_MASK) != 0 { + return Ok(WlResp::InvalidFlags); + } + + match self.vfds.get_mut(&vfd_id) { + Some(vfd) => { + vfd.dmabuf_sync(flags)?; + Ok(WlResp::Ok) + } + None => Ok(WlResp::InvalidId), + } + } + fn new_context(&mut self, id: u32) -> WlResult<WlResp> { if id & VFD_ID_HOST_MASK != 0 { return Ok(WlResp::InvalidId); @@ -1112,6 +1195,8 @@ impl WlState { WlOp::NewPipe { id, flags } => self.new_pipe(id, flags), #[cfg(feature = "wl-dmabuf")] WlOp::NewDmabuf { id, width, height, format } => self.new_dmabuf(id, width, height, format), + #[cfg(feature = "wl-dmabuf")] + WlOp::DmabufSync { id, flags } => self.dmabuf_sync(id, flags), WlOp::InvalidCommand { op_type } => { warn!("unexpected command {}", op_type); Ok(WlResp::InvalidCommand) diff --git a/seccomp/aarch64/wl_device.policy b/seccomp/aarch64/wl_device.policy index 9f21169..52bf028 100644 --- a/seccomp/aarch64/wl_device.policy +++ b/seccomp/aarch64/wl_device.policy @@ -30,8 +30,8 @@ write: 1 eventfd2: 1 # Used to connect to wayland. arg0 == AF_UNIX && arg1 == SOCK_STREAM|SOCK_CLOEXEC socket: arg0 == 1 && arg1 == 0x80001 && arg2 == 0 -# arg1 == FIONBIO -ioctl: arg1 == 0x5421 +# arg1 == FIONBIO || arg1 == DMA_BUF_IOCTL_SYNC +ioctl: arg1 == 0x5421 || arg1 == 0x40086200 connect: arg2 == 13 # Used to communicate with wayland recvmsg: 1 diff --git a/seccomp/x86_64/wl_device.policy b/seccomp/x86_64/wl_device.policy index 045e40f..cb8d6e4 100644 --- a/seccomp/x86_64/wl_device.policy +++ b/seccomp/x86_64/wl_device.policy @@ -1,3 +1,7 @@ +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + close: 1 dup: 1 dup2: 1 @@ -25,8 +29,8 @@ write: 1 eventfd2: 1 # Used to connect to wayland. arg0 == AF_UNIX && arg1 == SOCK_STREAM|SOCK_CLOEXEC socket: arg0 == 1 && arg1 == 0x80001 && arg2 == 0 -# arg1 == FIONBIO -ioctl: arg1 == 0x5421 +# arg1 == FIONBIO || arg1 == DMA_BUF_IOCTL_SYNC +ioctl: arg1 == 0x5421 || arg1 == 0x40086200 connect: arg2 == 13 # Used to communicate with wayland recvmsg: 1 |