[PATCH v4 00/14] RELRO link maps

Florian Weimer fweimer@redhat.com
Sun Feb 2 21:12:42 GMT 2025


This series introduces a new security hardening.  The main goal is to
prevent direct overwrite attacks on the internal l_info[DT_FINI] and
l_infi[DT_FINI_ARRAY] members of the link map.  These are attractive
targets because the pointers are not obfuscated.  The path to DWARF data
via _dl_find_object is kept read-only as well.

During dlopen/dlmopen and dlclose, dynamic linker data structures are
temporarily made read-write using mprotect.  To offset the overhead from
that, the penultimate commit in the series implements a hash table for
dlopen.  It speeds up dlopen with many shared objects in the process,
and makes up for the additional mprotect overhead while starting Emacs,
for example.

The last commit optionally uses memory protection keys if available.
POWER and x86-64 CPU support that, but the x86-64 support is not usable
due to adverse interactions with signal handler.  The new tunable can be
used force their use, though.  This is purely a kernel limitation; a
different mode of operation could be selected with a pkey_alloc flag.
POWER also has a software limitation: modern system tends to use the
radix MMU, and protection keys are not implemented for that (only for
the hash MMU).  Not surprisingly, with memory protection keys active, I
could not measure any overhead (and the dlopen hash table often makes
startup and dlopen operations a bit faster).  AArch64 protection key
support is available in the glibc sources, but I have not been able to
test it on an implementation.

The mprotect-based implementation is still quite slow, even with the
speedup from the dlopen hash table.  This is very visible with the
nptl/tst-stack4 test case: in a previous test, its run time grows from
3.3 seconds to to 4.3 seconds.  (It remains at 3.3 seconds if I force
the use of memory protection keys.)  I have some ideas for speeding up
things further, but the memprotect overhead is quite unavoidable
unfortunately.  Things like plugin discover might be somewhat similar to
what nptl/tst-stack4 does.  But I expect these rapid dlopen/dlclose
sequences to be somewhat unusual, so the hardening should not have much
of an impact in practice.

The new data structures are more complex than what we had before.  The
dl-protmem.c allocator is not protected by a fork lock (unlike malloc,
which was used before).  This means that there is a possiblity that
dlopen will not work after multi-threaded fork.  We sort-of support that
as an extension (although GLRO(dl_load_write_lock) can still cause hangs
even today, I believe).  We can probably trade memory corruption for
hangs by careful use of GLRO(dl_load_write_lock).

I would like to add some tests for memory leaks, for example by marking
all protected memory allocations by chasing pointers from the roots, and
then checking that the gaps correspond exactly to the free chunks in the
protected memory allocator.

To counteract the dlclose overhead, we could stop unloading converters
in the iconv subsystem.  It does not seem to be a very useful thing to
do, now that we have the dlopen hash table and many DSOs do not slow us
down much (as long RTLD_LOCAL is used, of course).

More data structures should eventually be added under the GLPM umbrella.
The head of the link map lists, GL(dl_ns)[nsid]._ns_loaded, is a good
candidate for this.  These changes could happen incrementally over time.

Version 4 of this series merges some of the patches.  The first two
patches are new.  The introduction of struct link_map_private has been
dropped in this version, to aid with future rebases.  The optional
debugging protected memory allocator is gone.

