1use core::slice;
10use std::fs::File;
11use std::io;
12use std::num::NonZeroU64;
13use std::num::NonZeroUsize;
14use std::os::fd::AsFd;
15use std::os::fd::AsRawFd;
16use std::os::fd::BorrowedFd;
17use std::os::fd::RawFd;
18use std::ptr::NonNull;
19
20use nix::errno::Errno;
21use nix::sys::memfd::memfd_create;
22use nix::sys::memfd::MFdFlags;
23use nix::sys::mman;
24use thiserror::Error;
25
26pub struct MemFdBuffer {
30 file: File,
31 size: NonZeroU64,
32}
33
34#[derive(Debug, Error)]
35pub enum NewMemFdBufferError {
36 #[error("MemFdBuffer size cannot be zero")]
37 ZeroSize,
38 #[error("call to memfd_create failed: {0}")]
39 FailedToCreate(#[from] Errno),
40 #[error("failed to set size of memfd: {0}")]
41 FailedToSetSize(io::Error),
42 #[error("failed to seal memfd: {0}")]
43 FailedToSeal(io::Error),
44}
45
46#[derive(Debug, Error)]
47pub enum MemFdMmapError {
48 #[error("buffer size {0} larger than usize")]
49 BufferTooLarge(u64),
50 #[error("mmap call returned error: {0}")]
51 Mmap(#[from] Errno),
52}
53
54impl MemFdBuffer {
55 pub fn new(size: u64) -> Result<Self, NewMemFdBufferError> {
56 let size = NonZeroU64::new(size).ok_or(NewMemFdBufferError::ZeroSize)?;
57
58 let fd = memfd_create(c"", MFdFlags::MFD_ALLOW_SEALING)?;
60
61 let file: File = fd.into();
62
63 file.set_len(size.into())
65 .map_err(NewMemFdBufferError::FailedToSetSize)?;
66
67 if unsafe {
71 libc::fcntl(
72 file.as_raw_fd(),
73 libc::F_ADD_SEALS,
74 libc::F_SEAL_SHRINK | libc::F_SEAL_GROW | libc::F_SEAL_SEAL,
75 )
76 } < 0
77 {
78 return Err(NewMemFdBufferError::FailedToSeal(io::Error::last_os_error()));
79 }
80
81 Ok(Self { file, size })
82 }
83
84 pub fn as_file(&self) -> &File {
85 &self.file
86 }
87
88 pub fn mmap(&self) -> Result<MemFdMapping, MemFdMmapError> {
89 let size = NonZeroUsize::try_from(self.size)
90 .map_err(|_| MemFdMmapError::BufferTooLarge(self.size.into()))?;
91
92 let data = unsafe {
94 mman::mmap(
95 None,
96 size,
97 mman::ProtFlags::PROT_READ | mman::ProtFlags::PROT_WRITE,
98 mman::MapFlags::MAP_SHARED,
99 &self.file,
100 0,
101 )?
102 };
103
104 Ok(MemFdMapping {
105 data: unsafe { slice::from_raw_parts_mut(data.as_ptr().cast(), size.into()) },
107 })
108 }
109}
110
111impl AsFd for MemFdBuffer {
112 fn as_fd(&self) -> BorrowedFd<'_> {
113 self.file.as_fd()
114 }
115}
116
117impl AsRawFd for MemFdBuffer {
118 fn as_raw_fd(&self) -> RawFd {
119 self.file.as_raw_fd()
120 }
121}
122
123impl From<MemFdBuffer> for File {
124 fn from(memfd: MemFdBuffer) -> Self {
125 memfd.file
126 }
127}
128
129pub struct MemFdMapping {
131 data: &'static mut [u8],
134}
135
136impl MemFdMapping {
137 pub fn size(&self) -> usize {
138 self.data.len()
139 }
140}
141
142impl Drop for MemFdMapping {
143 fn drop(&mut self) {
144 unsafe {
147 mman::munmap(
148 NonNull::new_unchecked(self.data.as_mut_ptr().cast()),
149 self.data.len(),
150 )
151 }
152 .unwrap_or_else(|e| {
153 log::error!("error while unmapping MemFdBuffer: {:#}", e);
154 });
155 }
156}
157
158impl AsRef<[u8]> for MemFdMapping {
159 fn as_ref(&self) -> &[u8] {
160 self.data
161 }
162}
163
164impl AsMut<[u8]> for MemFdMapping {
165 fn as_mut(&mut self) -> &mut [u8] {
166 self.data
167 }
168}