mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-28 19:29:20 +00:00
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:
parent
a13839564c
commit
d42e493143
3 changed files with 126 additions and 17 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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; }
|
||||
|
|
Loading…
Reference in a new issue