sys_util: add memfd seal support to SharedMemory

Getting and settings seals is useful to ensure the size of files
underlying memory mappings doesn't shrink, which can trigger a SIGBUS on
access to the truncated pages.

This also bumps the libc version to get MFD_ALLOW_SEALING.

TEST=cargo test
BUG=None
CQ-DEPEND=CL:850535

Change-Id: Ifbe1ec2c47d3d5c51b63472f545acc10d3c8eed2
Reviewed-on: https://chromium-review.googlesource.com/849488
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
Zach Reizner 2018-01-03 15:21:04 -08:00 committed by chrome-bot
parent a13839564c
commit d42e493143
3 changed files with 126 additions and 17 deletions

26
Cargo.lock generated
View file

@ -13,7 +13,7 @@ dependencies = [
"io_jail 0.1.0",
"kernel_loader 0.1.0",
"kvm 0.1.0",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"sys_util 0.1.0",
"vm_control 0.1.0",
"x86_64 0.1.0",
@ -30,7 +30,7 @@ dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"data_model 0.1.0",
"io_jail 0.1.0",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"net_sys 0.1.0",
"net_util 0.1.0",
"sys_util 0.1.0",
@ -48,14 +48,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "io_jail"
version = "0.1.0"
dependencies = [
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel_loader"
version = "0.1.0"
dependencies = [
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"sys_util 0.1.0",
]
@ -64,7 +64,7 @@ name = "kvm"
version = "0.1.0"
dependencies = [
"kvm_sys 0.1.0",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"sys_util 0.1.0",
]
@ -72,13 +72,13 @@ dependencies = [
name = "kvm_sys"
version = "0.1.0"
dependencies = [
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"sys_util 0.1.0",
]
[[package]]
name = "libc"
version = "0.2.32"
version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -92,7 +92,7 @@ dependencies = [
name = "net_util"
version = "0.1.0"
dependencies = [
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"net_sys 0.1.0",
"sys_util 0.1.0",
]
@ -103,7 +103,7 @@ version = "0.1.0"
dependencies = [
"data_model 0.1.0",
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"syscall_defines 0.1.0",
]
@ -115,7 +115,7 @@ version = "0.1.0"
name = "vhost"
version = "0.1.0"
dependencies = [
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"net_util 0.1.0",
"sys_util 0.1.0",
"virtio_sys 0.1.0",
@ -135,7 +135,7 @@ dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"data_model 0.1.0",
"kvm 0.1.0",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"sys_util 0.1.0",
]
@ -147,11 +147,11 @@ dependencies = [
"data_model 0.1.0",
"kvm 0.1.0",
"kvm_sys 0.1.0",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"sys_util 0.1.0",
]
[metadata]
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148"
"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0"

View file

@ -15,7 +15,7 @@ io_jail = { path = "io_jail" }
kvm = { path = "kvm" }
sys_util = { path = "sys_util" }
kernel_loader = { path = "kernel_loader" }
libc = "=0.2.32"
libc = "=0.2.34"
byteorder = "=1.1.0"
vm_control = { path = "vm_control" }
data_model = { path = "data_model" }

View file

@ -7,7 +7,9 @@ use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::os::unix::io::{AsRawFd, IntoRawFd, FromRawFd, RawFd};
use libc::{self, off64_t, c_long, c_int, c_uint, c_char, close, syscall, ftruncate64};
use libc::{self, off64_t, c_long, c_int, c_uint, c_char, close, syscall, ftruncate64, fcntl,
F_ADD_SEALS, F_GET_SEALS, F_SEAL_GROW, F_SEAL_SHRINK, F_SEAL_WRITE, F_SEAL_SEAL,
MFD_ALLOW_SEALING};
use errno;
use syscall_defines::linux::LinuxSyscall::SYS_memfd_create;
@ -27,19 +29,87 @@ unsafe fn memfd_create(name: *const c_char, flags: c_uint) -> c_int {
syscall(SYS_memfd_create as c_long, name as i64, flags as i64) as c_int
}
/// A set of memfd seals.
///
/// An enumeration of each bit can be found at `fcntl(2)`.
#[derive(Copy, Clone)]
pub struct MemfdSeals(i32);
impl MemfdSeals {
/// Returns an empty set of memfd seals.
#[inline]
pub fn new() -> MemfdSeals {
MemfdSeals(0)
}
/// Gets the raw bitmask of seals enumerated in `fcntl(2)`.
#[inline]
pub fn bitmask(self) -> i32 {
self.0
}
/// True of the grow seal bit is present.
#[inline]
pub fn grow_seal(self) -> bool {
self.0 & F_SEAL_GROW != 0
}
/// Sets the grow seal bit.
#[inline]
pub fn set_grow_seal(&mut self) {
self.0 |= F_SEAL_GROW;
}
/// True of the shrink seal bit is present.
#[inline]
pub fn shrink_seal(self) -> bool {
self.0 & F_SEAL_SHRINK != 0
}
/// Sets the shrink seal bit.
#[inline]
pub fn set_shrink_seal(&mut self) {
self.0 |= F_SEAL_SHRINK;
}
/// True of the write seal bit is present.
#[inline]
pub fn write_seal(self) -> bool {
self.0 & F_SEAL_WRITE != 0
}
/// Sets the write seal bit.
#[inline]
pub fn set_write_seal(&mut self) {
self.0 |= F_SEAL_WRITE;
}
/// True of the seal seal bit is present.
#[inline]
pub fn seal_seal(self) -> bool {
self.0 & F_SEAL_SEAL != 0
}
/// Sets the seal seal bit.
#[inline]
pub fn set_seal_seal(&mut self) {
self.0 |= F_SEAL_SEAL;
}
}
impl SharedMemory {
/// Creates a new shared memory file descriptor with zero size.
///
/// If a name is given, it will appear in `/proc/self/fd/<shm fd>` for the purposes of
/// debugging. The name does not need to be unique.
///
/// The file descriptor is opened with the close on exec flag.
/// The file descriptor is opened with the close on exec flag and allows memfd sealing.
pub fn new(name: Option<&CStr>) -> Result<SharedMemory> {
let shm_name = name.map(|n| n.as_ptr())
.unwrap_or(b"/crosvm_shm\0".as_ptr() as *const c_char);
// The following are safe because we give a valid C string and check the
// results of the memfd_create call.
let fd = unsafe { memfd_create(shm_name, MFD_CLOEXEC) };
let fd = unsafe { memfd_create(shm_name, MFD_CLOEXEC | MFD_ALLOW_SEALING) };
if fd < 0 {
return errno_result();
}
@ -63,6 +133,29 @@ impl SharedMemory {
})
}
/// Gets the memfd seals that have already been added to this.
///
/// This may fail if this instance was not constructed from a memfd.
pub fn get_seals(&self) -> Result<MemfdSeals> {
let ret = unsafe { fcntl(self.fd.as_raw_fd(), F_GET_SEALS) };
if ret < 0 {
return errno_result();
}
Ok(MemfdSeals(ret))
}
/// Adds the given set of memfd seals.
///
/// This may fail if this instance was not constructed from a memfd with sealing allowed or if
/// the seal seal (`F_SEAL_SEAL`) bit was already added.
pub fn add_seals(&mut self, seals: MemfdSeals) -> Result<()> {
let ret = unsafe { fcntl(self.fd.as_raw_fd(), F_ADD_SEALS, seals) };
if ret < 0 {
return errno_result();
}
Ok(())
}
/// Gets the size in bytes of the shared memory.
///
/// The size returned here does not reflect changes by other interfaces or users of the shared
@ -165,6 +258,22 @@ mod tests {
assert!(link_name.to_str().unwrap().contains(name));
}
#[test]
fn new_sealed() {
if !kernel_has_memfd() {
return;
}
let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
let mut seals = shm.get_seals().expect("failed to get seals");
assert_eq!(seals.bitmask(), 0);
seals.set_seal_seal();
shm.add_seals(seals).expect("failed to add seals");
seals = shm.get_seals().expect("failed to get seals");
assert!(seals.seal_seal());
// Adding more seals should be rejected by the kernel.
shm.add_seals(seals).unwrap_err();
}
#[test]
fn mmap_page() {
if !kernel_has_memfd() { return; }