mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-31 14:39:06 +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",
|
"io_jail 0.1.0",
|
||||||
"kernel_loader 0.1.0",
|
"kernel_loader 0.1.0",
|
||||||
"kvm 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",
|
"sys_util 0.1.0",
|
||||||
"vm_control 0.1.0",
|
"vm_control 0.1.0",
|
||||||
"x86_64 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)",
|
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"data_model 0.1.0",
|
"data_model 0.1.0",
|
||||||
"io_jail 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_sys 0.1.0",
|
||||||
"net_util 0.1.0",
|
"net_util 0.1.0",
|
||||||
"sys_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"
|
name = "io_jail"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
name = "kernel_loader"
|
name = "kernel_loader"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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",
|
"sys_util 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ name = "kvm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kvm_sys 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",
|
"sys_util 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -72,13 +72,13 @@ dependencies = [
|
||||||
name = "kvm_sys"
|
name = "kvm_sys"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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",
|
"sys_util 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.32"
|
version = "0.2.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -92,7 +92,7 @@ dependencies = [
|
||||||
name = "net_util"
|
name = "net_util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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",
|
"net_sys 0.1.0",
|
||||||
"sys_util 0.1.0",
|
"sys_util 0.1.0",
|
||||||
]
|
]
|
||||||
|
@ -103,7 +103,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data_model 0.1.0",
|
"data_model 0.1.0",
|
||||||
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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",
|
"syscall_defines 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ version = "0.1.0"
|
||||||
name = "vhost"
|
name = "vhost"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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",
|
"net_util 0.1.0",
|
||||||
"sys_util 0.1.0",
|
"sys_util 0.1.0",
|
||||||
"virtio_sys 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)",
|
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"data_model 0.1.0",
|
"data_model 0.1.0",
|
||||||
"kvm 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",
|
"sys_util 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -147,11 +147,11 @@ dependencies = [
|
||||||
"data_model 0.1.0",
|
"data_model 0.1.0",
|
||||||
"kvm 0.1.0",
|
"kvm 0.1.0",
|
||||||
"kvm_sys 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",
|
"sys_util 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
|
"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 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" }
|
kvm = { path = "kvm" }
|
||||||
sys_util = { path = "sys_util" }
|
sys_util = { path = "sys_util" }
|
||||||
kernel_loader = { path = "kernel_loader" }
|
kernel_loader = { path = "kernel_loader" }
|
||||||
libc = "=0.2.32"
|
libc = "=0.2.34"
|
||||||
byteorder = "=1.1.0"
|
byteorder = "=1.1.0"
|
||||||
vm_control = { path = "vm_control" }
|
vm_control = { path = "vm_control" }
|
||||||
data_model = { path = "data_model" }
|
data_model = { path = "data_model" }
|
||||||
|
|
|
@ -7,7 +7,9 @@ use std::fs::File;
|
||||||
use std::io::{Seek, SeekFrom};
|
use std::io::{Seek, SeekFrom};
|
||||||
use std::os::unix::io::{AsRawFd, IntoRawFd, FromRawFd, RawFd};
|
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 errno;
|
||||||
use syscall_defines::linux::LinuxSyscall::SYS_memfd_create;
|
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
|
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 {
|
impl SharedMemory {
|
||||||
/// Creates a new shared memory file descriptor with zero size.
|
/// 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
|
/// 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.
|
/// 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> {
|
pub fn new(name: Option<&CStr>) -> Result<SharedMemory> {
|
||||||
let shm_name = name.map(|n| n.as_ptr())
|
let shm_name = name.map(|n| n.as_ptr())
|
||||||
.unwrap_or(b"/crosvm_shm\0".as_ptr() as *const c_char);
|
.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
|
// The following are safe because we give a valid C string and check the
|
||||||
// results of the memfd_create call.
|
// 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 {
|
if fd < 0 {
|
||||||
return errno_result();
|
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.
|
/// 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
|
/// 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));
|
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]
|
#[test]
|
||||||
fn mmap_page() {
|
fn mmap_page() {
|
||||||
if !kernel_has_memfd() { return; }
|
if !kernel_has_memfd() { return; }
|
||||||
|
|
Loading…
Reference in a new issue