Message ID | 20240930200831.1669010-1-adhemerval.zanella@linaro.org |
---|---|
Headers | show |
Series | Add support for memory sealing | expand |
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 >