mbox series

[v3,0/9] Add support for memory sealing

Message ID 20240930200831.1669010-1-adhemerval.zanella@linaro.org
Headers show
Series Add support for memory sealing | expand

Message

Adhemerval Zanella Netto Sept. 30, 2024, 8:08 p.m. UTC
The Linux 6.10 (8be7258aad44b5e25977a98db136f677fa6f4370) 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 location, 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 useful as a hardening mechanism to avoid either
remapping the memory segments or changing the memory protection segments
layout by the dynamic loader (for instance, the RELRO hardening). A
similar hardening is done by OpenBSD with the mimmutable syscall [1].

The sealing is an opt-in security feature that requires a new GNU
property GNU_PROPERTY_MEMORY_SEAL to indicate that the ELF module
supports and should use memory sealing if the loader supports it.
Previous versions [2] had the sealing as an opt-out feature, however, it
has some drawbacks where the backport is not straightforward, there is
no clear semantic if memory sealing is a hint or requirement, some
programs bypass the loader to apply relocation themselves and are
incompatible with an opt-out feature [3], and it deviates from how other
security hardening was added on Linux ecosystem (such as RELRO and
non-executable stacks).

A GNU property is used instead of a new dynamic section tag (like the
one proposed for DT_GNU_FLAGS_1) because the memory sealing should be
selectable for ET_EXEC and not only for ET_DYN. It also fits new opt-in
security features like x86 CET or AArch64 BTI. 

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 eighth patch adds memory sealing tests, they are enabled if the
linker supports it.

The last patch adds a new tunable, glibc.rtld.seal, which can be used to
enforce memory sealing even if the programs or dependencies do not have
the GNU_PROPERTY_MEMORY_SEAL. The tunable accepts two different values:

* '0': where loaders follow the GNU_PROPERTY_MEMORY_SEAL attribute if
* present.  This is the default and no sealing would be applied if the
* object does not have the memory sealing attribute.

* '1': where sealing is enforced even if the object does not have the
* GNU_PROPERTY_MEMORY_SEAL.  Also, any syscall failure on memory sealing
* aborts the programs.

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.11, along with some testing on a powerpc64le-linux-gnu VM.

[1] https://man.openbsd.org/mimmutable.2
[2] https://sourceware.org/pipermail/libc-alpha/2024-August/158836.html
[3] https://glandium.org/blog/?p=4297

Changes v2->v3:
* Make the option opt-int instead of opt-out.

Adhemerval Zanella (9):
  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
  elf: Add glibc.rtld.seal tunable

 INSTALL                                       |   5 +
 Makeconfig                                    |  17 ++
 Makerules                                     |   2 +
 NEWS                                          |  20 ++
 configure                                     |  57 ++++
 configure.ac                                  |  19 ++
 elf/Makefile                                  |   1 +
 elf/dl-load.c                                 |   7 +
 elf/dl-map-segments.h                         |   6 +
 elf/dl-minimal-malloc.c                       |   3 +
 elf/dl-mseal-mode.h                           |  28 ++
 elf/dl-open.c                                 |   7 +-
 elf/dl-reloc.c                                |  64 ++++
 elf/dl-support.c                              |  22 ++
 elf/dl-tunables.list                          |   6 +
 elf/elf.h                                     |   2 +
 elf/rtld.c                                    |  27 +-
 elf/setup-vdso.h                              |   2 +
 elf/tst-rtld-list-tunables.exp                |   1 +
 include/link.h                                |   8 +
 manual/install.texi                           |   5 +
 manual/memory.texi                            |  66 +++++
 manual/tunables.texi                          |  35 +++
 sysdeps/aarch64/dl-prop.h                     |   5 +
 sysdeps/generic/dl-mseal.h                    |  23 ++
 sysdeps/generic/dl-prop-mseal.h               |  36 +++
 sysdeps/generic/dl-prop.h                     |   5 +
 sysdeps/generic/ldsodefs.h                    |  14 +
 sysdeps/unix/sysv/linux/Makefile              | 107 +++++++
 sysdeps/unix/sysv/linux/Versions              |   1 +
 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            |  48 +++
 sysdeps/unix/sysv/linux/dl-mseal.h            |  27 ++
 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/nios2/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 |  74 +++++
 .../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   | 278 ++++++++++++++++++
 .../sysv/linux/tst-dl_mseal-static-noseal.c   |  45 +++
 sysdeps/unix/sysv/linux/tst-dl_mseal-static.c |  42 +++
 .../unix/sysv/linux/tst-dl_mseal-tunable.c    |  76 +++++
 sysdeps/unix/sysv/linux/tst-dl_mseal.c        |  72 +++++
 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                         |   4 +
 89 files changed, 1611 insertions(+), 6 deletions(-)
 create mode 100644 elf/dl-mseal-mode.h
 create mode 100644 sysdeps/generic/dl-mseal.h
 create mode 100644 sysdeps/generic/dl-prop-mseal.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-tunable.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-mseal.c

