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