From patchwork Tue Mar 17 01:39:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 131847 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 379364C91767 for ; Tue, 17 Mar 2026 01:40:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 379364C91767 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=EQdPDhp/ 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 ESMTP id 5C0B64C91764 for ; Tue, 17 Mar 2026 01:39:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5C0B64C91764 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5C0B64C91764 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773711585; cv=none; b=guAeRWEkW2T3xQ/2XkW+pBvGvjZVQ5Yl4J+J0Ae1txWQ68zlNHIklQKHEJyyiFyVnxtd1cyRsCK+rdSQZ2+x+JwUGrl52vQrSpoMbqDeJ6pijpg4dg5IsTB44LFx4wXPr8d9zHRrwzJs18JH0dg6bgZ8dtKuCcLrdtDV9SqxhKs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773711585; c=relaxed/simple; bh=Fvqz1egj/MiwtlP7PMMy5cbIVWOpD3VflUmi15sENws=; h=DKIM-Signature:Date:Message-Id:From:To:Subject; b=GUTbZ5U34IKgTY32RzEBG83NsYrKCi6k1xIqp015+73A01oWyHLY4XuBP5BEIXzPlBldlIbTcnxH0xgjJmUirNdzj61IlzTtNoKXHyeKcdcSPnvf5KkQ1uAnC8tSF21emWXwltF6GDfpsZvi4qO8wXEn20kP14aYlz5cskDueGY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5C0B64C91764 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1773711585; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:content-type:content-type; bh=JyBQImU7Oge5TRCxLKLNRMS4MagsXqYgcSpoDo3o4Dk=; b=EQdPDhp/3vaeHGpbqStvDJC3LcYb7jSb+QH8eV8jecLr3MavYqM2LnFrjzR3EWdPqjC7fy jFYSS797nXTqcAQXGavQtndRF5cZFfPjVgfFjimAVdWhHjz/KpBapXEMyNoNzKJYK8nY2E Kky6uw7iktx9YAvFP5GftFDllQBlTm4= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-502-XMetceQBNPChKa91PYaG-w-1; Mon, 16 Mar 2026 21:39:43 -0400 X-MC-Unique: XMetceQBNPChKa91PYaG-w-1 X-Mimecast-MFC-AGG-ID: XMetceQBNPChKa91PYaG-w_1773711582 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B2D38195605E for ; Tue, 17 Mar 2026 01:39:42 +0000 (UTC) Received: from greed.delorie.com (unknown [10.22.88.83]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6EC251800351 for ; Tue, 17 Mar 2026 01:39:41 +0000 (UTC) Received: from greed.delorie.com.redhat.com (localhost [127.0.0.1]) by greed.delorie.com (8.16.1/8.16.1) with ESMTP id 62H1ddBm1583440 for ; Mon, 16 Mar 2026 21:39:39 -0400 Date: Mon, 16 Mar 2026 21:39:39 -0400 Message-Id: From: DJ Delorie To: libc-alpha@sourceware.org Subject: [PATCH v6 4/4] Add system-wide tunables: Filters X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: QKkKi1E7crRKmuXRbb_LMXzrK8Jt2HKSngtGhAS3ILc_1773711582 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-9.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Add support for [proc:*] syntax where * matches /proc/self/exe (fallback: argv[0] unless AT_SECURE). Tunables after such a line are limited to matching processes. Note that this filter is reset when including a file or at end of file. If the filename starts with a slash (example: [proc:/bin/foo]) the full path must match. If not (example: [proc:foo]) the basename is matched. Add support for filtering out AT_SECURE or non-AT_SECURE binaries: $glibc.only-for.unsecure-binaries=1 @glibc.only-for.secure-binaries=1 --- csu/libc-start.c | 2 +- elf/Makefile | 4 + elf/cache.c | 3 +- elf/dl-tunables.c | 80 +++++++++++++++- elf/dl-tunables.h | 2 +- elf/ldconfig-parse.c | 6 +- elf/ldconfig.c | 3 + elf/tst-tunconf1.c | 36 +++++++ elf/tst-tunconf1.root/etc/tunables.conf | 15 +++ elf/tst-tunconf1.root/ldconfig.run | 0 elf/tst-tunconf1.root/postclean.req | 0 elf/tunconf.c | 122 +++++++++++++++++++++++- elf/tunconf.h | 3 + sysdeps/mach/hurd/dl-sysdep.c | 2 +- sysdeps/unix/sysv/linux/dl-sysdep.c | 2 +- 15 files changed, 265 insertions(+), 15 deletions(-) create mode 100644 elf/tst-tunconf1.c create mode 100644 elf/tst-tunconf1.root/etc/tunables.conf create mode 100644 elf/tst-tunconf1.root/ldconfig.run create mode 100644 elf/tst-tunconf1.root/postclean.req diff --git a/csu/libc-start.c b/csu/libc-start.c index 1c58561bce..ae36170045 100644 --- a/csu/libc-start.c +++ b/csu/libc-start.c @@ -264,7 +264,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), _dl_aux_init (auxvec); # endif - __tunables_init (__environ); + __tunables_init (__environ, argv); ARCH_INIT_CPU_FEATURES (); diff --git a/elf/Makefile b/elf/Makefile index 5398fe0d2c..4fbd03cefc 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -323,6 +323,7 @@ tests-internal := \ $(tests-static-internal) \ tst-tls1 \ tst-tls_tp_offset \ + tst-tunconf1 \ # tests-internal tests-static := $(tests-static-normal) $(tests-static-internal) @@ -333,6 +334,8 @@ tests-static += \ tst-tls9-static \ # tests-static +tst-tunconf1-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=5 + static-dlopen-environment = \ LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx)dlfcn tst-tls9-static-ENV = $(static-dlopen-environment) @@ -563,6 +566,7 @@ tests-container += \ tst-pldd \ tst-preload-pthread-libc \ tst-rootdir \ + tst-tunconf1 \ # tests-container test-srcs = \ diff --git a/elf/cache.c b/elf/cache.c index e798f7e2d8..2809f255f5 100644 --- a/elf/cache.c +++ b/elf/cache.c @@ -300,9 +300,10 @@ print_extensions (struct cache_extension_all_loaded *ext, thc->signature, thc->version, thc->num_tunables); for (i = 0; i < count; ++ i) { - printf(" [%d] %s : %s [flags 0x%08x", + printf(" [%d] %s (%d) : %s [flags 0x%08x", i, cache_data + tec[i].name_offset, + tec[i].tunable_id, cache_data + tec[i].value_offset, tec[i].flags); if (tec[i].flag_offset != 0) diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c index 29fcd4504b..acee6eb872 100644 --- a/elf/dl-tunables.c +++ b/elf/dl-tunables.c @@ -291,13 +291,22 @@ parse_tunables (const char *valstring) ENV_ALIAS to find values. Later we will also use the tunable names to find values. */ void -__tunables_init (char **envp) +__tunables_init (char **envp, char **argv) { char *envname = NULL; char *envval = NULL; char **prev_envp = envp; #if defined(SHARED) && defined (USE_LDCONFIG) + const char *prog_name = (argv && argv[0]) ? argv[0] : ""; + int prog_name_len = -1; + const char *base_name = NULL; + int base_name_len = -1; +#ifdef PATH_MAX + char exebuf[PATH_MAX]; +#else + char exebuf[256]; +#endif const struct tunable_header_cached *thc; const char *td; @@ -330,9 +339,70 @@ __tunables_init (char **envp) if (tid == -1) continue; } - /* At this point, TID is valid for the tunable we want. See - if the parsed type matches the desired type. */ - + /* At this point, TID is valid for the tunable we want. */ + + if (tec->flags & TUNCONF_EXCLUDE_SECURE && __libc_enable_secure) + goto skip_due_to_filter; + if (tec->flags & TUNCONF_EXCLUDE_UNSECURE && !__libc_enable_secure) + goto skip_due_to_filter; + + /* Apply selected filter, if any. */ + switch (tec->flags & TUNCONF_FLAG_FILTER) { + case TUNCONF_FILTER_PERPROC: + /* Perform one-time calculations that aren't needed if we + don't use this filter. */ + if (prog_name_len == -1) + { + ssize_t n = readlink ("/proc/self/exe", + exebuf, sizeof (exebuf) - 1); + if (n > 0 && n < sizeof(exebuf)-1) + { + /* If /proc/self/exe exists and we can read it, + it's more reliable than argv[] so use it. */ + exebuf[n] = '\0'; + prog_name = exebuf; + } + else if (__libc_enable_secure) + prog_name = NULL; + if (prog_name != NULL) + { + const char *slash = NULL, *cp; + for (cp = prog_name; *cp; ++ cp) + if (*cp == '/') + slash = cp; + if (slash) + base_name = slash + 1; + else + base_name = prog_name; + prog_name_len = strlen (prog_name); + base_name_len = strlen (base_name); + } + } + /* prog_name and the cached string are both NUL terminated. */ + if (prog_name) + { + if (((const char *)(td + tec->flag_offset))[0] == '/') + { + if (memcmp (prog_name, td + tec->flag_offset, prog_name_len) != 0) + goto skip_due_to_filter; + } + else + { + if (memcmp (base_name, td + tec->flag_offset, base_name_len) != 0) + goto skip_due_to_filter; + } + } + else + /* Program is AT_SECURE but the only source of program + name is argv[0], which is not secure, so we do not + match any name-based filter. */ + goto skip_due_to_filter; + break; + default: + break; + } + + /* See if the parsed type matches the desired type. */ if (tunable_list[tid].type.type_code == TUNABLE_TYPE_STRING) { /* This is a memory leak but there's no easy way around @@ -355,6 +425,8 @@ __tunables_init (char **envp) value, strlen (value)); } } + + skip_due_to_filter:; } } #endif /* defined(SHARED) && defined (USE_LDCONFIG) */ diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h index 45aeed47bc..3f34329614 100644 --- a/elf/dl-tunables.h +++ b/elf/dl-tunables.h @@ -47,7 +47,7 @@ typedef void (*tunable_callback_t) (tunable_val_t *); #include "dl-tunable-list.h" -extern void __tunables_init (char **); +extern void __tunables_init (char **, char **); extern void __tunables_print (void); extern bool __tunable_is_initialized (tunable_id_t); extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t); diff --git a/elf/ldconfig-parse.c b/elf/ldconfig-parse.c index b7bb664eb5..baddfdbac0 100644 --- a/elf/ldconfig-parse.c +++ b/elf/ldconfig-parse.c @@ -47,8 +47,10 @@ ldconfig_parse_config_1 (const char *filename, bool do_chroot, opt_chroot - If non-NULL, all paths are relative to this. - callback - for each non-blank line in the file, this function is called - with the line and it's location. + callback - for each non-blank line in the file, this function is + called with the line and it's location. Will also be called + with a NULL line at the start and end of each file, for + file-scoped config items. */ void diff --git a/elf/ldconfig.c b/elf/ldconfig.c index 11b063eb5c..1ea55400f3 100644 --- a/elf/ldconfig.c +++ b/elf/ldconfig.c @@ -435,6 +435,9 @@ add_dir_1 (const char *line, const char *from_file, int from_line) static void add_dir_callback (char *line, const char *from_file, int from_line) { + /* Denotes file boundaries. Not needed here. */ + if (line == NULL) + return; if (!strncasecmp (line, "hwcap", 5) && isblank (line[5])) error (0, 0, _("%s:%u: hwcap directive ignored"), from_file, from_line); else diff --git a/elf/tst-tunconf1.c b/elf/tst-tunconf1.c new file mode 100644 index 0000000000..c95a7cb8ba --- /dev/null +++ b/elf/tst-tunconf1.c @@ -0,0 +1,36 @@ +/* Test that the tunables cache can override env vars. + Copyright (C) 2026 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 "dl-tunables.h" + +static int +do_test (void) +{ + size_t tcache_count = TUNABLE_GET_FULL (glibc, malloc, tcache_count, size_t, NULL); + size_t tcache_max = TUNABLE_GET_FULL (glibc, malloc, tcache_max, size_t, NULL); + printf("tcache count is %ld (should be 5, from env)\n", (long)tcache_count); + TEST_COMPARE ((long)tcache_count, 5); + printf("tcache max is %ld (should be 4, from /etc)\n", (long)tcache_max); + TEST_COMPARE ((long)tcache_max, 4); + return 0; +} + +#include diff --git a/elf/tst-tunconf1.root/etc/tunables.conf b/elf/tst-tunconf1.root/etc/tunables.conf new file mode 100644 index 0000000000..6cd6c8a949 --- /dev/null +++ b/elf/tst-tunconf1.root/etc/tunables.conf @@ -0,0 +1,15 @@ +# These test the parser for both the overridability characters as well as +# tunables that either never exist, or only exist on some platforms. +!glibc.foo=19 +-glibc.cpu.cached_memopt=1 ++glibc.cpu.hwcaps=some,random,string +@glibc.test_secure=1 +$glibc.test_unsecure=1 + +# These are checked inside the test case +glibc.malloc.tcache_max=6 +$glibc.malloc.tcache_count=3 +[proc:/bin/ls] +glibc.malloc.tcache_max=7 +[proc:tst-tunconf1] +glibc.malloc.tcache_max=4 diff --git a/elf/tst-tunconf1.root/ldconfig.run b/elf/tst-tunconf1.root/ldconfig.run new file mode 100644 index 0000000000..e69de29bb2 diff --git a/elf/tst-tunconf1.root/postclean.req b/elf/tst-tunconf1.root/postclean.req new file mode 100644 index 0000000000..e69de29bb2 diff --git a/elf/tunconf.c b/elf/tunconf.c index d0fc1b7352..c912abd876 100644 --- a/elf/tunconf.c +++ b/elf/tunconf.c @@ -66,12 +66,16 @@ typedef enum { struct tunable_entry_int { struct stringtable_entry *name; struct stringtable_entry *value; + struct stringtable_entry *filter; TOP top; + bool exclude_secure:1; + bool exclude_unsecure:1; int tunable_id; int value_is_negative:1; int value_was_parsed:1; unsigned long long value_ull; signed long long value_sll; + long filter_flags; struct tunable_entry_int *next; }; @@ -79,8 +83,76 @@ struct tunable_entry_int { struct tunable_entry_int *entry_list; struct tunable_entry_int **entry_list_next = &entry_list; +static int filter_flags = 0; +static char *filter_string = NULL; + /*----------------------------------------------------------------------*/ +static void +clear_filter (void) +{ + free (filter_string); + filter_string = NULL; + filter_flags = 0; +} + +/* Filters are lines the are bracketed, like + [prog:foo] +*/ +static void +parse_filter (char *line, const char *filename, int lineno) +{ + const char *colon = NULL; + const char *right_bracket = NULL; + const char *cp; + + for (cp=line; *cp != 0; cp++) + { + if (*cp == ':') + colon = cp; + if (*cp == ']') + { + right_bracket = cp; + break; + } + } + /* Special case: [] means "no filter" */ + if (right_bracket != NULL && right_bracket == line + 1) + { + clear_filter (); + return; + } + if (colon == NULL) + { + printf("%s:%d: syntax error, filter line ignored: `%s' (missing ':')\n", + filename, lineno, line); + return; + } + if (right_bracket == NULL) + { + printf("%s:%d: syntax error, filter line ignored: `%s' (missing ']')\n", + filename, lineno, line); + return; + } + + if (filter_string != NULL) + { + clear_filter (); + } + + if (memcmp ("proc", line + 1, colon - line - 1) == 0) + { + filter_string = (char *) malloc (right_bracket - colon); + memcpy (filter_string, colon + 1, right_bracket - colon - 1); + filter_string [right_bracket - colon] = 0; + filter_flags = TUNCONF_FILTER_PERPROC; + } + + else + printf("%s:%d: unrecognized filter `%.*s', ignored\n", filename, lineno, (int)(colon - line - 1), line + 1); +} + + static void add_tunable (char *line, const char *filename, int lineno) { @@ -91,12 +163,20 @@ add_tunable (char *line, const char *filename, int lineno) char *orig_line; struct tunable_entry_int *entry; int i, id; + bool exclude_secure = 0, exclude_unsecure = 0; + + /* Denotes file boundaries. */ + if (line == NULL) + { + clear_filter(); + return; + } orig_line = line; /* Leading whitespace has already been stripped. */ - if (*line == '!' || *line == '+' || *line == '-') + while (*line) { switch (*line) { @@ -109,11 +189,25 @@ add_tunable (char *line, const char *filename, int lineno) case '-': top = TOP_DENY; break; + case '@': + exclude_unsecure = 1; + break; + case '$': + exclude_secure = 1; + break; + case '[': + parse_filter (line, filename, lineno); + return; + case ' ': + case '\t': + break; + + default: + goto done; } line ++; - while (*line && isspace(*line)) - line ++; } + done: /* NAME now points to the start of the tunable name. */ name = line; @@ -174,6 +268,14 @@ add_tunable (char *line, const char *filename, int lineno) entry->value = cache_store_string (value); entry->tunable_id = id; entry->top = top; + entry->exclude_secure = exclude_secure; + entry->exclude_unsecure = exclude_unsecure; + + if (filter_flags) + { + entry->filter_flags = filter_flags; + entry->filter = cache_store_string (filter_string); + } *entry_list_next = entry; entry_list_next = & (entry->next); @@ -248,11 +350,23 @@ get_tunconf_ext (uint32_t string_table_offset) tec->flags |= TUNCONF_OVERRIDE_DENY; break; } + if (tei->exclude_secure) + tec->flags |= TUNCONF_EXCLUDE_SECURE; + if (tei->exclude_unsecure) + tec->flags |= TUNCONF_EXCLUDE_UNSECURE; tec->tunable_id = tei->tunable_id; tec->name_offset = tei->name->offset + string_table_offset; tec->value_offset = tei->value->offset + string_table_offset; - tec->flag_offset = 0; + + if (tei->filter_flags != 0) + { + tec->flag_offset = tei->filter->offset + string_table_offset; + tec->flags |= tei->filter_flags; + } + else + tec->flag_offset = 0; + tec->unused_1 = 0; if (tei->value_is_negative) tec->parsed_value = (uint64_t) tei->value_sll; diff --git a/elf/tunconf.h b/elf/tunconf.h index 9551119167..e880aa574a 100644 --- a/elf/tunconf.h +++ b/elf/tunconf.h @@ -10,6 +10,9 @@ #define TUNCONF_OVERRIDE_STRICTER 0x00000008 #define TUNCONF_OVERRIDE_DENY 0x0000000C +#define TUNCONF_EXCLUDE_SECURE 0x00000010 +#define TUNCONF_EXCLUDE_UNSECURE 0x00000020 + #define TUNCONF_FLAG_FILTER 0x0000ff00 #define TUNCONF_FILTER_PERPROC 0x00000100 diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c index 0e348d6440..fe6d453756 100644 --- a/sysdeps/mach/hurd/dl-sysdep.c +++ b/sysdeps/mach/hurd/dl-sysdep.c @@ -98,7 +98,7 @@ _dl_sysdep_start (void **start_argptr, __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE; - __tunables_init (_environ); + __tunables_init (_environ, _dl_argv); /* Initialize DSO sorting algorithm after tunables. */ _dl_sort_maps_init (); diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.c b/sysdeps/unix/sysv/linux/dl-sysdep.c index cb1f94ee23..c2701f274c 100644 --- a/sysdeps/unix/sysv/linux/dl-sysdep.c +++ b/sysdeps/unix/sysv/linux/dl-sysdep.c @@ -107,7 +107,7 @@ _dl_sysdep_start (void **start_argptr, dl_hwcap_check (); - __tunables_init (_environ); + __tunables_init (_environ, (char **) (start_argptr + 1)); /* Initialize DSO sorting algorithm after tunables. */ _dl_sort_maps_init ();