summary refs log tree commit diff
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2019-09-10 15:33:44 -0700
committerCommit Bot <commit-bot@chromium.org>2019-09-11 09:34:10 +0000
commit532533dd3994ef2047dea770e799831b4c38418e (patch)
tree55bc1b06dedb5ec839b0f95ad0bb85be9708a766
parent0b86007d3e1ee400c6201c00b7dea323d661b50f (diff)
downloadcrosvm-532533dd3994ef2047dea770e799831b4c38418e.tar
crosvm-532533dd3994ef2047dea770e799831b4c38418e.tar.gz
crosvm-532533dd3994ef2047dea770e799831b4c38418e.tar.bz2
crosvm-532533dd3994ef2047dea770e799831b4c38418e.tar.lz
crosvm-532533dd3994ef2047dea770e799831b4c38418e.tar.xz
crosvm-532533dd3994ef2047dea770e799831b4c38418e.tar.zst
crosvm-532533dd3994ef2047dea770e799831b4c38418e.zip
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 <dverkamp@chromium.org>
Commit-Queue: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
-rw-r--r--sys_util/src/shm.rs81
1 files 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<T: Into<Vec<u8>>>(name: T) -> Result<SharedMemory> {
+        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<SharedMemory> {
+        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/<shm 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<String> {
+        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");