A process can establish a memory mapping with the intended address, size, and protection bits, then later alter that mapping with operations such as munmap(), mprotect(), or mremap(). Linux mseal() adds a one-way state transition: selected virtual memory areas can be sealed so a class of later mapping modifications is rejected by the kernel.

The mechanism protects mapping structure rather than the bytes stored in the mapping. A writable sealed mapping remains writable through ordinary stores. Sealing instead constrains operations that could remove the mapping, relocate it, replace it, or change attributes covered by the sealing rules.

Sealing attaches to virtual memory areas

mseal() accepts an address, a length, and a flags argument. The start address must be page aligned and both ends of the requested interval must lie in allocated virtual memory. Gaps inside the interval are not accepted. The kernel rounds the length to a page boundary as required by the interface.

A successful call marks the covered mappings as sealed. Repeating the operation on memory that is already sealed is harmless. There is deliberately no inverse operation that removes the seal.

This irreversible property is central to the interface. Code can construct its address-space state during initialization and then reduce the set of transformations available later in the process lifetime.

Layout-changing operations are constrained

A seal blocks operations that could dismantle or reshape the protected mapping. munmap() cannot remove sealed regions. mremap() cannot be used to move or resize them, and mmap() cannot replace a sealed mapping with a new mapping at the same address.

The boundary also covers permission changes. mprotect() and pkey_mprotect() are rejected when they attempt prohibited changes involving sealed mappings. This prevents a later code path from using those interfaces to rewrite the protection state established before sealing.

The effect differs from merely remembering the expected mapping metadata in application state. The restriction is enforced in the kernel’s memory-management path, so code executing in the same process cannot simply ignore an application-level flag and perform a blocked mapping operation.

Sealing does not make writable data immutable

The name can suggest stronger data semantics than the syscall provides. mseal() does not turn a writable page into read-only storage. If a mapping has PROT_WRITE, normal writes remain governed by that permission after sealing.

For data that must become read-only, the process can first establish the desired protection with mprotect() and then seal the resulting mapping. The order matters: once the mapping is sealed, the blocked memory-management transformations cannot be used as a routine reconfiguration path.

This separation produces two distinct properties. Page permissions govern memory accesses such as reads, writes, and instruction fetches. The seal governs later attempts to alter selected properties of the mapping itself.

Destructive advice is also part of the boundary

Some madvise() behaviors can discard or materially alter mapped contents without changing the apparent address range. Linux therefore blocks specific destructive advice operations for sealed mappings, including relevant discard and fork-related behaviors documented by the interface.

This closes a gap that would exist if sealing guarded only mmap(), munmap(), and protection changes. A mapping could otherwise retain the same virtual address and permission bits while an operation discards its backing contents.

Not every madvise() command is equivalent, and sealing is not a blanket prohibition on all advice. Software that depends on a particular advice operation must treat the documented set of blocked operations as part of the syscall contract rather than infer behavior from the name of the mechanism.

Failure across multiple mappings requires care

Memory-management syscalls can span more than one VMA. For some blocked operations, failure caused by a sealed VMA does not imply that every earlier part of a multi-VMA request remained untouched. The kernel documentation explicitly distinguishes operations with atomic behavior from cases where partial updates can occur before EPERM is returned.

munmap() is documented as atomic with respect to this sealing check: if a sealed VMA is encountered in the supplied range, the VMAs in that request are not unmapped. Other operations, including some protection and advice changes, can have different partial-update behavior.

Code that treats an error return as a universal rollback signal can therefore hold an incorrect model of the resulting address space. The relevant syscall’s failure semantics remain significant even after sealing is introduced.

The boundary is local to process memory state

A sealed mapping remains part of the process address space until process termination unless an allowed kernel path has semantics outside the blocked transformation set. The mechanism does not create a persistent object-level seal on the underlying file, nor does it change another process’s independent mapping of that file.

This makes mseal() different from file seals applied to objects such as memfd files. File sealing constrains operations on the file object according to its own rules. Memory sealing constrains selected transformations of VMAs in one process address space.

The distinction matters when the same file is mapped into several processes. Sealing one process’s mapping does not convert the shared backing file into an immutable resource for every participant.

Architecture support is an explicit deployment constraint

The current Linux interface is built for 64-bit kernels. On unsupported kernels the syscall is unavailable and returns the corresponding not-implemented result. Software that uses sealing as a security boundary therefore needs an explicit policy for kernels that do not provide it.

Silently continuing without the seal can turn a required invariant into a best-effort preference. A program can instead fail startup, disable the feature that depends on the invariant, or select another isolation mechanism according to its threat model.

mseal() is most useful after a process has finished constructing memory regions whose layout and permissions should no longer be reconfigured. It turns that established state into a kernel-enforced, one-way boundary while leaving ordinary accesses subject to the permissions already attached to each mapping.