From 532533dd3994ef2047dea770e799831b4c38418e Mon Sep 17 00:00:00 2001 From: Zach Reizner Date: Tue, 10 Sep 2019 15:33:44 -0700 Subject: sys_util: shm: make using names with shared memory more convenient This change adds a string based constructor of `SharedMemory` as well as adding a method for retrieving that name from the underlying file. This change also includes a new anonymous constructor. TEST=cargo test -p sys_util BUG=None Change-Id: Ibd7a28851c8a0f41e595ee35b35f0d06fef1e1d9 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1797187 Reviewed-by: Daniel Verkamp Commit-Queue: Zach Reizner Tested-by: Zach Reizner Tested-by: kokoro --- sys_util/src/shm.rs | 81 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/sys_util/src/shm.rs b/sys_util/src/shm.rs index bb008d9..d158230 100644 --- a/sys_util/src/shm.rs +++ b/sys_util/src/shm.rs @@ -2,14 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use std::ffi::CStr; -use std::fs::File; +use std::ffi::{CStr, CString}; +use std::fs::{read_link, File}; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use libc::{ - self, c_char, c_int, c_long, c_uint, close, fcntl, ftruncate64, off64_t, syscall, F_ADD_SEALS, - F_GET_SEALS, F_SEAL_GROW, F_SEAL_SEAL, F_SEAL_SHRINK, F_SEAL_WRITE, MFD_ALLOW_SEALING, + self, c_char, c_int, c_long, c_uint, close, fcntl, ftruncate64, off64_t, syscall, EINVAL, + F_ADD_SEALS, F_GET_SEALS, F_SEAL_GROW, F_SEAL_SEAL, F_SEAL_SHRINK, F_SEAL_WRITE, + MFD_ALLOW_SEALING, }; use syscall_defines::linux::LinuxSyscall::SYS_memfd_create; @@ -97,6 +98,22 @@ impl MemfdSeals { } impl SharedMemory { + /// Convenience function for `SharedMemory::new` that is always named and accepts a wide variety + /// of string-like types. + /// + /// Note that the given name may not have NUL characters anywhere in it, or this will return an + /// error. + pub fn named>>(name: T) -> Result { + Self::new(Some( + &CString::new(name).map_err(|_| errno::Error::new(EINVAL))?, + )) + } + + /// Convenience function for `SharedMemory::new` that has an arbitrary and unspecified name. + pub fn anon() -> Result { + Self::new(None) + } + /// Creates a new shared memory file descriptor with zero size. /// /// If a name is given, it will appear in `/proc/self/fd/` for the purposes of @@ -176,6 +193,24 @@ impl SharedMemory { self.size = size; Ok(()) } + + /// Reads the name from the underlying file as a `String`. + /// + /// If the underlying file was not created with `SharedMemory::new` or with `memfd_create`, the + /// results are undefined. Because this returns a `String`, the name's bytes are interpreted as + /// utf-8. + pub fn read_name(&self) -> Result { + let fd_path = format!("/proc/self/fd/{}", self.as_raw_fd()); + let link_name = read_link(fd_path)?; + link_name + .to_str() + .map(|s| { + s.trim_start_matches("/memfd:") + .trim_end_matches(" (deleted)") + .to_owned() + }) + .ok_or(errno::Error::new(EINVAL)) + } } impl Read for SharedMemory { @@ -262,18 +297,35 @@ mod tests { use super::*; use std::ffi::CString; - use std::fs::read_link; use data_model::VolatileMemory; use crate::MemoryMapping; + #[test] + fn named() { + if !kernel_has_memfd() { + return; + } + const TEST_NAME: &str = "Name McCool Person"; + let shm = SharedMemory::named(TEST_NAME).expect("failed to create shared memory"); + assert_eq!(shm.read_name(), Ok(TEST_NAME.to_owned())); + } + + #[test] + fn anon() { + if !kernel_has_memfd() { + return; + } + SharedMemory::anon().expect("failed to create shared memory"); + } + #[test] fn new() { if !kernel_has_memfd() { return; } - let shm = SharedMemory::new(None).expect("failed to create shared memory"); + let shm = SharedMemory::anon().expect("failed to create shared memory"); assert_eq!(shm.size(), 0); } @@ -282,7 +334,7 @@ mod tests { if !kernel_has_memfd() { return; } - let mut shm = SharedMemory::new(None).expect("failed to create shared memory"); + let mut shm = SharedMemory::anon().expect("failed to create shared memory"); shm.set_size(1024) .expect("failed to set shared memory size"); assert_eq!(shm.size(), 1024); @@ -293,7 +345,7 @@ mod tests { if !kernel_has_memfd() { return; } - let mut shm = SharedMemory::new(None).expect("failed to create shared memory"); + let mut shm = SharedMemory::anon().expect("failed to create shared memory"); shm.set_size(0x7fff_ffff_ffff_ffff) .expect("failed to set shared memory size"); assert_eq!(shm.size(), 0x7fff_ffff_ffff_ffff); @@ -304,7 +356,7 @@ mod tests { if !kernel_has_memfd() { return; } - let mut shm = SharedMemory::new(None).expect("failed to create shared memory"); + let mut shm = SharedMemory::anon().expect("failed to create shared memory"); shm.set_size(0x8000_0000_0000_0000).unwrap_err(); assert_eq!(shm.size(), 0); } @@ -317,10 +369,7 @@ mod tests { let name = "very unique name"; let cname = CString::new(name).unwrap(); let shm = SharedMemory::new(Some(&cname)).expect("failed to create shared memory"); - let fd_path = format!("/proc/self/fd/{}", shm.as_raw_fd()); - let link_name = - read_link(fd_path).expect("failed to read link of shared memory /proc/self/fd entry"); - assert!(link_name.to_str().unwrap().contains(name)); + assert_eq!(shm.read_name(), Ok(name.to_owned())); } #[test] @@ -328,7 +377,7 @@ mod tests { if !kernel_has_memfd() { return; } - let mut shm = SharedMemory::new(None).expect("failed to create shared memory"); + let mut shm = SharedMemory::anon().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(); @@ -344,7 +393,7 @@ mod tests { if !kernel_has_memfd() { return; } - let mut shm = SharedMemory::new(None).expect("failed to create shared memory"); + let mut shm = SharedMemory::anon().expect("failed to create shared memory"); shm.set_size(4096) .expect("failed to set shared memory size"); @@ -373,7 +422,7 @@ mod tests { if !kernel_has_memfd() { return; } - let mut shm = SharedMemory::new(None).expect("failed to create shared memory"); + let mut shm = SharedMemory::anon().expect("failed to create shared memory"); shm.set_size(8092) .expect("failed to set shared memory size"); -- cgit 1.4.1