Comments

Jeff Xu Oct. 2, 2024, 12:20 a.m. UTC | #1
On Mon, Sep 30, 2024 at 1:08 PM Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
>
> The Linux 6.10 (8be7258aad44b5e25977a98db136f677fa6f4370) 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 location, 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 useful as a hardening mechanism to avoid either
> remapping the memory segments or changing the memory protection segments
> layout by the dynamic loader (for instance, the RELRO hardening). A
> similar hardening is done by OpenBSD with the mimmutable syscall [1].
>
> The sealing is an opt-in security feature that requires a new GNU
> property GNU_PROPERTY_MEMORY_SEAL to indicate that the ELF module
> supports and should use memory sealing if the loader supports it.
> Previous versions [2] had the sealing as an opt-out feature, however, it
> has some drawbacks where the backport is not straightforward, there is
> no clear semantic if memory sealing is a hint or requirement, some
> programs bypass the loader to apply relocation themselves and are
> incompatible with an opt-out feature [3], and it deviates from how other
> security hardening was added on Linux ecosystem (such as RELRO and
> non-executable stacks).
>
> A GNU property is used instead of a new dynamic section tag (like the
> one proposed for DT_GNU_FLAGS_1) because the memory sealing should be
> selectable for ET_EXEC and not only for ET_DYN. It also fits new opt-in
> security features like x86 CET or AArch64 BTI.
>
> 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 eighth patch adds memory sealing tests, they are enabled if the
> linker supports it.
>
> The last patch adds a new tunable, glibc.rtld.seal, which can be used to
> enforce memory sealing even if the programs or dependencies do not have
> the GNU_PROPERTY_MEMORY_SEAL. The tunable accepts two different values:
>
> * '0': where loaders follow the GNU_PROPERTY_MEMORY_SEAL attribute if
> * present.  This is the default and no sealing would be applied if the
> * object does not have the memory sealing attribute.
>
> * '1': where sealing is enforced even if the object does not have the
> * GNU_PROPERTY_MEMORY_SEAL.  Also, any syscall failure on memory sealing
> * aborts the programs.
>
> 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.11, along with some testing on a powerpc64le-linux-gnu VM.
>
I have tested the binutil and glibc patches in a Debian VM. My testing
confirms that the functionality aligns with the descriptions provided
in the patch series.

As reference: here is how the mapping looks like, with the default
configuration of binutil and glibc.

For example:
#test_glibc_sealed.out => sealed
#\_ lib4.so  dlopen(lib4.so, RT_LAZY|RTLD_NODELETE) => sealed
#| \_ lib4_1.so => sealed.
#\_ lib1.so => sealed
#\_ libc.so => sealed
#\_ ld.so => sealed.

