[PATCH v8 0/8] Add support for memory sealing
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Mon Feb 3 19:25:12 GMT 2025
On 03/02/25 16:05, Florian Weimer wrote:
> * Adhemerval Zanella Netto:
>
>> On 03/02/25 15:03, Florian Weimer wrote:
>>> * Adhemerval Zanella:
>>>
>>>> The Linux 6.10 (8be7258aad44) added the mseal syscall that allows
>>>> blocking some memory operations on the VMA range:
>>>>
>>>> * Unmapping, moving to another location, extending or shrinking the
>>>> size, munmap, and mremap.
>>>> * Moving or expanding a different VMA into the current range, via
>>>> mremap.
>>>> * Modifying the memory range with mmap along with flag MAP_FIXED.
>>>> * Expanding the size with mremap.
>>>> * Change the protection flags with mprotect or pkey_mprotect.
>>>> * Destructive behaviors on anonymous memory, such as madvice with
>>>> MADV_DONTNEED.
>>>>
>>>> Memory sealing is a hardening mechanism [1] to avoid either remapping
>>>> the memory segments or changing the memory protection segments layout
>>>> by the dynamic loader (for instance, the RELRO hardening). The OpenBSD
>>>> supports a similar hardening with the mimmutable syscall [2].
>>>
>>> Have you checked that CRIU restore still works after these changes? I
>>> don't see how it can because the initial mappings can no longer be
>>> unmapped.
>>
>> No, I will take a look but I am not if this applies since it is a opt-in
>> feature. The CRIU adds some extra semantic requirements that is hard
>> to take in consideration, similar to the defunct prelink support.
>>
>> But from CRIU discussion about a sealing extension to kernel mappings
>> (such as vDSO) I got the impression that memory sealing is not a problem
>> for userland (I guess that restoring just either ignore sealing or
>> apply itself).
>
> CRIU needs to be able to unmap everything that was initially loaded by
> the kernel and glibc. This will stop working if we use mseal for glibc
> itself.
So in this case the easiest way it to filter of mseal (with seccomp or
something related) and disable sealing. I don't have a easy solution.
>
>> A dynamic tag would add support only for ET_DYN, where a GNU attribute
>> allows for ET_EXEC as well (similar to recent hardening mechanism like
>> BTI, GCS, etc.).
>
> We don't need the compatibility indicator on static executables because
> incompatible static binaries won't have the PT_* header that requests
> sealing.
But we will still need to mark the ET_EXEC as opt-in for sealing. A dynamic
tag will be only enabled for ET_DYN.
>
>> An the range approach is an extra complexity that I don't really see
>> much gain, since the idea of PT_LOAD are to being *immutable* over process
>> execution and not selective applied (different than PT_GNU_RELRO where
>> only part of memory range should be RO).
>>
>> A range-based approach will still allow a misconfigured binary to be
>> partially sealed, which defeats the whole idea of the hardening (similar
>> to partial relro).
>
> But partial sealing could be a feature, too. For example, in libgcc_s,
> we might want to keep the root of the dynamic unwinding data structure
> in read-only memory most of the time, as a post-exploitation
> countermeasure that makes it harder to run arbitrary DWARF programs.
Right, but I feel that this is out of scope of the current proposed approach,
where the idea is to only mark the binary to seal the current immutable
easily obtained loaded ELF segments.
Is this allocated dynamic during process execution of defined during build?
Can't you put this on relro segment, with a constructor to do any required
initialization?
More information about the Libc-alpha
mailing list