[PATCH v8 0/8] Add support for memory sealing

Adhemerval Zanella adhemerval.zanella@linaro.org
Wed Jan 29 17:22:34 GMT 2025


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].

Memory sealing is an opt-in security feature that requires the new GNU
property GNU_PROPERTY_MEMORY_SEAL, defined in Linux ABI [3] and
supported on binutils 2.44 [4]. A GNU property is preferable over a
new dynamic section tag (like the one proposed for DT_GNU_FLAGS_1) so
it can be applied to ET_EXEC (for instance on static binaries).

The GNU_PROPERTY_MEMORY_SEAL enforcement depends on whether the kernel
supports the mseal syscall and how glibc is configured.  On the default
configuration that aims to support older kernel releases, the memory
sealing attribute is taken as a hint. If glibc is configured with a
minimum kernel of 6.10, where mseal is implied to be supported,
sealing is enforced.

The first patch adds the mseal support for Linux.  Although most
programs will not use it directly, some specific ones, like Chrome,
intend to use it.

The second and third patches are requirements to enable memory sealing
to work on executables, where they add gnu property parsing on the
loader and static binaries.

The fourth patch moves 'call_init_paths' after gnu attribute parsing,
so the loader can seal the rtld_malloc pages (since they are meant to
be immutable over process execution).

The fifth patch propagates the RTLD_NODELETE flag in case of dlopen. It
will be used to extend memory sealing for the object dependencies.

The sixth patch adds the memory sealing supports in multiple places
where the page is supposed to be immutable over program execution:

 * All shared library dependencies from the binary, including the
   read-only segments after PT_GNU_RELRO setup.
 * The binary itself, including dynamic and static links. In both cases,
   it is up either to binary or the loader to set up the sealing.
 * Any preload libraries.
 * Any library loaded with dlopen with RTLD_NODELETE flag (including
   libgcc.so loaded to enable process unwind and thread cancellation).
 * Audit modules.
 * The loader bump allocator.

The seventh patch makes glibc enable memory sealing as default if the
linker supports the option (-Wl,memory-seal). A new configure option,
--disable-default-memory-seal, disable it.

The last patch adds memory sealing tests, they are enabled if the linker
supports it.

This patchset does not delay RELRO activation until after their ELF
constructors have been executed, as suggested on the previous RFC for
mseal support. It is not strictly required, and it requires extensive
changes on_dl_start_user to either make _dl_init call RELRO/sealing
setup after ctor/initarray is done, or call it after _dl_init.  There 
is also the question of whether to apply RELRO/sealing per module after
dtor/initarray or in bulk after _dt_init.

I tested on both x86_64-linux-gnu and aarch64-linux-gnu with Linux
6.13, along with some testing on a powerpc64le-linux-gnu and s390x-inux-gnu VMs.

[1] https://blog.trailofbits.com/2024/10/25/a-deep-dive-into-linuxs-new-mseal-syscall/
[2] https://man.openbsd.org/mimmutable.2
[3] https://gitlab.com/x86-psABIs/Linux-ABI/-/commit/25a851b99665e7b22db5fabe818efaaa52466893
[4] https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=4d890484df4b2cf004f6f1f6d8c39a69fa39c875

Changes v4->v5:
* Removed the tunable.
* Rebased against GCS change to enable GNU attribute parsing on all architectures.

Changes v3->v4:
* Rebase against master (remove nios2 ABI update and handle f2326c2ec0a0a8db
  changes).
* Handle vvar_vclock mapping on tests.
 
Changes v2->v3:
* Make the option opt-in instead of opt-out.