test_glibc_sealed.out
[557a3d5db000-557a3d5dc000        ], [rd mr mw me sl      ]
[/root/workdir3/test2/test_glibc_sealed.out]
[557a3d5dc000-557a3d5dd000        ], [rd ex mr mw me sl   ]
[/root/workdir3/test2/test_glibc_sealed.out]
[557a3d5dd000-557a3d5de000        ], [rd mr mw me sl      ]
[/root/workdir3/test2/test_glibc_sealed.out]
[557a3d5de000-557a3d5df000        ], [rd mr mw me ac sl   ]
[/root/workdir3/test2/test_glibc_sealed.out]
[557a3d5df000-557a3d5e0000        ], [rd wr mr mw me ac sl]
[/root/workdir3/test2/test_glibc_sealed.out]
[557a49b0a000-557a49b2b000        ], [rd wr mr mw me ac   ] [[heap]]
[7f98f6690000-7f98f6691000        ], [rd mr mw me sl      ]
[/root/workdir3/test2/lib4_1.so]
[7f98f6691000-7f98f6692000        ], [rd ex mr mw me sl   ]
[/root/workdir3/test2/lib4_1.so]
[7f98f6692000-7f98f6693000        ], [rd mr mw me sl      ]
[/root/workdir3/test2/lib4_1.so]
[7f98f6693000-7f98f6694000        ], [rd mr mw me ac sl   ]
[/root/workdir3/test2/lib4_1.so]
[7f98f6694000-7f98f6695000        ], [rd wr mr mw me ac sl]
[/root/workdir3/test2/lib4_1.so]
[7f98f6695000-7f98f6696000        ], [rd mr mw me sl      ]
[/root/workdir3/test2/lib4.so]
[7f98f6696000-7f98f6697000        ], [rd ex mr mw me sl   ]
[/root/workdir3/test2/lib4.so]
[7f98f6697000-7f98f6698000        ], [rd mr mw me sl      ]
[/root/workdir3/test2/lib4.so]
[7f98f6698000-7f98f6699000        ], [rd mr mw me ac sl   ]
[/root/workdir3/test2/lib4.so]
[7f98f6699000-7f98f669a000        ], [rd wr mr mw me ac sl]
[/root/workdir3/test2/lib4.so]
[7f98f669a000-7f98f669d000        ], [rd wr mr mw me ac sl] [[anonymous]]
[7f98f669d000-7f98f66c1000        ], [rd mr mw me sl      ]
[/root/workdir3/target/lib/libc.so.6]
[7f98f66c1000-7f98f6824000        ], [rd ex mr mw me sl   ]
[/root/workdir3/target/lib/libc.so.6]
[7f98f6824000-7f98f687a000        ], [rd mr mw me sl      ]
[/root/workdir3/target/lib/libc.so.6]
[7f98f687a000-7f98f687e000        ], [rd mr mw me ac sl   ]
[/root/workdir3/target/lib/libc.so.6]
[7f98f687e000-7f98f6880000        ], [rd wr mr mw me ac sl]
[/root/workdir3/target/lib/libc.so.6]
[7f98f6880000-7f98f688d000        ], [rd wr mr mw me ac sl] [[anonymous]]
[7f98f688d000-7f98f688e000        ], [rd mr mw me sl      ]
[/root/workdir3/test2/lib1.so]
[7f98f688e000-7f98f688f000        ], [rd ex mr mw me sl   ]
[/root/workdir3/test2/lib1.so]
[7f98f688f000-7f98f6890000        ], [rd mr mw me sl      ]
[/root/workdir3/test2/lib1.so]
[7f98f6890000-7f98f6891000        ], [rd mr mw me ac sl   ]
[/root/workdir3/test2/lib1.so]
[7f98f6891000-7f98f6892000        ], [rd wr mr mw me ac sl]
[/root/workdir3/test2/lib1.so]
[7f98f6892000-7f98f6894000        ], [rd wr mr mw me ac sl] [[anonymous]]
[7f98f6894000-7f98f6898000        ], [rd mr pf io de dd   ] [[vvar]]
[7f98f6898000-7f98f689a000        ], [rd ex mr mw me de   ] [[vdso]]
[7f98f689a000-7f98f689b000        ], [rd mr mw me sl      ]
[/root/workdir3/target/lib/ld-linux-x86-64.so.2]
[7f98f689b000-7f98f68c3000        ], [rd ex mr mw me sl   ]
[/root/workdir3/target/lib/ld-linux-x86-64.so.2]
[7f98f68c3000-7f98f68ce000        ], [rd mr mw me sl      ]
[/root/workdir3/target/lib/ld-linux-x86-64.so.2]
[7f98f68ce000-7f98f68d0000        ], [rd mr mw me ac sl   ]
[/root/workdir3/target/lib/ld-linux-x86-64.so.2]
[7f98f68d0000-7f98f68d2000        ], [rd wr mr mw me ac sl]
[/root/workdir3/target/lib/ld-linux-x86-64.so.2]
[7fff9c392000-7fff9c3b3000        ], [rd wr mr mw me gd ac] [[stack]]
[ffffffffff600000-ffffffffff601000], [ex                  ] [[vsyscall]]

