Skip to content

Commit 0f4ac28

Browse files
committed
Add mlockall and munlockall
1 parent 1a9d129 commit 0f4ac28

File tree

6 files changed

+182
-0
lines changed

6 files changed

+182
-0
lines changed

src/backend/libc/mm/syscalls.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
#[cfg(not(target_os = "redox"))]
44
use super::types::Advice;
5+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
6+
use super::types::MlockAllFlags;
57
#[cfg(any(target_os = "emscripten", target_os = "linux"))]
68
use super::types::MremapFlags;
79
use super::types::{MapFlags, MprotectFlags, MsyncFlags, ProtFlags};
@@ -220,3 +222,22 @@ pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd>
220222
}
221223
ret_owned_fd(userfaultfd(bitflags_bits!(flags)))
222224
}
225+
226+
/// Locks all pages mapped into the address space of the calling process.
227+
///
228+
/// This includes the pages of the code, data and stack segment, as well as shared libraries,
229+
/// user space kernel data, shared memory, and memory-mapped files. All mapped pages are
230+
/// guaranteed to be resident in RAM when the call returns successfully;
231+
/// the pages are guaranteed to stay in RAM until later unlocked.
232+
#[inline]
233+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
234+
pub(crate) fn mlockall(flags: MlockAllFlags) -> io::Result<()> {
235+
unsafe { ret(c::mlockall(bitflags_bits!(flags))) }
236+
}
237+
238+
/// Unlocks all pages mapped into the address space of the calling process.
239+
#[inline]
240+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
241+
pub(crate) fn munlockall() -> io::Result<()> {
242+
unsafe { ret(c::munlockall()) }
243+
}

src/backend/libc/mm/types.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,3 +442,28 @@ bitflags! {
442442
const _ = !0;
443443
}
444444
}
445+
446+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
447+
bitflags! {
448+
/// `MCL_*` flags for use with [`mlockall`].
449+
///
450+
/// [`mlockall`]: crate::mm::mlockall
451+
#[repr(transparent)]
452+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
453+
pub struct MlockAllFlags: u32 {
454+
// libc doesn't define `MCL_ONFAULT` yet.
455+
// const ONFAULT = libc::MCL_ONFAULT;
456+
/// Lock all pages which will become mapped into the address
457+
/// space of the process in the future. These could be, for
458+
/// instance, new pages required by a growing heap and stack
459+
/// as well as new memory-mapped files or shared memory
460+
/// regions.
461+
const FUTURE = bitcast!(libc::MCL_FUTURE);
462+
/// Lock all pages which are currently mapped into the address
463+
/// space of the process.
464+
const CURRENT = bitcast!(libc::MCL_CURRENT);
465+
466+
/// <https://docs.rs/bitflags/latest/bitflags/#externally-defined-flags>
467+
const _ = !0;
468+
}
469+
}

src/backend/linux_raw/conv.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,15 @@ impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MlockFlags> for ArgReg<
621621
}
622622
}
623623

