From patchwork Tue Jul 4 20:02:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 1803355 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=UlkBc4dl; dkim-atps=neutral Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QwYcD0sRMz20Pf for ; Wed, 5 Jul 2023 06:02:35 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C2A31385700D for ; Tue, 4 Jul 2023 20:02:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C2A31385700D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1688500953; bh=xwt3ENazkamxEtdiwq56T275+wVtG5Nc8ag8gYmwSrs=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=UlkBc4dlvCH/7hzBmAhc9FOhn4VPaxEcrNdPdd8uv8kO8Od4PClRwL6v5+OK4oY/d Ifepkv/cElskXGOigJTiWZDCrVBHcakOLYP0bSZ+g6d0/QkrFT7XR762q3qDpEIUJx UEoVE/tB0WaOBcD/uctQGDDSVkVG+xEIkjkq4YQA= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 302893858D35 for ; Tue, 4 Jul 2023 20:02:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 302893858D35 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-538-p1hY0hlfOjSsB-t1w1KtRw-1; Tue, 04 Jul 2023 16:02:15 -0400 X-MC-Unique: p1hY0hlfOjSsB-t1w1KtRw-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 717FF802666 for ; Tue, 4 Jul 2023 20:02:15 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.2.16.19]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5CC2D15230A6 for ; Tue, 4 Jul 2023 20:02:14 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH 00/33] RFC: RELRO link maps Message-ID: X-From-Line: 477cc628fed2769f25399d7674080dd257a80d46 Mon Sep 17 00:00:00 2001 Date: Tue, 04 Jul 2023 22:02:12 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-4.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Sender: "Libc-alpha" 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). There are some limitations, so this is 2.39 material at this point. 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: on my machine, 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. Maybe I should remove the debugging memory allocator and only add the region-based one. Some of the commits in the series could perhaps be reordered and merged. To counteract the dlclose ooverhead, we could stop unloading converters in the iconv subsystem. It does not seem to be a vert 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. Thanks, Florian Florian Weimer (33): support: Add for protection flags probing misc: Enable internal use of memory protection keys elf: Remove _dl_sysdep_open_object hook function elf: Eliminate second loop in find_version in dl-version.c elf: In rtld_setup_main_map, assume ld.so has a DYNAMIC segment elf: Remove version assert in check_match in elf/dl-lookup.c elf: Disambiguate some failures in _dl_load_cache_lookup elf: Eliminate alloca in open_verify Do not export functions from libc elf: Make usable in ld.so elf: Merge the three implementations of _dl_dst_substitute elf: _dl_find_object may return 1 during early startup (bug 30515) elf: Move __rtld_malloc_init_stubs call into _dl_start_final elf: Merge __dl_libc_freemem into __rtld_libc_freeres elf: Use struct link_map_private for the internal link map elf: Remove run-time-writable fields from struct link_map_private elf: Move l_tls_offset into read-write part of link map elf: Allocate auditor state after read-write link map elf: Move link map fields used by dependency sorting to writable part elf: Split _dl_lookup_map, _dl_map_new_object from _dl_map_object elf: Add l_soname accessor function for DT_SONAME values elf: _dl_rtld_map should not exist in static builds elf: Introduce GLPM accessor for the protected memory area elf: Bootstrap allocation for future protected memory allocator elf: Implement a basic protected memory allocator elf: Move most of the _dl_find_object data to the protected heap elf: Switch to a region-based protected memory allocator elf: Determine the caller link map in _dl_open elf: Add fast path to dlopen for fully-opened maps elf: Use _dl_find_object instead of _dl_find_dso_for_object in dlopen elf: Put critical _dl_find_object pointers into protected memory area elf: Add hash tables to speed up DT_NEEDED, dlopen lookups elf: Use memory protection keys for the protected memory allocator NEWS | 4 + csu/libc-start.c | 7 +- csu/libc-tls.c | 8 +- debug/backtracesyms.c | 4 +- debug/backtracesymsfd.c | 6 +- dlfcn/dladdr1.c | 7 +- dlfcn/dlinfo.c | 4 +- dlfcn/tst-dlinfo-phdr.c | 15 +- elf/Makefile | 25 +- elf/circleload1.c | 18 +- elf/dl-addr-obj.c | 4 +- elf/dl-addr.c | 13 +- elf/dl-audit.c | 25 +- elf/dl-cache.c | 33 +- elf/dl-call-libc-early-init.c | 2 +- elf/dl-call_fini.c | 11 +- elf/dl-close.c | 181 ++--- elf/dl-debug.c | 12 - elf/dl-deps.c | 177 +++-- elf/dl-diagnostics.c | 2 + elf/dl-find_object.c | 169 ++--- elf/dl-find_object.h | 21 +- elf/dl-fini.c | 16 +- elf/dl-fptr.c | 6 +- elf/dl-init.c | 22 +- elf/dl-iteratephdr.c | 11 +- elf/dl-libc.c | 115 +-- elf/dl-libc_freeres.c | 94 ++- elf/dl-libname.c | 275 +++++++ elf/dl-libname.h | 121 ++++ elf/dl-load.c | 499 ++++++------- elf/dl-load.h | 10 +- elf/dl-lookup-direct.c | 5 +- elf/dl-lookup.c | 150 ++-- elf/dl-machine-reject-phdr.h | 4 +- elf/dl-map-segments.h | 16 +- elf/dl-minimal.c | 4 +- elf/dl-misc.c | 20 - elf/dl-object.c | 181 +++-- elf/dl-open.c | 225 +++--- elf/dl-profile.c | 4 +- elf/dl-protmem-internal.h | 100 +++ elf/dl-protmem.c | 679 ++++++++++++++++++ elf/dl-protmem.h | 102 +++ elf/dl-protmem_bootstrap.h | 36 + elf/dl-reloc-static-pie.c | 7 +- elf/dl-reloc.c | 46 +- elf/dl-runtime.c | 6 +- elf/dl-setup_hash.c | 2 +- elf/dl-sort-maps.c | 53 +- elf/dl-static-tls.h | 10 +- elf/dl-support.c | 46 +- elf/dl-sym-post.h | 6 +- elf/dl-sym.c | 10 +- elf/dl-symaddr.c | 2 +- elf/dl-sysdep-open.h | 45 -- elf/dl-tls.c | 61 +- elf/dl-tunables.list | 6 + elf/dl-unmap-segments.h | 2 +- elf/dl-usage.c | 2 +- elf/dl-version.c | 77 +- elf/do-rel.h | 19 +- elf/dynamic-link.h | 14 +- elf/get-dynamic-info.h | 12 +- elf/libc-early-init.h | 6 +- elf/loadtest.c | 34 +- elf/neededtest.c | 18 +- elf/neededtest2.c | 18 +- elf/neededtest3.c | 18 +- elf/neededtest4.c | 18 +- elf/pldd-xx.c | 19 +- elf/pldd.c | 1 + elf/rtld.c | 455 ++++++------ elf/rtld_static_init.c | 2 +- elf/setup-vdso.h | 48 +- elf/sotruss-lib.c | 5 +- elf/sprof.c | 27 +- elf/tlsdeschtab.h | 4 +- elf/tst-_dl_addr_inside_object.c | 13 +- elf/tst-audit19a.c | 2 +- elf/tst-auditmod28.c | 11 + elf/tst-dl-protmem.c | 364 ++++++++++ elf/tst-dl_find_object-threads.c | 6 +- elf/tst-dl_find_object.c | 19 +- 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-list-tunables.exp | 1 + elf/tst-rtld-nomem.c | 177 +++++ elf/tst-tls6.c | 8 +- elf/tst-tls7.c | 8 +- elf/tst-tls8.c | 24 +- elf/unload.c | 10 +- elf/unload2.c | 10 +- htl/pt-alloc.c | 7 +- include/alloc_buffer.h | 26 +- include/dlfcn.h | 6 +- include/link.h | 178 +++-- include/rtld-malloc.h | 5 +- include/set-freeres.h | 1 - libio/vtables.c | 2 +- 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 | 7 +- malloc/set-freeres.c | 2 - malloc/tst-alloc_buffer.c | 4 + manual/tunables.texi | 29 + nptl/Versions | 3 +- nptl/pthread_create.c | 8 + nptl_db/db_info.c | 3 +- nptl_db/structs.def | 3 +- nptl_db/td_thr_tlsbase.c | 12 +- nss/Makefile | 4 +- stdlib/cxa_thread_atexit_impl.c | 10 +- stdlib/tst-tls-atexit.c | 10 +- support/Makefile | 3 + support/memprobe.h | 43 ++ support/support-alloc_buffer.c | 26 + support/support_memprobe.c | 251 +++++++ support/tst-support_memprobe.c | 118 +++ sysdeps/aarch64/dl-bti.c | 14 +- sysdeps/aarch64/dl-lookupcfg.h | 4 +- sysdeps/aarch64/dl-machine.h | 29 +- sysdeps/aarch64/dl-prop.h | 12 +- sysdeps/aarch64/dl-tlsdesc.h | 2 +- sysdeps/aarch64/tlsdesc.c | 2 +- sysdeps/alpha/dl-machine.h | 24 +- sysdeps/arc/dl-machine.h | 21 +- sysdeps/arm/dl-lookupcfg.h | 4 +- sysdeps/arm/dl-machine.h | 43 +- sysdeps/arm/dl-tlsdesc.h | 2 +- sysdeps/arm/tlsdesc.c | 2 +- sysdeps/csky/dl-machine.h | 22 +- sysdeps/generic/dl-debug.h | 2 +- sysdeps/generic/dl-early_mmap.h | 35 + sysdeps/generic/dl-fptr.h | 4 +- sysdeps/generic/dl-prop.h | 8 +- sysdeps/generic/dl-protected.h | 10 +- sysdeps/generic/dl-protmem-pkey.h | 20 + sysdeps/generic/ldsodefs.h | 277 ++++--- sysdeps/generic/rtld_static_init.h | 3 +- sysdeps/hppa/dl-fptr.c | 10 +- sysdeps/hppa/dl-lookupcfg.h | 6 +- sysdeps/hppa/dl-machine.h | 29 +- sysdeps/hppa/dl-runtime.c | 4 +- sysdeps/hppa/dl-runtime.h | 2 +- sysdeps/hppa/dl-symaddr.c | 2 +- sysdeps/htl/pthreadP.h | 2 +- sysdeps/i386/dl-machine.h | 41 +- sysdeps/i386/dl-tlsdesc.h | 2 +- sysdeps/i386/tlsdesc.c | 2 +- sysdeps/ia64/dl-lookupcfg.h | 6 +- sysdeps/ia64/dl-machine.h | 29 +- sysdeps/loongarch/dl-machine.h | 19 +- sysdeps/loongarch/dl-tls.h | 2 +- sysdeps/m68k/dl-machine.h | 20 +- sysdeps/m68k/dl-tls.h | 2 +- sysdeps/microblaze/dl-machine.h | 23 +- sysdeps/mips/Makefile | 6 + sysdeps/mips/dl-debug.h | 2 +- sysdeps/mips/dl-machine-reject-phdr.h | 20 +- sysdeps/mips/dl-machine.h | 74 +- sysdeps/mips/dl-tls.h | 2 +- sysdeps/mips/dl-trampoline.c | 19 +- sysdeps/nios2/dl-init.c | 6 +- sysdeps/nios2/dl-machine.h | 19 +- sysdeps/nios2/dl-tls.h | 2 +- sysdeps/nptl/dl-mutex.c | 2 +- sysdeps/or1k/dl-machine.h | 20 +- sysdeps/powerpc/dl-tls.h | 2 +- sysdeps/powerpc/powerpc32/dl-machine.c | 19 +- sysdeps/powerpc/powerpc32/dl-machine.h | 40 +- sysdeps/powerpc/powerpc64/dl-machine.c | 8 +- sysdeps/powerpc/powerpc64/dl-machine.h | 48 +- sysdeps/riscv/dl-machine.h | 26 +- sysdeps/riscv/dl-tls.h | 2 +- sysdeps/s390/s390-32/dl-machine.h | 29 +- sysdeps/s390/s390-64/dl-machine.h | 29 +- sysdeps/sh/dl-machine.h | 36 +- sysdeps/sparc/sparc32/dl-machine.h | 24 +- sysdeps/sparc/sparc64/dl-irel.h | 2 +- sysdeps/sparc/sparc64/dl-machine.h | 27 +- sysdeps/sparc/sparc64/dl-plt.h | 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/dl-vdso.h | 2 +- .../sysv/linux/include/bits/mman-shared.h | 16 + sysdeps/unix/sysv/linux/pkey_get.c | 5 +- sysdeps/unix/sysv/linux/pkey_mprotect.c | 4 +- sysdeps/unix/sysv/linux/pkey_set.c | 5 +- sysdeps/unix/sysv/linux/powerpc/libc-start.c | 2 +- .../sysv/linux/powerpc/powerpc64/ldsodefs.h | 14 +- .../sysv/linux/powerpc/powerpc64/pkey_get.c | 4 +- .../sysv/linux/powerpc/powerpc64/pkey_set.c | 4 +- .../sysv/linux/powerpc/rtld_static_init.h | 3 +- sysdeps/unix/sysv/linux/syscalls.list | 4 +- sysdeps/unix/sysv/linux/x86/dl-protmem-pkey.h | 26 + sysdeps/unix/sysv/linux/x86/pkey_get.c | 5 +- sysdeps/unix/sysv/linux/x86/pkey_set.c | 5 +- sysdeps/x86/dl-cet.c | 4 +- sysdeps/x86/dl-lookupcfg.h | 4 +- sysdeps/x86/dl-prop.h | 29 +- sysdeps/x86_64/dl-machine.h | 39 +- sysdeps/x86_64/dl-tlsdesc.h | 2 +- sysdeps/x86_64/tlsdesc.c | 2 +- 216 files changed, 5271 insertions(+), 2444 deletions(-) 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 delete mode 100644 elf/dl-sysdep-open.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/include/bits/mman-shared.h create mode 100644 sysdeps/unix/sysv/linux/x86/dl-protmem-pkey.h base-commit: e18c293af0ece38921ad71fbd76ff8049c3b2d67