1 //! The `mmap` API.
2 //!
3 //! # Safety
4 //!
5 //! `mmap` and related functions manipulate raw pointers and have special
6 //! semantics and are wildly unsafe.
7 #![allow(unsafe_code)]
8 
9 use crate::{backend, io};
10 use backend::fd::AsFd;
11 use core::ffi::c_void;
12 
13 #[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
14 pub use backend::mm::types::MlockAllFlags;
15 #[cfg(linux_kernel)]
16 pub use backend::mm::types::MlockFlags;
17 #[cfg(any(target_os = "emscripten", target_os = "linux"))]
18 pub use backend::mm::types::MremapFlags;
19 pub use backend::mm::types::{MapFlags, MprotectFlags, ProtFlags};
20 
21 impl MapFlags {
22     /// Create `MAP_HUGETLB` with provided size of huge page.
23     ///
24     /// Under the hood it computes
25     /// `MAP_HUGETLB | (huge_page_size_log2 << MAP_HUGE_SHIFT)`.
26     /// `huge_page_size_log2` denotes logarithm of huge page size to use and
27     /// should be between 16 and 63 (inclusive).
28     ///
29     /// ```
30     /// use rustix::mm::MapFlags;
31     ///
32     /// let f = MapFlags::hugetlb_with_size_log2(30).unwrap();
33     /// assert_eq!(f, MapFlags::HUGETLB | MapFlags::HUGE_1GB);
34     /// ```
35     #[cfg(feature = "linux-raw-sys")]
hugetlb_with_size_log2(huge_page_size_log2: u32) -> Option<Self>36     pub const fn hugetlb_with_size_log2(huge_page_size_log2: u32) -> Option<Self> {
37         use linux_raw_sys::general::{MAP_HUGETLB, MAP_HUGE_SHIFT};
38         if 16 <= huge_page_size_log2 && huge_page_size_log2 <= 63 {
39             let bits = MAP_HUGETLB | (huge_page_size_log2 << MAP_HUGE_SHIFT);
40             Self::from_bits(bits)
41         } else {
42             None
43         }
44     }
45 }
46 
47 /// `mmap(ptr, len, prot, flags, fd, offset)`—Create a file-backed memory
48 /// mapping.
49 ///
50 /// For anonymous mappings (`MAP_ANON`/`MAP_ANONYMOUS`), see
51 /// [`mmap_anonymous`].
52 ///
53 /// # Safety
54 ///
55 /// Raw pointers and lots of special semantics.
56 ///
57 /// # References
58 ///  - [POSIX]
59 ///  - [Linux]
60 ///  - [Apple]
61 ///  - [FreeBSD]
62 ///  - [NetBSD]
63 ///  - [OpenBSD]
64 ///  - [DragonFly BSD]
65 ///  - [illumos]
66 ///  - [glibc]
67 ///
68 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html
69 /// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html
70 /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html
71 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2
72 /// [NetBSD]: https://man.netbsd.org/mmap.2
73 /// [OpenBSD]: https://man.openbsd.org/mmap.2
74 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap&section=2
75 /// [illumos]: https://illumos.org/man/2/mmap
76 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-mmap
77 #[inline]
mmap<Fd: AsFd>( ptr: *mut c_void, len: usize, prot: ProtFlags, flags: MapFlags, fd: Fd, offset: u64, ) -> io::Result<*mut c_void>78 pub unsafe fn mmap<Fd: AsFd>(
79     ptr: *mut c_void,
80     len: usize,
81     prot: ProtFlags,
82     flags: MapFlags,
83     fd: Fd,
84     offset: u64,
85 ) -> io::Result<*mut c_void> {
86     backend::mm::syscalls::mmap(ptr, len, prot, flags, fd.as_fd(), offset)
87 }
88 
89 /// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`—Create an anonymous
90 /// memory mapping.
91 ///
92 /// For file-backed mappings, see [`mmap`].
93 ///
94 /// # Safety
95 ///
96 /// Raw pointers and lots of special semantics.
97 ///
98 /// # References
99 ///  - [POSIX]
100 ///  - [Linux]
101 ///  - [Apple]
102 ///  - [FreeBSD]
103 ///  - [NetBSD]
104 ///  - [OpenBSD]
105 ///  - [DragonFly BSD]
106 ///  - [illumos]
107 ///  - [glibc]
108 ///
109 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html
110 /// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html
111 /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html
112 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2
113 /// [NetBSD]: https://man.netbsd.org/mmap.2
114 /// [OpenBSD]: https://man.openbsd.org/mmap.2
115 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap&section=2
116 /// [illumos]: https://illumos.org/man/2/mmap
117 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-mmap
118 #[inline]
119 #[doc(alias = "mmap")]
mmap_anonymous( ptr: *mut c_void, len: usize, prot: ProtFlags, flags: MapFlags, ) -> io::Result<*mut c_void>120 pub unsafe fn mmap_anonymous(
121     ptr: *mut c_void,
122     len: usize,
123     prot: ProtFlags,
124     flags: MapFlags,
125 ) -> io::Result<*mut c_void> {
126     backend::mm::syscalls::mmap_anonymous(ptr, len, prot, flags)
127 }
128 
129 /// `munmap(ptr, len)`—Remove a memory mapping.
130 ///
131 /// # Safety
132 ///
133 /// Raw pointers and lots of special semantics.
134 ///
135 /// # References
136 ///  - [POSIX]
137 ///  - [Linux]
138 ///  - [Apple]
139 ///  - [FreeBSD]
140 ///  - [NetBSD]
141 ///  - [OpenBSD]
142 ///  - [DragonFly BSD]
143 ///  - [illumos]
144 ///  - [glibc]
145 ///
146 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munmap.html
147 /// [Linux]: https://man7.org/linux/man-pages/man2/munmap.2.html
148 /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munmap.2.html
149 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munmap&sektion=2
150 /// [NetBSD]: https://man.netbsd.org/munmap.2
151 /// [OpenBSD]: https://man.openbsd.org/munmap.2
152 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munmap&section=2
153 /// [illumos]: https://illumos.org/man/2/munmap
154 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-munmap
155 #[inline]
munmap(ptr: *mut c_void, len: usize) -> io::Result<()>156 pub unsafe fn munmap(ptr: *mut c_void, len: usize) -> io::Result<()> {
157     backend::mm::syscalls::munmap(ptr, len)
158 }
159 
160 /// `mremap(old_address, old_size, new_size, flags)`—Resize, modify, and/or
161 /// move a memory mapping.
162 ///
163 /// For moving a mapping to a fixed address (`MREMAP_FIXED`), see
164 /// [`mremap_fixed`].
165 ///
166 /// # Safety
167 ///
168 /// Raw pointers and lots of special semantics.
169 ///
170 /// # References
171 ///  - [Linux]
172 ///
173 /// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html
174 #[cfg(any(target_os = "emscripten", target_os = "linux"))]
175 #[inline]
mremap( old_address: *mut c_void, old_size: usize, new_size: usize, flags: MremapFlags, ) -> io::Result<*mut c_void>176 pub unsafe fn mremap(
177     old_address: *mut c_void,
178     old_size: usize,
179     new_size: usize,
180     flags: MremapFlags,
181 ) -> io::Result<*mut c_void> {
182     backend::mm::syscalls::mremap(old_address, old_size, new_size, flags)
183 }
184 
185 /// `mremap(old_address, old_size, new_size, MREMAP_FIXED | flags)`—Resize,
186 /// modify, and/or move a memory mapping to a specific address.
187 ///
188 /// For `mremap` without moving to a specific address, see [`mremap`].
189 /// [`mremap_fixed`].
190 ///
191 /// # Safety
192 ///
193 /// Raw pointers and lots of special semantics.
194 ///
195 /// # References
196 ///  - [Linux]
197 ///
198 /// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html
199 #[cfg(any(target_os = "emscripten", target_os = "linux"))]
200 #[inline]
201 #[doc(alias = "mremap")]
mremap_fixed( old_address: *mut c_void, old_size: usize, new_size: usize, flags: MremapFlags, new_address: *mut c_void, ) -> io::Result<*mut c_void>202 pub unsafe fn mremap_fixed(
203     old_address: *mut c_void,
204     old_size: usize,
205     new_size: usize,
206     flags: MremapFlags,
207     new_address: *mut c_void,
208 ) -> io::Result<*mut c_void> {
209     backend::mm::syscalls::mremap_fixed(old_address, old_size, new_size, flags, new_address)
210 }
211 
212 /// `mprotect(ptr, len, flags)`—Change the protection flags of a region of
213 /// memory.
214 ///
215 /// # Safety
216 ///
217 /// Raw pointers and lots of special semantics.
218 ///
219 /// # References
220 ///  - [POSIX]
221 ///  - [Linux]
222 ///  - [Apple]
223 ///  - [FreeBSD]
224 ///  - [NetBSD]
225 ///  - [OpenBSD]
226 ///  - [DragonFly BSD]
227 ///  - [illumos]
228 ///
229 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html
230 /// [Linux]: https://man7.org/linux/man-pages/man2/mprotect.2.html
231 /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html
232 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mprotect&sektion=2
233 /// [NetBSD]: https://man.netbsd.org/mprotect.2
234 /// [OpenBSD]: https://man.openbsd.org/mprotect.2
235 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mprotect&section=2
236 /// [illumos]: https://illumos.org/man/2/mprotect
237 #[inline]
mprotect(ptr: *mut c_void, len: usize, flags: MprotectFlags) -> io::Result<()>238 pub unsafe fn mprotect(ptr: *mut c_void, len: usize, flags: MprotectFlags) -> io::Result<()> {
239     backend::mm::syscalls::mprotect(ptr, len, flags)
240 }
241 
242 /// `mlock(ptr, len)`—Lock memory into RAM.
243 ///
244 /// # Safety
245 ///
246 /// This function operates on raw pointers, but it should only be used on
247 /// memory which the caller owns. Technically, locking memory shouldn't violate
248 /// any invariants, but since unlocking it can violate invariants, this
249 /// function is also unsafe for symmetry.
250 ///
251 /// Some implementations implicitly round the memory region out to the nearest
252 /// page boundaries, so this function may lock more memory than explicitly
253 /// requested if the memory isn't page-aligned. Other implementations fail if
254 /// the memory isn't page-aligned.
255 ///
256 /// # References
257 ///  - [POSIX]
258 ///  - [Linux]
259 ///  - [Apple]
260 ///  - [FreeBSD]
261 ///  - [NetBSD]
262 ///  - [OpenBSD]
263 ///  - [DragonFly BSD]
264 ///  - [illumos]
265 ///  - [glibc]
266 ///
267 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlock.html
268 /// [Linux]: https://man7.org/linux/man-pages/man2/mlock.2.html
269 /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mlock.2.html
270 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlock&sektion=2
271 /// [NetBSD]: https://man.netbsd.org/mlock.2
272 /// [OpenBSD]: https://man.openbsd.org/mlock.2
273 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlock&section=2
274 /// [illumos]: https://illumos.org/man/3C/mlock
275 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlock
276 #[inline]
mlock(ptr: *mut c_void, len: usize) -> io::Result<()>277 pub unsafe fn mlock(ptr: *mut c_void, len: usize) -> io::Result<()> {
278     backend::mm::syscalls::mlock(ptr, len)
279 }
280 
281 /// `mlock2(ptr, len, flags)`—Lock memory into RAM, with flags.
282 ///
283 /// `mlock_with` is the same as [`mlock`] but adds an additional flags operand.
284 ///
285 /// # Safety
286 ///
287 /// This function operates on raw pointers, but it should only be used on
288 /// memory which the caller owns. Technically, locking memory shouldn't violate
289 /// any invariants, but since unlocking it can violate invariants, this
290 /// function is also unsafe for symmetry.
291 ///
292 /// Some implementations implicitly round the memory region out to the nearest
293 /// page boundaries, so this function may lock more memory than explicitly
294 /// requested if the memory isn't page-aligned.
295 ///
296 /// # References
297 ///  - [Linux]
298 ///  - [glibc]
299 ///
300 /// [Linux]: https://man7.org/linux/man-pages/man2/mlock2.2.html
301 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlock2
302 #[cfg(linux_kernel)]
303 #[inline]
304 #[doc(alias = "mlock2")]
mlock_with(ptr: *mut c_void, len: usize, flags: MlockFlags) -> io::Result<()>305 pub unsafe fn mlock_with(ptr: *mut c_void, len: usize, flags: MlockFlags) -> io::Result<()> {
306     backend::mm::syscalls::mlock_with(ptr, len, flags)
307 }
308 
309 /// `munlock(ptr, len)`—Unlock memory.
310 ///
311 /// # Safety
312 ///
313 /// This function operates on raw pointers, but it should only be used on
314 /// memory which the caller owns, to avoid compromising the `mlock` invariants
315 /// of other unrelated code in the process.
316 ///
317 /// Some implementations implicitly round the memory region out to the nearest
318 /// page boundaries, so this function may unlock more memory than explicitly
319 /// requested if the memory isn't page-aligned.
320 ///
321 /// # References
322 ///  - [POSIX]
323 ///  - [Linux]
324 ///  - [Apple]
325 ///  - [FreeBSD]
326 ///  - [NetBSD]
327 ///  - [OpenBSD]
328 ///  - [DragonFly BSD]
329 ///  - [illumos]
330 ///  - [glibc]
331 ///
332 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munlock.html
333 /// [Linux]: https://man7.org/linux/man-pages/man2/munlock.2.html
334 /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munlock.2.html
335 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlock&sektion=2
336 /// [NetBSD]: https://man.netbsd.org/munlock.2
337 /// [OpenBSD]: https://man.openbsd.org/munlock.2
338 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlock&section=2
339 /// [illumos]: https://illumos.org/man/3C/munlock
340 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-munlock
341 #[inline]
munlock(ptr: *mut c_void, len: usize) -> io::Result<()>342 pub unsafe fn munlock(ptr: *mut c_void, len: usize) -> io::Result<()> {
343     backend::mm::syscalls::munlock(ptr, len)
344 }
345 
346 /// Locks all pages mapped into the address space of the calling process.
347 ///
348 /// This includes the pages of the code, data, and stack segment, as well as
349 /// shared libraries, user space kernel data, shared memory, and memory-mapped
350 /// files. All mapped pages are guaranteed to be resident in RAM when the call
351 /// returns successfully; the pages are guaranteed to stay in RAM until later
352 /// unlocked.
353 ///
354 /// # References
355 ///  - [POSIX]
356 ///  - [Linux]
357 ///  - [FreeBSD]
358 ///  - [NetBSD]
359 ///  - [OpenBSD]
360 ///  - [DragonFly BSD]
361 ///  - [illumos]
362 ///  - [glibc]
363 ///
364 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlockall.html
365 /// [Linux]: https://man7.org/linux/man-pages/man2/mlockall.2.html
366 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlockall&sektion=2
367 /// [NetBSD]: https://man.netbsd.org/mlockall.2
368 /// [OpenBSD]: https://man.openbsd.org/mlockall.2
369 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlockall&section=2
370 /// [illumos]: https://illumos.org/man/3C/mlockall
371 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlockall
372 #[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
373 #[inline]
mlockall(flags: MlockAllFlags) -> io::Result<()>374 pub fn mlockall(flags: MlockAllFlags) -> io::Result<()> {
375     backend::mm::syscalls::mlockall(flags)
376 }
377 
378 /// Unlocks all pages mapped into the address space of the calling process.
379 ///
380 /// # Warnings
381 ///
382 /// This function is aware of all the memory pages in the process, as if it
383 /// were a debugger. It unlocks all the pages, which could potentially
384 /// compromise security assumptions made by code about memory it has
385 /// encapsulated.
386 ///
387 /// # References
388 ///  - [POSIX]
389 ///  - [Linux]
390 ///  - [FreeBSD]
391 ///  - [NetBSD]
392 ///  - [OpenBSD]
393 ///  - [DragonFly BSD]
394 ///  - [illumos]
395 ///  - [glibc]
396 ///
397 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munlockall.html
398 /// [Linux]: https://man7.org/linux/man-pages/man2/munlockall.2.html
399 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlockall&sektion=2
400 /// [NetBSD]: https://man.netbsd.org/munlockall.2
401 /// [OpenBSD]: https://man.openbsd.org/munlockall.2
402 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlockall&section=2
403 /// [illumos]: https://illumos.org/man/3C/munlockall
404 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-munlockall
405 #[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
406 #[inline]
munlockall() -> io::Result<()>407 pub fn munlockall() -> io::Result<()> {
408     backend::mm::syscalls::munlockall()
409 }
410