Except vvar/vdso/stack/heap/vsyscall, all mappings are sealed.
(The vvar/vdso/stack/vsyscall will be sealed by kernel, which I am working on)

-Jeff


> [1] https://man.openbsd.org/mimmutable.2
> [2] https://sourceware.org/pipermail/libc-alpha/2024-August/158836.html
> [3] https://glandium.org/blog/?p=4297
>
> Changes v2->v3:
> * Make the option opt-int instead of opt-out.
>

> Adhemerval Zanella (9):
>   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
>   elf: Add glibc.rtld.seal tunable
>
>  INSTALL                                       |   5 +
>  Makeconfig                                    |  17 ++
>  Makerules                                     |   2 +
>  NEWS                                          |  20 ++
>  configure                                     |  57 ++++
>  configure.ac                                  |  19 ++
>  elf/Makefile                                  |   1 +
>  elf/dl-load.c                                 |   7 +
>  elf/dl-map-segments.h                         |   6 +
>  elf/dl-minimal-malloc.c                       |   3 +
>  elf/dl-mseal-mode.h                           |  28 ++
>  elf/dl-open.c                                 |   7 +-
>  elf/dl-reloc.c                                |  64 ++++
>  elf/dl-support.c                              |  22 ++
>  elf/dl-tunables.list                          |   6 +
>  elf/elf.h                                     |   2 +
>  elf/rtld.c                                    |  27 +-
>  elf/setup-vdso.h                              |   2 +
>  elf/tst-rtld-list-tunables.exp                |   1 +
>  include/link.h                                |   8 +
>  manual/install.texi                           |   5 +
>  manual/memory.texi                            |  66 +++++
>  manual/tunables.texi                          |  35 +++
>  sysdeps/aarch64/dl-prop.h                     |   5 +
>  sysdeps/generic/dl-mseal.h                    |  23 ++
>  sysdeps/generic/dl-prop-mseal.h               |  36 +++
>  sysdeps/generic/dl-prop.h                     |   5 +
>  sysdeps/generic/ldsodefs.h                    |  14 +
>  sysdeps/unix/sysv/linux/Makefile              | 107 +++++++
>  sysdeps/unix/sysv/linux/Versions              |   1 +
>  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            |  48 +++
>  sysdeps/unix/sysv/linux/dl-mseal.h            |  27 ++
>  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/nios2/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 |  74 +++++
>  .../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   | 278 ++++++++++++++++++
>  .../sysv/linux/tst-dl_mseal-static-noseal.c   |  45 +++
>  sysdeps/unix/sysv/linux/tst-dl_mseal-static.c |  42 +++
>  .../unix/sysv/linux/tst-dl_mseal-tunable.c    |  76 +++++
>  sysdeps/unix/sysv/linux/tst-dl_mseal.c        |  72 +++++
>  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                         |   4 +
>  89 files changed, 1611 insertions(+), 6 deletions(-)
>  create mode 100644 elf/dl-mseal-mode.h
>  create mode 100644 sysdeps/generic/dl-mseal.h
>  create mode 100644 sysdeps/generic/dl-prop-mseal.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-tunable.c
>  create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal.c
>  create mode 100644 sysdeps/unix/sysv/linux/tst-mseal.c
>
> --
> 2.34.1
>
Cristian Rodríguez Oct. 31, 2024, 3:39 p.m. UTC | #2
On Tue, Oct 1, 2024 at 9:21 PM Jeff Xu <jeffxu@google.com> wrote:

