• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::{
6     ffi::{CStr, CString},
7     fs::{read_link, File},
8     io::{
9         Read, Seek, SeekFrom, Write, {self},
10     },
11     os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd},
12 };
13 
14 use libc::{
15     c_char, c_int, c_long, c_uint, close, fcntl, ftruncate64, off64_t, syscall, SYS_memfd_create,
16     EINVAL, F_ADD_SEALS, F_GET_SEALS, F_SEAL_FUTURE_WRITE, F_SEAL_GROW, F_SEAL_SEAL, F_SEAL_SHRINK,
17     F_SEAL_WRITE, MFD_ALLOW_SEALING, {self},
18 };
19 use serde::{Deserialize, Serialize};
20 
21 use super::{errno_result, Error, Result};
22 use crate::{AsRawDescriptor, RawDescriptor};
23 
24 /// A shared memory file descriptor and its size.
25 #[derive(Serialize, Deserialize)]
26 pub struct SharedMemory {
27     #[serde(with = "super::with_as_descriptor")]
28     fd: File,
29     size: u64,
30 }
31 
32 // from <sys/memfd.h>
33 const MFD_CLOEXEC: c_uint = 0x0001;
34 
memfd_create(name: *const c_char, flags: c_uint) -> c_int35 unsafe fn memfd_create(name: *const c_char, flags: c_uint) -> c_int {
36     syscall(SYS_memfd_create as c_long, name, flags) as c_int
37 }
38 
39 /// A set of memfd seals.
40 ///
41 /// An enumeration of each bit can be found at `fcntl(2)`.
42 #[derive(Copy, Clone, Default)]
43 pub struct MemfdSeals(i32);
44 
45 impl MemfdSeals {
46     /// Returns an empty set of memfd seals.
47     #[inline]
new() -> MemfdSeals48     pub fn new() -> MemfdSeals {
49         MemfdSeals(0)
50     }
51 
52     /// Gets the raw bitmask of seals enumerated in `fcntl(2)`.
53     #[inline]
bitmask(self) -> i3254     pub fn bitmask(self) -> i32 {
55         self.0
56     }
57 
58     /// True if the grow seal bit is present.
59     #[inline]
grow_seal(self) -> bool60     pub fn grow_seal(self) -> bool {
61         self.0 & F_SEAL_GROW != 0
62     }
63 
64     /// Sets the grow seal bit.
65     #[inline]
set_grow_seal(&mut self)66     pub fn set_grow_seal(&mut self) {
67         self.0 |= F_SEAL_GROW;
68     }
69 
70     /// True if the shrink seal bit is present.
71     #[inline]
shrink_seal(self) -> bool72     pub fn shrink_seal(self) -> bool {
73         self.0 & F_SEAL_SHRINK != 0
74     }
75 
76     /// Sets the shrink seal bit.
77     #[inline]
set_shrink_seal(&mut self)78     pub fn set_shrink_seal(&mut self) {
79         self.0 |= F_SEAL_SHRINK;
80     }
81 
82     /// True if the write seal bit is present.
83     #[inline]
write_seal(self) -> bool84     pub fn write_seal(self) -> bool {
85         self.0 & F_SEAL_WRITE != 0
86     }
87 
88     /// Sets the write seal bit.
89     #[inline]
set_write_seal(&mut self)90     pub fn set_write_seal(&mut self) {
91         self.0 |= F_SEAL_WRITE;
92     }
93 
94     /// True if the future write seal bit is present.
95     #[inline]
future_write_seal(self) -> bool96     pub fn future_write_seal(self) -> bool {
97         self.0 & F_SEAL_FUTURE_WRITE != 0
98     }
99 
100     /// Sets the future write seal bit.
101     #[inline]
set_future_write_seal(&mut self)102     pub fn set_future_write_seal(&mut self) {
103         self.0 |= F_SEAL_FUTURE_WRITE;
104     }
105 
106     /// True of the seal seal bit is present.
107     #[inline]
seal_seal(self) -> bool108     pub fn seal_seal(self) -> bool {
109         self.0 & F_SEAL_SEAL != 0
110     }
111 
112     /// Sets the seal seal bit.
113     #[inline]
set_seal_seal(&mut self)114     pub fn set_seal_seal(&mut self) {
115         self.0 |= F_SEAL_SEAL;
116     }
117 }
118 
119 impl SharedMemory {
120     /// Convenience function for `SharedMemory::new` that is always named and accepts a wide variety
121     /// of string-like types.
122     ///
123     /// Note that the given name may not have NUL characters anywhere in it, or this will return an
124     /// error.
named<T: Into<Vec<u8>>>(name: T) -> Result<SharedMemory>125     pub fn named<T: Into<Vec<u8>>>(name: T) -> Result<SharedMemory> {
126         Self::new(Some(&CString::new(name).map_err(|_| Error::new(EINVAL))?))
127     }
128 
129     /// Convenience function for `SharedMemory::new` that has an arbitrary and unspecified name.
anon() -> Result<SharedMemory>130     pub fn anon() -> Result<SharedMemory> {
131         Self::new(None)
132     }
133 
134     /// Creates a new shared memory file descriptor with zero size.
135     ///
136     /// If a name is given, it will appear in `/proc/self/fd/<shm fd>` for the purposes of
137     /// debugging. The name does not need to be unique.
138     ///
139     /// The file descriptor is opened with the close on exec flag and allows memfd sealing.
new(name: Option<&CStr>) -> Result<SharedMemory>140     pub fn new(name: Option<&CStr>) -> Result<SharedMemory> {
141         let shm_name = name
142             .map(|n| n.as_ptr())
143             .unwrap_or(b"/crosvm_shm\0".as_ptr() as *const c_char);
144         // The following are safe because we give a valid C string and check the
145         // results of the memfd_create call.
146         let fd = unsafe { memfd_create(shm_name, MFD_CLOEXEC | MFD_ALLOW_SEALING) };
147         if fd < 0 {
148             return errno_result();
149         }
150 
151         let file = unsafe { File::from_raw_fd(fd) };
152 
153         Ok(SharedMemory { fd: file, size: 0 })
154     }
155 
156     /// Constructs a `SharedMemory` instance from a `File` that represents shared memory.
157     ///
158     /// The size of the resulting shared memory will be determined using `File::seek`. If the given
159     /// file's size can not be determined this way, this will return an error.
from_file(mut file: File) -> Result<SharedMemory>160     pub fn from_file(mut file: File) -> Result<SharedMemory> {
161         let file_size = file.seek(SeekFrom::End(0))?;
162         Ok(SharedMemory {
163             fd: file,
164             size: file_size as u64,
165         })
166     }
167 
168     /// Gets the memfd seals that have already been added to this.
169     ///
170     /// This may fail if this instance was not constructed from a memfd.
get_seals(&self) -> Result<MemfdSeals>171     pub fn get_seals(&self) -> Result<MemfdSeals> {
172         let ret = unsafe { fcntl(self.fd.as_raw_fd(), F_GET_SEALS) };
173         if ret < 0 {
174             return errno_result();
175         }
176         Ok(MemfdSeals(ret))
177     }
178 
179     /// Adds the given set of memfd seals.
180     ///
181     /// This may fail if this instance was not constructed from a memfd with sealing allowed or if
182     /// the seal seal (`F_SEAL_SEAL`) bit was already added.
add_seals(&mut self, seals: MemfdSeals) -> Result<()>183     pub fn add_seals(&mut self, seals: MemfdSeals) -> Result<()> {
184         let ret = unsafe { fcntl(self.fd.as_raw_fd(), F_ADD_SEALS, seals) };
185         if ret < 0 {
186             return errno_result();
187         }
188         Ok(())
189     }
190 
191     /// Gets the size in bytes of the shared memory.
192     ///
193     /// The size returned here does not reflect changes by other interfaces or users of the shared
194     /// memory file descriptor..
size(&self) -> u64195     pub fn size(&self) -> u64 {
196         self.size
197     }
198 
199     /// Sets the size in bytes of the shared memory.
200     ///
201     /// Note that if some process has already mapped this shared memory and the new size is smaller,
202     /// that process may get signaled with SIGBUS if they access any page past the new size.
set_size(&mut self, size: u64) -> Result<()>203     pub fn set_size(&mut self, size: u64) -> Result<()> {
204         let ret = unsafe { ftruncate64(self.fd.as_raw_fd(), size as off64_t) };
205         if ret < 0 {
206             return errno_result();
207         }
208         self.size = size;
209         Ok(())
210     }
211 
212     /// Reads the name from the underlying file as a `String`.
213     ///
214     /// If the underlying file was not created with `SharedMemory::new` or with `memfd_create`, the
215     /// results are undefined. Because this returns a `String`, the name's bytes are interpreted as
216     /// utf-8.
read_name(&self) -> Result<String>217     pub fn read_name(&self) -> Result<String> {
218         let fd_path = format!("/proc/self/fd/{}", self.as_raw_fd());
219         let link_name = read_link(fd_path)?;
220         link_name
221             .to_str()
222             .map(|s| {
223                 s.trim_start_matches("/memfd:")
224                     .trim_end_matches(" (deleted)")
225                     .to_owned()
226             })
227             .ok_or_else(|| Error::new(EINVAL))
228     }
229 }
230 
231 impl Read for SharedMemory {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>232     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
233         self.fd.read(buf)
234     }
235 }
236 
237 impl Read for &SharedMemory {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>238     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
239         (&self.fd).read(buf)
240     }
241 }
242 
243 impl Write for SharedMemory {
write(&mut self, buf: &[u8]) -> io::Result<usize>244     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
245         self.fd.write(buf)
246     }
247 
flush(&mut self) -> io::Result<()>248     fn flush(&mut self) -> io::Result<()> {
249         self.fd.flush()
250     }
251 }
252 
253 impl Write for &SharedMemory {
write(&mut self, buf: &[u8]) -> io::Result<usize>254     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
255         (&self.fd).write(buf)
256     }
257 
flush(&mut self) -> io::Result<()>258     fn flush(&mut self) -> io::Result<()> {
259         (&self.fd).flush()
260     }
261 }
262 
263 impl Seek for SharedMemory {
seek(&mut self, pos: SeekFrom) -> io::Result<u64>264     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
265         self.fd.seek(pos)
266     }
267 }
268 
269 impl Seek for &SharedMemory {
seek(&mut self, pos: SeekFrom) -> io::Result<u64>270     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
271         (&self.fd).seek(pos)
272     }
273 }
274 
275 impl AsRawFd for SharedMemory {
as_raw_fd(&self) -> RawFd276     fn as_raw_fd(&self) -> RawFd {
277         self.fd.as_raw_fd()
278     }
279 }
280 
281 impl AsRawFd for &SharedMemory {
as_raw_fd(&self) -> RawFd282     fn as_raw_fd(&self) -> RawFd {
283         self.fd.as_raw_fd()
284     }
285 }
286 
287 impl IntoRawFd for SharedMemory {
into_raw_fd(self) -> RawFd288     fn into_raw_fd(self) -> RawFd {
289         self.fd.into_raw_fd()
290     }
291 }
292 
293 impl AsRawDescriptor for SharedMemory {
as_raw_descriptor(&self) -> RawDescriptor294     fn as_raw_descriptor(&self) -> RawDescriptor {
295         self.fd.as_raw_descriptor()
296     }
297 }
298 
299 impl From<SharedMemory> for File {
from(s: SharedMemory) -> File300     fn from(s: SharedMemory) -> File {
301         s.fd
302     }
303 }
304 
305 /// Checks if the kernel we are running on has memfd_create. It was introduced in 3.17.
306 /// Only to be used from tests to prevent running on ancient kernels that won't
307 /// support the functionality anyways.
kernel_has_memfd() -> bool308 pub fn kernel_has_memfd() -> bool {
309     unsafe {
310         let fd = memfd_create(b"/test_memfd_create\0".as_ptr() as *const c_char, 0);
311         if fd < 0 {
312             if Error::last().errno() == libc::ENOSYS {
313                 return false;
314             }
315             return true;
316         }
317         close(fd);
318     }
319     true
320 }
321 
322 #[cfg(test)]
323 mod tests {
324     use super::*;
325 
326     use std::ffi::CString;
327 
328     use data_model::VolatileMemory;
329 
330     use super::super::MemoryMapping;
331 
332     #[test]
named()333     fn named() {
334         if !kernel_has_memfd() {
335             return;
336         }
337         const TEST_NAME: &str = "Name McCool Person";
338         let shm = SharedMemory::named(TEST_NAME).expect("failed to create shared memory");
339         assert_eq!(shm.read_name(), Ok(TEST_NAME.to_owned()));
340     }
341 
342     #[test]
anon()343     fn anon() {
344         if !kernel_has_memfd() {
345             return;
346         }
347         SharedMemory::anon().expect("failed to create shared memory");
348     }
349 
350     #[test]
new()351     fn new() {
352         if !kernel_has_memfd() {
353             return;
354         }
355         let shm = SharedMemory::anon().expect("failed to create shared memory");
356         assert_eq!(shm.size(), 0);
357     }
358 
359     #[test]
new_sized()360     fn new_sized() {
361         if !kernel_has_memfd() {
362             return;
363         }
364         let mut shm = SharedMemory::anon().expect("failed to create shared memory");
365         shm.set_size(1024)
366             .expect("failed to set shared memory size");
367         assert_eq!(shm.size(), 1024);
368     }
369 
370     #[test]
new_huge()371     fn new_huge() {
372         if !kernel_has_memfd() {
373             return;
374         }
375         let mut shm = SharedMemory::anon().expect("failed to create shared memory");
376         shm.set_size(0x7fff_ffff_ffff_ffff)
377             .expect("failed to set shared memory size");
378         assert_eq!(shm.size(), 0x7fff_ffff_ffff_ffff);
379     }
380 
381     #[test]
new_too_huge()382     fn new_too_huge() {
383         if !kernel_has_memfd() {
384             return;
385         }
386         let mut shm = SharedMemory::anon().expect("failed to create shared memory");
387         shm.set_size(0x8000_0000_0000_0000).unwrap_err();
388         assert_eq!(shm.size(), 0);
389     }
390 
391     #[test]
new_named()392     fn new_named() {
393         if !kernel_has_memfd() {
394             return;
395         }
396         let name = "very unique name";
397         let cname = CString::new(name).unwrap();
398         let shm = SharedMemory::new(Some(&cname)).expect("failed to create shared memory");
399         assert_eq!(shm.read_name(), Ok(name.to_owned()));
400     }
401 
402     #[test]
new_sealed()403     fn new_sealed() {
404         if !kernel_has_memfd() {
405             return;
406         }
407         let mut shm = SharedMemory::anon().expect("failed to create shared memory");
408         let mut seals = shm.get_seals().expect("failed to get seals");
409         assert_eq!(seals.bitmask(), 0);
410         seals.set_seal_seal();
411         shm.add_seals(seals).expect("failed to add seals");
412         seals = shm.get_seals().expect("failed to get seals");
413         assert!(seals.seal_seal());
414         // Adding more seals should be rejected by the kernel.
415         shm.add_seals(seals).unwrap_err();
416     }
417 
418     #[test]
mmap_page()419     fn mmap_page() {
420         if !kernel_has_memfd() {
421             return;
422         }
423         let mut shm = SharedMemory::anon().expect("failed to create shared memory");
424         shm.set_size(4096)
425             .expect("failed to set shared memory size");
426 
427         let mmap1 =
428             MemoryMapping::from_fd(&shm, shm.size() as usize).expect("failed to map shared memory");
429         let mmap2 =
430             MemoryMapping::from_fd(&shm, shm.size() as usize).expect("failed to map shared memory");
431 
432         assert_ne!(
433             mmap1.get_slice(0, 1).unwrap().as_ptr(),
434             mmap2.get_slice(0, 1).unwrap().as_ptr()
435         );
436 
437         mmap1
438             .get_slice(0, 4096)
439             .expect("failed to get mmap slice")
440             .write_bytes(0x45);
441 
442         for i in 0..4096 {
443             assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0x45u8);
444         }
445     }
446 
447     #[test]
mmap_page_offset()448     fn mmap_page_offset() {
449         if !kernel_has_memfd() {
450             return;
451         }
452         let mut shm = SharedMemory::anon().expect("failed to create shared memory");
453         shm.set_size(8092)
454             .expect("failed to set shared memory size");
455 
456         let mmap1 = MemoryMapping::from_fd_offset(&shm, shm.size() as usize, 4096)
457             .expect("failed to map shared memory");
458         let mmap2 =
459             MemoryMapping::from_fd(&shm, shm.size() as usize).expect("failed to map shared memory");
460 
461         mmap1
462             .get_slice(0, 4096)
463             .expect("failed to get mmap slice")
464             .write_bytes(0x45);
465 
466         for i in 0..4096 {
467             assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0);
468         }
469         for i in 4096..8092 {
470             assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0x45u8);
471         }
472     }
473 }
474