Adhemerval Zanella (8):
  linux: Add mseal syscall support
  elf: Parse gnu properties for static linked binaries
  elf: Parse gnu properties for the loader
  rtld: Move call_init_paths after _dl_process_pt_gnu_property
  elf: Use RTLD_NODELETE for dependencies
  elf: Add support to memory sealing
  Enable memory sealing automatically
  linux: Add memory sealing tests

 INSTALL                                       |   5 +
 Makeconfig                                    |  19 +-
 Makerules                                     |   2 +
 NEWS                                          |  14 +-
 configure                                     |  58 ++++
 configure.ac                                  |  20 ++
 csu/libc-start.c                              |   4 +
 elf/Makefile                                  |  19 +-
 elf/dl-load.c                                 |   4 +
 elf/dl-map-segments.h                         |  16 +-
 elf/dl-minimal-malloc.c                       |   5 +
 elf/dl-open.c                                 |   7 +-
 elf/dl-reloc.c                                |  49 ++++
 elf/dl-support.c                              |  16 +
 elf/elf.h                                     |   2 +
 elf/rtld.c                                    |  26 +-
 elf/setup-vdso.h                              |   2 +
 include/link.h                                |   8 +
 manual/install.texi                           |   5 +
 manual/memory.texi                            |  66 +++++
 sysdeps/aarch64/dl-prop.h                     |   5 +
 sysdeps/generic/dl-mseal.h                    |  22 ++
 sysdeps/generic/dl-prop-mseal.h               |  34 +++
 sysdeps/generic/dl-prop.h                     |   5 +
 sysdeps/generic/ldsodefs.h                    |   9 +
 sysdeps/generic/libc-prop.h                   |  44 +++
 sysdeps/unix/sysv/linux/Makefile              | 102 +++++++
 sysdeps/unix/sysv/linux/Versions              |   3 +
 sysdeps/unix/sysv/linux/aarch64/libc-start.h  |  11 -
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/bits/mman-shared.h    |   8 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/dl-mseal.c            |  51 ++++
 sysdeps/unix/sysv/linux/dl-mseal.h            |  31 ++
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/kernel-features.h     |   8 +
 .../sysv/linux/loongarch/lp64/libc.abilist    |   1 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/microblaze/le/libc.abilist     |   1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |   1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/syscalls.list         |   1 +
 .../sysv/linux/tst-dl_mseal-auditmod-noseal.c |   1 +
 .../unix/sysv/linux/tst-dl_mseal-auditmod.c   |  23 ++
 .../unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c |  19 ++
 .../unix/sysv/linux/tst-dl_mseal-dlopen-1.c   |  19 ++
 .../linux/tst-dl_mseal-dlopen-2-1-noseal.c    |  19 ++
 .../unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c |  19 ++
 .../sysv/linux/tst-dl_mseal-dlopen-2-noseal.c |  19 ++
 .../unix/sysv/linux/tst-dl_mseal-dlopen-2.c   |  19 ++
 .../sysv/linux/tst-dl_mseal-mod-1-noseal.c    |  19 ++
 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c  |  19 ++
 .../sysv/linux/tst-dl_mseal-mod-2-noseal.c    |  19 ++
 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c  |  19 ++
 sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c |  80 +++++
 .../sysv/linux/tst-dl_mseal-preload-noseal.c  |   1 +
 .../unix/sysv/linux/tst-dl_mseal-preload.c    |  19 ++
 .../unix/sysv/linux/tst-dl_mseal-skeleton.c   | 276 ++++++++++++++++++
 .../sysv/linux/tst-dl_mseal-static-noseal.c   |  45 +++
 sysdeps/unix/sysv/linux/tst-dl_mseal-static.c |  42 +++
 sysdeps/unix/sysv/linux/tst-dl_mseal.c        |  78 +++++
 sysdeps/unix/sysv/linux/tst-mseal.c           |  67 +++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 sysdeps/x86/dl-prop.h                         |   8 +-
 86 files changed, 1514 insertions(+), 28 deletions(-)
 create mode 100644 sysdeps/generic/dl-mseal.h
 create mode 100644 sysdeps/generic/dl-prop-mseal.h
 create mode 100644 sysdeps/generic/libc-prop.h
 create mode 100644 sysdeps/unix/sysv/linux/dl-mseal.c
 create mode 100644 sysdeps/unix/sysv/linux/dl-mseal.h
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod-noseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1-noseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-noseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1-noseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2-noseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-preload-noseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-preload.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-static-noseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-static.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-mseal.c

-- 
2.43.0



More information about the Libc-alpha mailing list