> On Mon, Sep 30, 2024 at 1:08 PM Adhemerval Zanella
> <adhemerval.zanella@linaro.org> wrote:
> >
> > The Linux 6.10 (8be7258aad44b5e25977a98db136f677fa6f4370) added the
> > mseal syscall that allows blocking some memory operations on the VMA
> > range:
> >
>
This is a very nice & neccesary improvement.. what is the status of this
patchset?
Adhemerval Zanella Netto Nov. 1, 2024, 3 p.m. UTC | #3
On 31/10/24 12:39, Cristian Rodríguez wrote:
> 
> 
> On Tue, Oct 1, 2024 at 9:21 PM Jeff Xu <jeffxu@google.com <mailto:jeffxu@google.com>> wrote:
> 
>     On Mon, Sep 30, 2024 at 1:08 PM Adhemerval Zanella
>     <adhemerval.zanella@linaro.org <mailto:adhemerval.zanella@linaro.org>> wrote:
>     >
>     > The Linux 6.10 (8be7258aad44b5e25977a98db136f677fa6f4370) added the
>     > mseal syscall that allows blocking some memory operations on the VMA
>     > range:
>     >
> 
> This is a very nice & neccesary improvement.. what is the status of this patchset?

I still need to sort out the binutils patchset, H.J has asked to re-do
my initial approach of how to merge .gnu.attributes. The glibc patch did
not had much review though.
Olivier Dion Nov. 4, 2024, 5:31 p.m. UTC | #4
On Mon, 30 Sep 2024, Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote:

[...]

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

I have a concern of applying mseal(2) to whole executable regions on a
per-module granularity.  There are cases where some executable regions
might want to not be sealed by glibc or not sealed at all.

For example, I'm porting the Linux static keys [0] to user-space.  This
can be used for optimizing branches where the conditions are expected to
not change often or at all.  For examples:

    - Static tracepoints
    - Load time configurations
        - Enabling runtime assertions in production
        - Enabling loggings

A template for static key would look like this at the assembly level:

   program                                Out of line section

   inline asm goto
   jmp a               ->              a: nop
                                          load
                                          test
                                          cond branch l_yes (asm goto)
                                          fallthrough to l_no
   l_no:
      no callbacks
   l_yes:
      callbacks

The idea would be to patch the `nop' at label `a' to branch directly to
`l_no' or `l_yes'.  If code patching is not possible (e.g. due to
hardening), then a load/test/cond-branch is executed.

The level of indirection introduced by the out of line section
separates the program from the code patching.  This allows to keep the
memory seal on the program without impacting the static key patching
opportunity.

I see two different patching requirements.  For load-time
configuration, the patching is done once and then the seal can be
applied on the out of line section by the application itself.  For
tracepoints, mseal should not be applied because tracepoints can be
enabled/disabled during the execution of the program.

It is possible to bypass the mseal protection using `/proc/self/mem'
However this comes with some downsides.  First, a file descriptor is
required and all the concerns that it implies.  Second, accesses to
`/proc/self/mem' are made with calls to `access_remote_vm()' which are
basically memcpys from/to user-space to/from kernel-space.  Thus,
nothing atomic.  This imposes restriction on the type of patching that
can be done since we want to avoid a "stop the world" approach, i.e. we
want to do asynchronous cross-modifying code without stopping threads in
the program.

There are other cases outside of static keys.  What about patchable
function entries (-fpatchable-function-entry) or profiling (-mfentry,
-mnop-count, -minstrument-return)?  Should users use the tunable to
disable mseal on program when instrumentation/profiling is wanted?  Or
maybe we ought to implement something similar to static keys, i.e. a
level of indirection where mseal is relaxed for allowing patching.
Maybe mseal is not the good kind of protection for that and other
hardening mechanisms are better suited to prevent patchable code?

[...]

Thanks,
Olivier

[0] https://www.kernel.org/doc/html/latest/staging/static-keys.html