624+
#[cfg(feature = "mm")]
625+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
626+
impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MlockAllFlags> for ArgReg<'a, Num> {
627+
#[inline]
628+
fn from(flags: crate::backend::mm::types::MlockAllFlags) -> Self {
629+
c_uint(flags.bits())
630+
}
631+
}
632+
624633
#[cfg(feature = "mm")]
625634
impl<'a, Num: ArgNumber> From<crate::backend::mm::types::MapFlags> for ArgReg<'a, Num> {
626635
#[inline]

src/backend/linux_raw/mm/syscalls.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#![allow(unsafe_code)]
77
#![allow(clippy::undocumented_unsafe_blocks)]
88

9+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
10+
use super::types::MlockAllFlags;
911
use super::types::{
1012
Advice, MapFlags, MlockFlags, MprotectFlags, MremapFlags, MsyncFlags, ProtFlags,
1113
UserfaultfdFlags,
@@ -210,3 +212,29 @@ pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<
210212
pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> {
211213
ret_owned_fd(syscall_readonly!(__NR_userfaultfd, flags))
212214
}
215+
216+
/// Locks all pages mapped into the address space of the calling process.
217+
///
218+
/// This includes the pages of the code, data and stack segment, as well as shared libraries,
219+
/// user space kernel data, shared memory, and memory-mapped files. All mapped pages are
220+
/// guaranteed to be resident in RAM when the call returns successfully;
221+
/// the pages are guaranteed to stay in RAM until later unlocked.
222+
#[inline]
223+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
224+
pub(crate) fn mlockall(flags: MlockAllFlags) -> io::Result<()> {
225+
// When `mlockall` is used with `MCL_ONFAULT | MCL_FUTURE`, the ordering
226+
// of `mlockall` with respect to arbitrary loads may be significant,
227+
// because if a load happens and evokes a fault before the `mlockall`,
228+
// the memory doesn't get locked, but if the load and therefore
229+
// the fault happens after, then the memory does get locked.
230+
// So to be conservative in this regard, we use `syscall` instead
231+
// of `syscall_readonly`
232+
unsafe { ret(syscall!(__NR_mlockall, flags)) }
233+
}
234+
235+
/// Unlocks all pages mapped into the address space of the calling process.
236+
#[inline]
237+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
238+
pub(crate) fn munlockall() -> io::Result<()> {
239+
unsafe { ret(syscall_readonly!(__NR_munlockall)) }
240+
}

src/backend/linux_raw/mm/types.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,37 @@ bitflags! {
262262
const _ = !0;
263263
}
264264
}
265+
266+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
267+
bitflags! {
268+
/// `MCL_*` flags for use with [`mlockall`].
269+
///
270+
/// [`mlockall`]: crate::mm::mlockall
271+
#[repr(transparent)]
272+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
273+
pub struct MlockAllFlags: u32 {
274+
/// Used together with `MCL_CURRENT`, `MCL_FUTURE`, or both. Mark
275+
/// all current (with `MCL_CURRENT`) or future (with `MCL_FUTURE`)
276+
/// mappings to lock pages when they are faulted in. When
277+
/// used with `MCL_CURRENT`, all present pages are locked, but
278+
/// `mlockall()` will not fault in non-present pages. When used
279+
/// with `MCL_FUTURE`, all future mappings will be marked to
280+
/// lock pages when they are faulted in, but they will not be
281+
/// populated by the lock when the mapping is created.
282+
/// `MCL_ONFAULT` must be used with either `MCL_CURRENT` or
283+
/// `MCL_FUTURE` or both.
284+
const ONFAULT = linux_raw_sys::general::MCL_ONFAULT;
285+
/// Lock all pages which will become mapped into the address
286+
/// space of the process in the future. These could be, for
287+
/// instance, new pages required by a growing heap and stack
288+
/// as well as new memory-mapped files or shared memory
289+
/// regions.
290+
const FUTURE = linux_raw_sys::general::MCL_FUTURE;
291+
/// Lock all pages which are currently mapped into the address
292+
/// space of the process.
293+
const CURRENT = linux_raw_sys::general::MCL_CURRENT;
294+
295+
/// <https://docs.rs/bitflags/latest/bitflags/#externally-defined-flags>
296+
const _ = !0;
297+
}
298+
}

src/mm/mmap.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use crate::{backend, io};
1010
use backend::fd::AsFd;
1111
use core::ffi::c_void;
1212

13+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
14+
pub use backend::mm::types::MlockAllFlags;
1315
#[cfg(linux_kernel)]
1416
pub use backend::mm::types::MlockFlags;
1517
#[cfg(any(target_os = "emscripten", target_os = "linux"))]
@@ -340,3 +342,66 @@ pub unsafe fn mlock_with(ptr: *mut c_void, len: usize, flags: MlockFlags) -> io:
340342
pub unsafe fn munlock(ptr: *mut c_void, len: usize) -> io::Result<()> {
341343
backend::mm::syscalls::munlock(ptr, len)
342344
}
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 shared libraries,
349+
/// user space kernel data, shared memory, and memory-mapped files. All mapped pages are
350+
/// guaranteed to be resident in RAM when the call returns successfully;
351+
/// the pages are guaranteed to stay in RAM until later unlocked.
352+
///
353+
/// # References
354+
/// - [POSIX]
355+
/// - [Linux]
356+
/// - [FreeBSD]
357+
/// - [NetBSD]
358+
/// - [OpenBSD]
359+
/// - [DragonFly BSD]
360+
/// - [illumos]
361+
/// - [glibc]
362+
///
363+
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlockall.html
364+
/// [Linux]: https://man7.org/linux/man-pages/man2/mlockall.2.html
365+
/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlockall&sektion=2
366+
/// [NetBSD]: https://man.netbsd.org/mlockall.2
367+
/// [OpenBSD]: https://man.openbsd.org/mlockall.2
368+
/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlockall&section=2
369+
/// [illumos]: https://illumos.org/man/3C/mlockall
370+
/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlockall
371+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
372+
#[inline]
373+
pub fn mlockall(flags: MlockAllFlags) -> io::Result<()> {
374+
backend::mm::syscalls::mlockall(flags)
375+
}
376+
377+
/// Unlocks all pages mapped into the address space of the calling process.
378+
///
379+
/// # Warnings
380+
///
381+
/// This function is aware of all the memory pages in the process, as if it were a debugger.
382+
/// It unlocks all the pages, which could potentially compromise security assumptions made by
383+
/// code about memory it has encapsulated.
384+
///
385+
/// # References
386+
/// - [POSIX]
387+
/// - [Linux]
388+
/// - [FreeBSD]
389+
/// - [NetBSD]
390+
/// - [OpenBSD]
391+
/// - [DragonFly BSD]
392+
/// - [illumos]
393+
/// - [glibc]
394+
///
395+
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munlockall.html
396+
/// [Linux]: https://man7.org/linux/man-pages/man2/munlockall.2.html
397+
/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlockall&sektion=2
398+
/// [NetBSD]: https://man.netbsd.org/munlockall.2
399+
/// [OpenBSD]: https://man.openbsd.org/munlockall.2
400+
/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlockall&section=2
401+
/// [illumos]: https://illumos.org/man/3C/munlockall
402+
/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-munlockall
403+
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
404+
#[inline]
405+
pub fn munlockall() -> io::Result<()> {
406+
backend::mm::syscalls::munlockall()
407+
}

0 commit comments

Comments
 (0)