From patchwork Fri Feb 10 22:21:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 1740702 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=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=sWBOQyF6; dkim-atps=neutral Received: from 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 4PD7Wd5X3dz23fc for ; Sat, 11 Feb 2023 09:22:05 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0D93E3850437 for ; Fri, 10 Feb 2023 22:22:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0D93E3850437 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1676067723; bh=QBJ6hs8jRDufzZTT7/16R53R9zl+cl/Kc/5e3nHCzrM=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=sWBOQyF6gK3YqoPVttcQmOEyn/5QVkyT/qorKXc8qYIPexNn+0iBmUX7NK57yj8Jz JzbmlktdGy870cmask5y6Lv/shxLRqUH3sEByUNntaTgIIn+BkhFW4e1cvi69mh2f1 FtuSFNTKYBcVzIjVKjwT/WjPJL7uy+zvr5KFexZU= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pj1-x102f.google.com (mail-pj1-x102f.google.com [IPv6:2607:f8b0:4864:20::102f]) by sourceware.org (Postfix) with ESMTPS id 61FD73858414 for ; Fri, 10 Feb 2023 22:21:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 61FD73858414 Received: by mail-pj1-x102f.google.com with SMTP id d13-20020a17090ad3cd00b0023127b2d602so6975654pjw.2 for ; Fri, 10 Feb 2023 14:21:45 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=QBJ6hs8jRDufzZTT7/16R53R9zl+cl/Kc/5e3nHCzrM=; b=Qg63mUbXTXdAC+c2QGXbKI0dC4DhkVjQ7VKSrBHDfhut6QAh6o+gowHj72cGTZBeQP hYv/dqM3t6MvRWmhwn/J3FppUK9TdU3ne2VHCa9zlm3JP4q92zYN9/mULglg7krqmL0e d50OQwAQbTjRcmZHQgLVTV0fZrKGoH0ZznCkswTaOGPtL195Zkp2mqAARwFYiSGHkEcX WEBpzeR9kja1sANzHFUobfjAAhyWtLqiZ+G+Wfn/WUZixk0k2SF+FvqGRl4YqBLCFtWb 0eRhxOg5dfvW0wyE6DaABr9qCEzZI4x1ekPZ71gU5NyAPguh2cXaaMvsPacaT+chIFn1 3kLA== X-Gm-Message-State: AO0yUKWpouQ+YfnJ+kKYx067tL2C6mDnjMEVGJxIcG9WKf08SE9xINb9 ki/evVnPI0qog70v+dG46H236NwSoy4= X-Google-Smtp-Source: AK7set+fAXRmm1Vp4rDe0H8BFhq3hLAHrp7y/EgTv4qcn9Dcen0v+tptvQ2KSjfYtsPCkTsC1aYJFw== X-Received: by 2002:a17:903:230a:b0:196:2546:7cdd with SMTP id d10-20020a170903230a00b0019625467cddmr7942046plh.38.1676067704054; Fri, 10 Feb 2023 14:21:44 -0800 (PST) Received: from gnu-cfl-3.localdomain ([172.56.31.195]) by smtp.gmail.com with ESMTPSA id p4-20020a170902780400b001929f0b4582sm3759414pll.300.2023.02.10.14.21.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Feb 2023 14:21:43 -0800 (PST) Received: from gnu-cfl-3.. (localhost [IPv6:::1]) by gnu-cfl-3.localdomain (Postfix) with ESMTP id 47E1D740149; Fri, 10 Feb 2023 14:21:42 -0800 (PST) To: libc-alpha@sourceware.org Cc: Carlos O'Donell , Florian Weimer Subject: [PATCH v2] x86-64: Add glibc.cpu.prefer_map_32bit_exec [BZ #28656] Date: Fri, 10 Feb 2023 14:21:42 -0800 Message-Id: <20230210222142.17943-1-hjl.tools@gmail.com> X-Mailer: git-send-email 2.39.1 MIME-Version: 1.0 X-Spam-Status: No, score=-3025.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP 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: "H.J. Lu via Libc-alpha" From: "H.J. Lu" Reply-To: "H.J. Lu" Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Sender: "Libc-alpha" Crossing 2GB boundaries with indirect calls and jumps can use more branch prediction resources on Intel Golden Cove CPU (see the "Misprediction for Branches >2GB" section in Intel 64 and IA-32 Architectures Optimization Reference Manual.) There is visible performance improvement on workloads with many PLT calls when executable and shared libraries are mmapped below 2GB. Add the Prefer_MAP_32BIT_EXEC bit so that mmap will try to map executable or denywrite pages in shared libraries with MAP_32BIT first. NB: Prefer_MAP_32BIT_EXEC reduces bits available for address space layout randomization (ASLR), which is always disabled for SUID programs and can only be enabled by the tunable, glibc.cpu.prefer_map_32bit_exec, or the environment variable, LD_PREFER_MAP_32BIT_EXEC. This works only between shared libraries or between shared libraries and executables with addresses below 2GB. PIEs are usually mapped above 4GB by the kernel. --- manual/tunables.texi | 33 ++++++++++---- sysdeps/unix/sysv/linux/x86_64/64/Makefile | 25 +++++++++++ .../sysv/linux/x86_64/64/dl-tunables.list | 29 +++++++++++++ .../unix/sysv/linux/x86_64/64/mmap_internal.h | 43 +++++++++++++++++++ .../sysv/linux/x86_64/64/tst-map-32bit-1a.c | 34 +++++++++++++++ .../sysv/linux/x86_64/64/tst-map-32bit-1b.c | 1 + .../sysv/linux/x86_64/64/tst-map-32bit-mod.c | 33 ++++++++++++++ sysdeps/x86/cpu-features.c | 15 +++++++ ...cpu-features-preferred_feature_index_1.def | 1 + 9 files changed, 205 insertions(+), 9 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c diff --git a/manual/tunables.texi b/manual/tunables.texi index c2630b83ab..f63eb2f8a2 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -35,27 +35,32 @@ tunables with minimum and maximum values: @example $ /lib64/ld-linux-x86-64.so.2 --list-tunables glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10) -glibc.elision.skip_lock_after_retries: 3 (min: -2147483648, max: 2147483647) +glibc.elision.skip_lock_after_retries: 3 (min: 0, max: 2147483647) glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff) glibc.malloc.perturb: 0 (min: 0, max: 255) glibc.cpu.x86_shared_cache_size: 0x100000 (min: 0x0, max: 0xffffffffffffffff) +glibc.pthread.rseq: 1 (min: 0, max: 1) +glibc.cpu.prefer_map_32bit_exec: 0 (min: 0, max: 1) glibc.mem.tagging: 0 (min: 0, max: 255) -glibc.elision.tries: 3 (min: -2147483648, max: 2147483647) +glibc.elision.tries: 3 (min: 0, max: 2147483647) glibc.elision.enable: 0 (min: 0, max: 1) -glibc.cpu.x86_rep_movsb_threshold: 0x1000 (min: 0x100, max: 0xffffffffffffffff) +glibc.malloc.hugetlb: 0x0 (min: 0x0, max: 0xffffffffffffffff) +glibc.cpu.x86_rep_movsb_threshold: 0x2000 (min: 0x100, max: 0xffffffffffffffff) glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0xffffffffffffffff) -glibc.elision.skip_lock_busy: 3 (min: -2147483648, max: 2147483647) -glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0xffffffffffffffff) +glibc.rtld.dynamic_sort: 2 (min: 1, max: 2) +glibc.elision.skip_lock_busy: 3 (min: 0, max: 2147483647) +glibc.malloc.top_pad: 0x20000 (min: 0x0, max: 0xffffffffffffffff) glibc.cpu.x86_rep_stosb_threshold: 0x800 (min: 0x1, max: 0xffffffffffffffff) -glibc.cpu.x86_non_temporal_threshold: 0xc0000 (min: 0x4040, max: 0x0fffffffffffffff) +glibc.cpu.x86_non_temporal_threshold: 0xc0000 (min: 0x4040, max: 0xfffffffffffffff) glibc.cpu.x86_shstk: +glibc.pthread.stack_cache_size: 0x2800000 (min: 0x0, max: 0xffffffffffffffff) glibc.cpu.hwcap_mask: 0x6 (min: 0x0, max: 0xffffffffffffffff) -glibc.malloc.mmap_max: 0 (min: -2147483648, max: 2147483647) -glibc.elision.skip_trylock_internal_abort: 3 (min: -2147483648, max: 2147483647) +glibc.malloc.mmap_max: 0 (min: 0, max: 2147483647) +glibc.elision.skip_trylock_internal_abort: 3 (min: 0, max: 2147483647) glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0xffffffffffffffff) glibc.cpu.x86_ibt: glibc.cpu.hwcaps: -glibc.elision.skip_lock_internal_abort: 3 (min: -2147483648, max: 2147483647) +glibc.elision.skip_lock_internal_abort: 3 (min: 0, max: 2147483647) glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0xffffffffffffffff) glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff) glibc.cpu.x86_data_cache_size: 0x8000 (min: 0x0, max: 0xffffffffffffffff) @@ -580,6 +585,16 @@ instead. This tunable is specific to i386 and x86-64. @end deftp +@deftp Tunable glibc.cpu.prefer_map_32bit_exec +When this tunable is set to \code{1}, shared libraries of non-setuid +programs will be mmapped below 2GB with MAP_32BIT. + +Note that the @env{LD_PREFER_MAP_32BIT_EXEC} environment is an alias of +this tunable. + +This tunable is specific to 64-bit x86-64. +@end deftp + @node Memory Related Tunables @section Memory Related Tunables @cindex memory related tunables diff --git a/sysdeps/unix/sysv/linux/x86_64/64/Makefile b/sysdeps/unix/sysv/linux/x86_64/64/Makefile index a7b6dc5a53..8ff4f27786 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/Makefile +++ b/sysdeps/unix/sysv/linux/x86_64/64/Makefile @@ -1,2 +1,27 @@ # The default ABI is 64. default-abi := 64 + +ifeq ($(subdir),elf) +ifneq ($(have-tunables),no) + +tests-map-32bit = \ + tst-map-32bit-1a \ + tst-map-32bit-1b \ +# tests-map-32bit +tst-map-32bit-1a-no-pie = yes +tst-map-32bit-1b-no-pie = yes +tests += $(tests-map-32bit) + +modules-map-32bit = \ + tst-map-32bit-mod \ +# modules-map-32bit +modules-names += $(modules-map-32bit) + +$(objpfx)tst-map-32bit-mod.so: $(libsupport) +tst-map-32bit-1a-ENV = LD_PREFER_MAP_32BIT_EXEC=1 +$(objpfx)tst-map-32bit-1a: $(objpfx)tst-map-32bit-mod.so +tst-map-32bit-1b-ENV = GLIBC_TUNABLES=glibc.cpu.prefer_map_32bit_exec=1 +$(objpfx)tst-map-32bit-1b: $(objpfx)tst-map-32bit-mod.so + +endif +endif diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list new file mode 100644 index 0000000000..0aab52e662 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list @@ -0,0 +1,29 @@ +# x86-64 specific tunables. +# Copyright (C) 2023 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +glibc { + cpu { + prefer_map_32bit_exec { + type: INT_32 + minval: 0 + maxval: 1 + env_alias: LD_PREFER_MAP_32BIT_EXEC + security_level: SXID_IGNORE + } + } +} diff --git a/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h b/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h new file mode 100644 index 0000000000..33dec3f805 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h @@ -0,0 +1,43 @@ +/* Linux mmap system call. x86-64 version. + Copyright (C) 2015-2023 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef MMAP_X86_64_INTERNAL_H +#define MMAP_X86_64_INTERNAL_H + +#include + +/* If the Prefer_MAP_32BIT_EXEC bit is set, try to map executable or + denywrite pages with MAP_32BIT first. */ +#define MMAP_PREPARE(addr, len, prot, flags, fd, offset) \ + if ((addr) == NULL \ + && (((prot) & PROT_EXEC) != 0 \ + || ((flags) & MAP_DENYWRITE) != 0) \ + && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC)) \ + { \ + void *ret = (void*) INLINE_SYSCALL_CALL (mmap, (addr), (len), \ + (prot), \ + (flags) | MAP_32BIT, \ + (fd), (offset)); \ + if (ret != MAP_FAILED) \ + return ret; \ + } + +#include_next + +#endif diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c new file mode 100644 index 0000000000..abc396589e --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c @@ -0,0 +1,34 @@ +/* Check that LD_PREFER_MAP_32BIT_EXEC works in PDE and shared library. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +extern void dso_check_map_32bit (void); + +static int +do_test (void) +{ + printf ("do_test: %p\n", do_test); + TEST_VERIFY ((uintptr_t) do_test < 0xffffffffUL); + dso_check_map_32bit (); + return 0; +} + +#include diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c new file mode 100644 index 0000000000..34ab01c773 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c @@ -0,0 +1 @@ +#include "tst-map-32bit-1a.c" diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c new file mode 100644 index 0000000000..78d4b6133c --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c @@ -0,0 +1,33 @@ +/* Check that LD_PREFER_MAP_32BIT_EXEC works in shared library. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +static void +dso_do_test (void) +{ +} + +void +dso_check_map_32bit (void) +{ + printf ("dso_do_test: %p\n", dso_do_test); + TEST_VERIFY ((uintptr_t) dso_do_test < 0xffffffffUL); +} diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index a2197ed211..822688e21f 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -27,6 +27,16 @@ extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *) attribute_hidden; +# ifdef __LP64__ +static void +TUNABLE_CALLBACK (set_prefer_map_32bit_exec) (tunable_val_t *valp) +{ + if (valp->numval) + GLRO(dl_x86_cpu_features).preferred[index_arch_Prefer_MAP_32BIT_EXEC] + |= bit_arch_Prefer_MAP_32BIT_EXEC; +} +# endif + # if CET_ENABLED extern void TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *) attribute_hidden; @@ -705,6 +715,11 @@ no_cpuid: #if HAVE_TUNABLES TUNABLE_GET (hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps)); +# ifdef __LP64__ + TUNABLE_GET (prefer_map_32bit_exec, tunable_val_t *, + TUNABLE_CALLBACK (set_prefer_map_32bit_exec)); +# endif + bool disable_xsave_features = false; if (!CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE)) diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def index e45f9cb159..d20c5b3196 100644 --- a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def +++ b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def @@ -26,6 +26,7 @@ BIT (I586) BIT (I686) BIT (Slow_SSE4_2) BIT (AVX_Fast_Unaligned_Load) +BIT (Prefer_MAP_32BIT_EXEC) BIT (Prefer_No_VZEROUPPER) BIT (Prefer_ERMS) BIT (Prefer_No_AVX512)