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