In the patch list below, I'm adding links to Joseph's prior reviews
where available.

  elf: Default to ENOENT error in _dl_map_new_object
  aarch64: Enable internal use of memory protection keys
  Do not export <alloc_buffer.h> functions from libc
    (merge of two patches)
    <https://inbox.sourceware.org/libc-alpha/ed384da1-24e-7c72-5780-e3ba8b3c3ffd@redhat.com/>
    <https://inbox.sourceware.org/libc-alpha/3d85d0a4-9a40-9046-d0a2-d7e5f0f345dd@redhat.com/>
  support: Add <support/memprobe.h> for protection flags probing
    <https://inbox.sourceware.org/libc-alpha/7514e96e-ca15-6728-7ea1-b22891b78cc@redhat.com/>
  elf: Eliminate second loop in find_version in dl-version.c
    <https://inbox.sourceware.org/libc-alpha/6e8b2e62-d72d-6218-dfb1-edd78be9cba5@redhat.com/>
  elf: Disambiguate some failures in _dl_load_cache_lookup
    <https://inbox.sourceware.org/libc-alpha/2115e44e-77fc-2d29-ea4-b4d3cf5a1388@redhat.com/>
  elf: Merge the three implementations of _dl_dst_substitute
    <https://inbox.sourceware.org/libc-alpha/1087df9e-958d-9397-8d5-908db19c6150@redhat.com/>
  elf: Remove run-time-writable fields from struct link_map
    (merge of four patches)
    <https://inbox.sourceware.org/libc-alpha/f0843527-6aad-6f8b-383d-35f74455ca33@redhat.com/>
    <https://inbox.sourceware.org/libc-alpha/724e9492-3d66-9050-922e-3213679cb16@redhat.com/>
    <https://inbox.sourceware.org/libc-alpha/fa6ef045-377f-684a-c34b-1383314c875@redhat.com/>
    <https://inbox.sourceware.org/libc-alpha/adeb2d8-d2cd-4f44-3062-55d4f4c88a3@redhat.com/>  
  elf: Introduce GLPM accessor for the protected memory area
    <https://inbox.sourceware.org/libc-alpha/9119d6b3-3fab-5070-73a4-ed699ab28052@redhat.com/>
  elf: Bootstrap allocation for future protected memory allocator
    <https://inbox.sourceware.org/libc-alpha/accd49e-16e-43dd-622-82c62bdd859c@redhat.com/>
  elf: Implement a region-based protected memory allocator
    (merge of two patches, debugging allocator removed)
    <https://inbox.sourceware.org/libc-alpha/b270938f-76b6-113d-e1ee-c27dbe41ddce@redhat.com/>
    <https://inbox.sourceware.org/libc-alpha/cdf9dae-2e37-8515-1c65-892743f2aabe@redhat.com/>
  elf: Move most of the _dl_find_object data to the protected heap
    (merge of two patches)
    <https://inbox.sourceware.org/libc-alpha/6d5e490-f5d7-585-64b7-21c67d4369a@redhat.com/>
    <https://inbox.sourceware.org/libc-alpha/e44a6cb3-87df-e466-849a-67ab39cb3a95@redhat.com/>
  elf: Add hash tables to speed up DT_NEEDED, dlopen lookups
    <https://inbox.sourceware.org/libc-alpha/7c966325-5dc7-ef9e-9da0-9cb39b8f5a68@redhat.com/>
  elf: Use memory protection keys for the protected memory allocator
    <https://inbox.sourceware.org/libc-alpha/886716b6-9e9b-ccba-155-e244478c3c3@redhat.com/>

 NEWS                                          |   4 +-
 elf/Makefile                                  |  24 +
 elf/circleload1.c                             |   3 +-
 elf/dl-cache.c                                |  53 +-
 elf/dl-call_fini.c                            |   2 +-
 elf/dl-close.c                                | 140 ++---
 elf/dl-deps.c                                 |  84 ++-
 elf/dl-diagnostics.c                          |   2 +
 elf/dl-dst.h                                  |  56 --
 elf/dl-find_object.c                          | 135 ++---
 elf/dl-find_object.h                          |   3 -
 elf/dl-fini.c                                 |   8 +-
 elf/dl-init.c                                 |   4 +-
 elf/dl-libc_freeres.c                         |  20 +-
 elf/dl-libname.c                              | 282 +++++++++
 elf/dl-libname.h                              | 120 ++++
 elf/dl-load.c                                 | 363 +++++-------
 elf/dl-lookup.c                               |  42 +-
 elf/dl-misc.c                                 |  18 -
 elf/dl-object.c                               | 159 +++--
 elf/dl-open.c                                 |  59 +-
 elf/dl-origin.c                               |   3 -
 elf/dl-protmem-internal.h                     |  66 +++
 elf/dl-protmem.c                              | 558 ++++++++++++++++++
 elf/dl-protmem.h                              | 102 ++++
 elf/dl-protmem_bootstrap.h                    |  36 ++
 elf/dl-reloc.c                                |  15 +-
 elf/dl-sort-maps.c                            |  26 +-
 elf/dl-static-tls.h                           |   8 +-
 elf/dl-support.c                              |  17 +-
 elf/dl-tls.c                                  |  37 +-
 elf/dl-tunables.list                          |   6 +
 elf/dl-version.c                              |  29 +-
 elf/get-dynamic-info.h                        |   2 +-
 elf/loadtest.c                                |   4 +-
 elf/neededtest.c                              |   3 +-
 elf/neededtest2.c                             |   3 +-
 elf/neededtest3.c                             |   3 +-
 elf/neededtest4.c                             |   3 +-
 elf/pldd-xx.c                                 |  19 +-
 elf/pldd.c                                    |   1 +
 elf/rtld.c                                    | 291 +++++----
 elf/setup-vdso.h                              |  24 +-
 elf/sotruss-lib.c                             |   4 +-
 elf/tst-dl-protmem.c                          | 360 +++++++++++
 elf/tst-relro-linkmap-disabled-mod1.c         |  46 ++
 elf/tst-relro-linkmap-disabled-mod2.c         |   2 +
 elf/tst-relro-linkmap-disabled.c              |  64 ++
 elf/tst-relro-linkmap-mod1.c                  |  42 ++
 elf/tst-relro-linkmap-mod2.c                  |   2 +
 elf/tst-relro-linkmap-mod3.c                  |   2 +
 elf/tst-relro-linkmap.c                       | 112 ++++
 elf/tst-rtld-dash-dash.sh                     |   2 +-
 elf/tst-rtld-does-not-exist.sh                |   2 +-
 elf/tst-rtld-list-tunables.exp                |   1 +
 elf/tst-rtld-nomem.c                          | 177 ++++++
 elf/tst-tls_tp_offset.c                       |   3 +-
 elf/unload.c                                  |   2 +-
 elf/unload2.c                                 |   2 +-
 htl/pt-alloc.c                                |   5 +-
 include/alloc_buffer.h                        |  27 +-
 include/link.h                                | 131 ++--
 malloc/Makefile                               |   6 +-
 malloc/Versions                               |   7 -
 malloc/alloc_buffer_alloc_array.c             |   1 -
 malloc/alloc_buffer_allocate.c                |   1 -
 malloc/alloc_buffer_copy_bytes.c              |   1 -
 malloc/alloc_buffer_copy_string.c             |   1 -
 malloc/alloc_buffer_create_failure.c          |   9 +-
 malloc/tst-alloc_buffer.c                     |   4 +
 manual/tunables.texi                          |  29 +
 nptl/Versions                                 |   3 +-
 nptl/pthread_create.c                         |   8 +
 nptl_db/db_info.c                             |   1 +
 nptl_db/structs.def                           |   3 +-
 nptl_db/td_thr_tlsbase.c                      |  12 +-
 nss/Makefile                                  |   4 +-
 stdlib/cxa_thread_atexit_impl.c               |   4 +-
 support/Makefile                              |   3 +
 support/memprobe.h                            |  43 ++
 support/support-alloc_buffer.c                |  26 +
 support/support_memprobe.c                    | 251 ++++++++
 support/tst-support_memprobe.c                | 111 ++++
 sysdeps/aarch64/dl-machine.h                  |   5 +-
 sysdeps/alpha/dl-machine.h                    |   4 +-
 sysdeps/arc/dl-machine.h                      |   3 +-
 sysdeps/arm/dl-machine.h                      |   4 +-
 sysdeps/csky/dl-machine.h                     |   2 +-
 sysdeps/generic/dl-early_mmap.h               |  35 ++
 sysdeps/generic/dl-protmem-pkey.h             |  20 +
 sysdeps/generic/ldsodefs.h                    |  97 +--
 sysdeps/hppa/dl-machine.h                     |   3 +-
 sysdeps/i386/dl-machine.h                     |  11 +-
 sysdeps/loongarch/dl-tls.h                    |   2 +-
 sysdeps/m68k/dl-tls.h                         |   2 +-
 sysdeps/microblaze/dl-machine.h               |   3 +-
 sysdeps/mips/Makefile                         |   6 +
 sysdeps/mips/dl-tls.h                         |   2 +-
 sysdeps/or1k/dl-machine.h                     |   4 +-
 sysdeps/powerpc/dl-tls.h                      |   2 +-
 sysdeps/powerpc/powerpc32/dl-machine.h        |   4 +-
 sysdeps/powerpc/powerpc64/dl-machine.h        |   4 +-
 sysdeps/riscv/dl-tls.h                        |   2 +-
 sysdeps/s390/s390-32/dl-machine.h             |   5 +-
 sysdeps/s390/s390-64/dl-machine.h             |   5 +-
 sysdeps/sh/dl-machine.h                       |   7 +-
 sysdeps/sparc/sparc32/dl-machine.h            |   4 +-
 sysdeps/sparc/sparc64/dl-machine.h            |   4 +-
 sysdeps/unix/sysv/linux/aarch64/pkey_get.c    |   4 +-
 sysdeps/unix/sysv/linux/aarch64/pkey_set.c    |   4 +-
 sysdeps/unix/sysv/linux/dl-early_allocate.c   |  17 +-
 sysdeps/unix/sysv/linux/dl-early_mmap.h       |  41 ++
 sysdeps/unix/sysv/linux/dl-origin.c           |   1 -
 sysdeps/unix/sysv/linux/dl-protmem-pkey.h     |  23 +
 sysdeps/unix/sysv/linux/dl-sysdep.c           |   2 +
 sysdeps/unix/sysv/linux/x86/dl-protmem-pkey.h |  26 +
 sysdeps/x86/dl-prop.h                         |   2 +-
 sysdeps/x86_64/dl-machine.h                   |   5 +-
 118 files changed, 3629 insertions(+), 1087 deletions(-)
 delete mode 100644 elf/dl-dst.h
 create mode 100644 elf/dl-libname.c
 create mode 100644 elf/dl-libname.h
 create mode 100644 elf/dl-protmem-internal.h
 create mode 100644 elf/dl-protmem.c
 create mode 100644 elf/dl-protmem.h
 create mode 100644 elf/dl-protmem_bootstrap.h
 create mode 100644 elf/tst-dl-protmem.c
 create mode 100644 elf/tst-relro-linkmap-disabled-mod1.c
 create mode 100644 elf/tst-relro-linkmap-disabled-mod2.c
 create mode 100644 elf/tst-relro-linkmap-disabled.c
 create mode 100644 elf/tst-relro-linkmap-mod1.c
 create mode 100644 elf/tst-relro-linkmap-mod2.c
 create mode 100644 elf/tst-relro-linkmap-mod3.c
 create mode 100644 elf/tst-relro-linkmap.c
 create mode 100644 elf/tst-rtld-nomem.c
 create mode 100644 support/memprobe.h
 create mode 100644 support/support-alloc_buffer.c
 create mode 100644 support/support_memprobe.c
 create mode 100644 support/tst-support_memprobe.c
 create mode 100644 sysdeps/generic/dl-early_mmap.h
 create mode 100644 sysdeps/generic/dl-protmem-pkey.h
 create mode 100644 sysdeps/unix/sysv/linux/dl-early_mmap.h
 create mode 100644 sysdeps/unix/sysv/linux/dl-protmem-pkey.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/dl-protmem-pkey.h


base-commit: fc058b46c78f090580c1ca5b785b54ae4092f0c1
-- 
2.48.1



More information about the Libc-alpha mailing list