From patchwork Thu Aug 27 23:47:25 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 142356 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8BF1C4BA9003 for ; Thu, 27 Aug 2026 23:49:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8BF1C4BA9003 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=iYlKfPjW 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.129.124]) by sourceware.org (Postfix) with ESMTP id 11E604BA903F for ; Thu, 27 Aug 2026 23:49:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 11E604BA903F 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 11E604BA903F Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1787874547; cv=none; b=JaKCiy0hk04PBoo0S8B0B+N7qk4iUElm3xjp8A+HbxO1dElTwsfrtQeKy52VJ/0DXdtT7ctid/zCp+HMF6pVzmInBATVPXTIsTgs6ID/5wVZuFb90GXq2UuLUUAtDJrbUphkuEmoYFaZevEnS12MRjvanCDfachS1ZCQjpMFFVY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1787874547; c=relaxed/simple; bh=wpsDWAwRVgOv1I+04f3e3n8We3/0afqT+e5Zn7m9/WA=; h=DKIM-Signature:Message-Id:From:Date:Subject:To; b=LSn7kRRVEl5Vikvmtk7USXufNa7mv6eSKPqnZpP68zWhliyRgXUkEo68ltdnhaeYmsHMU/FK5BmkStlFzKiwh8LAc7Fy+pF4b94rvR43BJprMPzIHsj4+uAvzqrBv/ksItfw0atpmDZPgdk/W5+Tl9n+SkFa907tQ+xkxAeY9bQ= ARC-Authentication-Results: i=1; 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=iYlKfPjW DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 11E604BA903F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1787874546; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:content-type:content-type; bh=n/vaD8ORijHkDkT3ejuncaDrR0LXGntNUZRbnG3RFIw=; b=iYlKfPjWyG/xLKU4Fw519wbjjZewBnxGWMePpH1xqfWF4G8Es41e/vDnMHq4euTqFWoBZ0 8pWHnmQVQnwrhGl09AK+fI9iRd6z1v3wEsFJvD0udkxLr1yrL3XvfRbxDDDsDg/9wBrw1/ UvvFVUTrQaUoF7+ZW3otgqSJRStEwNw= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-209-9nnBF4rkN8aTI6CTCSE0uw-1; Thu, 27 Aug 2026 19:49:04 -0400 X-MC-Unique: 9nnBF4rkN8aTI6CTCSE0uw-1 X-Mimecast-MFC-AGG-ID: 9nnBF4rkN8aTI6CTCSE0uw_1787874543 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8E40D1800657 for ; Thu, 27 Aug 2026 23:49:03 +0000 (UTC) Received: from greed.delorie.com (unknown [10.22.88.143]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 36D401955F03 for ; Thu, 27 Aug 2026 23:49:03 +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 67RNmuRo3789345 for ; Thu, 27 Aug 2026 19:48:57 -0400 Message-Id: From: DJ Delorie Date: Thu, 27 Aug 2026 19:47:25 -0400 Subject: [PATCH v1 1/1] rtld: add tunable for audit-specific surplus TLS To: libc-alpha@sourceware.org X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 2 X-Mimecast-MFC-PROC-ID: xQWcd64gI4Jvs3QwDGJrtOBLYWGYkyYTDm93BbGm3Yg_1787874543 X-Mimecast-Originator: redhat.com Content-type: text/plain; charset=UTF-8 X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no 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 glibc.rtld.audit_static_tls which specifies additional surplus TLS just for audit modules, as when audit modules are used the loader can't compute TLS space before the auditors run. This surplus exists until the loader can recompute the TLS needs, and is reduced for future threads. --- Note: this patch is built on the optional_static_tls_alignment patch, so CI/CD might complain about the missing context. https://inbox.sourceware.org/libc-alpha/587b3a82d77ed767a78068dd67ab529e2a9e1499.1786567326.git.dj@redhat.com/ elf/dl-tls.c | 43 ++++++++++++++++++++++++++++++++++++-- elf/dl-tunables.list | 5 +++++ elf/rtld.c | 2 ++ manual/tunables.texi | 22 +++++++++++++++++++ sysdeps/generic/ldsodefs.h | 5 +++++ 5 files changed, 75 insertions(+), 2 deletions(-) diff --git a/elf/dl-tls.c b/elf/dl-tls.c index e4c93bace0..b085ca16f2 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -127,6 +127,10 @@ tls_static_surplus (int nns, int opt_tls) #define LEGACY_TLS (1664 - tls_static_surplus (DEFAULT_NNS, OPTIONAL_TLS)) static size_t optional_static_tls_alignment = 0; +static size_t dl_audit_tls = 0; +static size_t dl_original_optional = 0; +static size_t dl_original_surplus = 0; +static size_t dl_original_align = 1; /* Calculate the size of the static TLS surplus, when the given number of audit modules are loaded. Must be called after the @@ -139,6 +143,8 @@ _dl_tls_static_surplus_init (size_t naudit) nns = TUNABLE_GET (nns, size_t, NULL); opt_tls = TUNABLE_GET (optional_static_tls, size_t, NULL); optional_static_tls_alignment = TUNABLE_GET (optional_static_tls_alignment, size_t, NULL); + if (naudit) + dl_audit_tls = TUNABLE_GET (audit_static_tls, size_t, NULL); if (nns > DL_NNS) nns = DL_NNS; if (DL_NNS - nns < naudit) @@ -149,6 +155,33 @@ _dl_tls_static_surplus_init (size_t naudit) GL(dl_tls_static_optional) = opt_tls; assert (LEGACY_TLS >= 0); GLRO(dl_tls_static_surplus) = tls_static_surplus (nns, opt_tls) + LEGACY_TLS; + + if (dl_audit_tls > 0) + { + if (dl_audit_tls >= SIZE_MAX / 2) + _dl_fatal_printf ("glibc.rtld.audit_static_tls exceeds SIZE_MAX/2\n"); + dl_original_optional = GL(dl_tls_static_optional); + dl_original_surplus = GLRO(dl_tls_static_surplus); + } +} + +/* Undo as much of the audit-specific extra TLS space accounted for + above, as possible. After this function, the unused amount of TLS + must be at least the dl_tls_static_surplus amount. */ +void +_dl_tls_prune_audit_storage (void) +{ + if (dl_audit_tls > 0) + { + GL(dl_tls_static_optional) = dl_original_optional; + GLRO(dl_tls_static_surplus) = dl_original_surplus; + GLRO(dl_tls_static_size) = roundup (GL(dl_tls_static_used) + + dl_original_surplus, + dl_original_align); +#ifdef TLS_TCB_AT_TP + GLRO(dl_tls_static_size) += TLS_TCB_SIZE; +#endif + } } /* Out-of-memory handler. */ @@ -374,9 +407,12 @@ _dl_determine_tlsoffset (void) _dl_extra_tls_set_offset (-offset); GL(dl_tls_static_used) = offset; - GLRO (dl_tls_static_size) = (roundup (offset + GLRO(dl_tls_static_surplus), + GLRO (dl_tls_static_size) = (roundup (offset + + GLRO(dl_tls_static_surplus) + + dl_audit_tls, max_align) + TLS_TCB_SIZE); + dl_original_align = max_align; #elif TLS_DTV_AT_TP /* The TLS blocks start right after the TCB. */ size_t offset = TLS_TCB_SIZE; @@ -461,8 +497,11 @@ _dl_determine_tlsoffset (void) offset += extra_tls_size; GL(dl_tls_static_used) = offset; - GLRO (dl_tls_static_size) = roundup (offset + GLRO(dl_tls_static_surplus), + GLRO (dl_tls_static_size) = roundup (offset + + GLRO(dl_tls_static_surplus) + + dl_audit_tls, TCB_ALIGNMENT); + dl_original_align = TCP_ALIGNMENT; #else # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" #endif diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list index 4c78444542..d8daf30ab0 100644 --- a/elf/dl-tunables.list +++ b/elf/dl-tunables.list @@ -106,6 +106,11 @@ glibc { minval: 0 default: 0 } + audit_static_tls { + type: SIZE_T + minval: 0 + default: 0 + } enable_secure { type: INT_32 minval: 0 diff --git a/elf/rtld.c b/elf/rtld.c index b37c650631..e4f4dcf4b8 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -2353,6 +2353,8 @@ dl_main (const ElfW(Phdr) *phdr, _dl_debug_post_relocate (main_map); } + _dl_tls_prune_audit_storage (); + /* All ld.so initialization is complete. Apply RELRO. */ _dl_protect_relro (&_dl_rtld_map); diff --git a/manual/tunables.texi b/manual/tunables.texi index b6bf0a3964..8e1f905081 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -430,6 +430,28 @@ requirement, as an alternative to requesting excessive optional_static_tls (above). @end deftp +@deftp Tunable glibc.rtld.audit_static_tls +Sets an additional amount of memory to be allocated in the initial +thread's TLS when one or more auditing modules are to be loaded. +Since auditing modules must run before the loader is done loading +dynamic objects, the loader cannot know how much TLS space is needed +before it must create the first TLS area. If no auditing modules are +loaded, the initial TLS size can be computed after the dynamic objects +are loaded. When this tunable is used, the initial TLS size can be +very large, and the size computation is adjusted after loading is +complete, so that any additional threads created will have a more +suitable TLS size (including any optional space as specified by +@code{glibc.rtld.optional_static_tls}). The default is to not +allocate any additional TLS for audit modules. + +As an example, if a program required 1MB of TLS space and specified an +optional 1MB surplus, normally every thread would have 2MB of TLS +space. If an auditing module requires 3MB of TLS space, and 5MB of +audit TLS was specified by this tunable, the main thread would have +7MB of TLS space (2MB plus the specified 5MB) and every other thread +would have 5MB (2MB plus the actual 3MB). +@end deftp + @deftp Tunable glibc.rtld.dynamic_sort Sets the algorithm to use for DSO sorting, valid values are @samp{1} and @samp{2}. For value of @samp{1}, an older O(n^3) algorithm is used, which is diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 305ca6e0df..54535452b3 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -1184,6 +1184,11 @@ extern void _dl_determine_tlsoffset (void) attribute_hidden; number of audit modules are loaded. */ void _dl_tls_static_surplus_init (size_t naudit) attribute_hidden; +/* After startup is complete but before user entry, the size of the + audit modules is more knowable so we can reduce the TLS size + accordingly. */ +void _dl_tls_prune_audit_storage (void) attribute_hidden; + /* This function is called very early from dl_main to set up TLS and other thread-related data structures. */ void __tls_pre_init_tp (void) attribute_hidden;