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