From patchwork Thu Jan 15 22:24:13 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 128164 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 A1A6E4BA2E1C for ; Thu, 15 Jan 2026 22:24:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A1A6E4BA2E1C 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=GbwJwBdx 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 CC58A4BA2E1E for ; Thu, 15 Jan 2026 22:24:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CC58A4BA2E1E 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 CC58A4BA2E1E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1768515858; cv=none; b=NTXXoafOlUdd9XX+x+MuynQyDPBlo1dkQltnRjfuUzyUoipQDCqgvBR7pARMSZlGiK8q87hWG/1QITpym68/bZ8Ub7Jdx5jkD4n6nSeoVhogIb9dOVCt5PR0M3eOtzsdj721uU+gci/1aKPSreBbKsPYxnY+H9sLkk+cvezeOh0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1768515858; c=relaxed/simple; bh=2ODR1mfQpidJGAW8DlMqatEtci8WS3SwYvpadcp7Kt0=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=J5LZToYGtJHdGo/8IPplJwJ8IlRyn8XqQtFseCSUbviaRNv4oced85xhdXGpruTJVuyAtb5BqoT/aCqIb7mkM8Qp7bPRspcWAbGkK9eDmhi2jDeEgWWtDZKnX2fTD1O3krStibaQWa2mjJql7CWGGXlEhUB+jg/xprKggK0gYxI= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CC58A4BA2E1E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768515858; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=ngILUeYTc6jD6wDPrXvfk+7Nu0YmDYobpz+m0HdTNoE=; b=GbwJwBdxKXI//ATwfnvnxNBLKcLFTjBDOuqZnDiBfNK1O80xSGJrzV8PK0Ctv6007IlgdE QB9Y1wxGDt4MVVboO0x5NuBI+bD4zem/MDrziC1LRr22IsowEHiyyyVF6jMDIAs5l+AOF1 lrRTA5fT/dHEynPrjpNxVQYdv1gn57w= Received: from mx-prod-mc-06.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-211-MJRGprpkOQuhbI7epzQU8A-1; Thu, 15 Jan 2026 17:24:17 -0500 X-MC-Unique: MJRGprpkOQuhbI7epzQU8A-1 X-Mimecast-MFC-AGG-ID: MJRGprpkOQuhbI7epzQU8A_1768515856 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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 49162180057E for ; Thu, 15 Jan 2026 22:24:16 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.202]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8F8FB18001D5 for ; Thu, 15 Jan 2026 22:24:15 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH] elf: Ignore LD_PROFILE if LD_PROFILE_OUTPUT is not set (bug 33797) Date: Thu, 15 Jan 2026 23:24:13 +0100 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: TJjO_Qa8gCB--wKzwB9z7E9EpZ3SltKzZHXISr943gs_1768515856 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.8 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, 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 The previous default for LD_PROFILE_OUTPUT, /var/tmp, is insecure because it's typically a 1777 directory, and other systems could place malicious files there which interfere with execution. Requiring the user to specify a profiling directory mitigates the impact of bug 33797. Clear LD_PROFILE_OUTPUT alongside with LD_PROFILE. Rework the test not to use predictable file names. Reviewed-by: Carlos O'Donell --- NEWS | 6 +++++- elf/rtld.c | 10 ++++++++- elf/tst-env-setuid.c | 50 ++++++++++++++++++++++++++------------------- sysdeps/generic/unsecvars.h | 1 + 4 files changed, 44 insertions(+), 23 deletions(-) base-commit: 274441f62a61dd5329b3a20d8356759bd2ff2d93 diff --git a/NEWS b/NEWS index 0568441385..b9dc48be83 100644 --- a/NEWS +++ b/NEWS @@ -84,7 +84,11 @@ Deprecated and removed features, and other changes affecting compatibility: Changes to build and runtime requirements: - [Add changes to build and runtime requirements here] +* The LD_PROFILE functionality has no longer a default directory for the + profile data it writes. Instead, developers are required to set a + directory explicitly using the LD_PROFILE_OUTPUT environment variable. + To restore the previous, insecure behavior, processes can be run with + LD_PROFILE_OUTPUT=/var/tmp. Security related changes: diff --git a/elf/rtld.c b/elf/rtld.c index 00df9acfca..80a3cc98e5 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -359,7 +359,6 @@ struct rtld_global_ro _rtld_global_ro attribute_relro = ._dl_fpu_control = _FPU_DEFAULT, ._dl_pagesize = EXEC_PAGESIZE, ._dl_inhibit_cache = 0, - ._dl_profile_output = "/var/tmp", /* Function pointers. */ ._dl_debug_printf = _dl_debug_printf, @@ -2706,6 +2705,15 @@ process_envvars_default (struct dl_main_state *state) } } + /* There is no fixed, safe directory to store profiling data, so + active LD_PROFILE only if LD_PROFILE_OUTPUT is set as well. */ + if (GLRO(dl_profile) != NULL && GLRO(dl_profile_output) == NULL) + { + _dl_error_printf ("\ +warning: LD_PROFILE ignored because LD_PROFILE_OUTPUT not specified\n"); + GLRO(dl_profile) = NULL; + } + /* If we have to run the dynamic linker in debugging mode and the LD_DEBUG_OUTPUT environment variable is given, we write the debug messages to this file. */ diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c index 830f330a37..ef8b968004 100644 --- a/elf/tst-env-setuid.c +++ b/elf/tst-env-setuid.c @@ -40,7 +40,11 @@ static char SETGID_CHILD[] = "setgid-child"; # define PROFILE_LIB "tst-sonamemove-runmod2.so" #endif -#define LD_DEBUG_OUTPUT "/tmp/some-file" +/* Computed path for LD_DEBUG_OUTPUT. */ +static char *debugoutputpath; + +/* Expected file name for erroneous LD_PROFILE output. */ +static char *profilepath; struct envvar_t { @@ -57,13 +61,14 @@ static const struct envvar_t filtered_envvars[] = { "LD_LIBRARY_PATH", FILTERED_VALUE }, { "LD_PRELOAD", FILTERED_VALUE }, { "LD_PROFILE", PROFILE_LIB }, + { "LD_PROFILE_OUTPUT", "/var/tmp" }, /* Not actually used. */ { "MALLOC_ARENA_MAX", FILTERED_VALUE }, { "MALLOC_PERTURB_", FILTERED_VALUE }, { "MALLOC_TRACE", FILTERED_VALUE }, { "MALLOC_TRIM_THRESHOLD_", FILTERED_VALUE }, { "RES_OPTIONS", FILTERED_VALUE }, { "LD_DEBUG", "all" }, - { "LD_DEBUG_OUTPUT", LD_DEBUG_OUTPUT }, + { "LD_DEBUG_OUTPUT", "overwritten" }, /* Not actually used. */ { "LD_WARN", FILTERED_VALUE }, { "LD_VERBOSE", FILTERED_VALUE }, { "LD_BIND_NOW", "0" }, @@ -79,7 +84,7 @@ static const struct envvar_t unfiltered_envvars[] = static void unlink_ld_debug_output (pid_t pid) { - char *output = xasprintf ("%s.%d", LD_DEBUG_OUTPUT, pid); + char *output = xasprintf ("%s.%d", debugoutputpath, pid); unlink (output); free (output); } @@ -121,18 +126,12 @@ test_child (void) } /* Also check if no profile file was created. - The parent sets LD_DEBUG_OUTPUT="/tmp/some-file" - which should be filtered. Then it falls back to "/var/tmp". Note: LD_PROFILE is not supported for static binaries. */ - { - char *profilepath = xasprintf ("/var/tmp/%s.profile", PROFILE_LIB); - if (!access (profilepath, R_OK)) - { - printf ("FAIL: LD_PROFILE file at %s was created!\n", profilepath); - ret = 1; - } - free (profilepath); - } + if (!access (profilepath, R_OK)) + { + printf ("FAIL: LD_PROFILE file at %s was created!\n", profilepath); + ret = 1; + } return ret; } @@ -145,6 +144,11 @@ do_test (int argc, char **argv) if (argc >= 2 && strstr (argv[1], LD_SO) != 0) FAIL_UNSUPPORTED ("dynamic test requires --enable-hardcoded-path-in-tests"); + profilepath = xasprintf ("%s/%s.profile", + support_objdir_root, PROFILE_LIB); + debugoutputpath = xasprintf ("%s/tst-env-setuid-file", + support_objdir_root); + /* Setgid child process. */ if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0) { @@ -165,7 +169,6 @@ do_test (int argc, char **argv) if (ret != 0) exit (1); - return 0; } else { @@ -179,20 +182,25 @@ do_test (int argc, char **argv) e++) setenv (e->env, e->value, 1); + /* Dynamically computed values. */ + setenv ("LD_DEBUG_OUTPUT", debugoutputpath, 1); + setenv ("LD_PROFILE_OUTPUT", support_objdir_root, 1); + /* Ensure that the profile output does not exist from a previous run (e.g. if test_dir, which defaults to /tmp, is mounted nosuid.) Note: support_capture_subprogram_self_sgid creates the SGID binary in test_dir. */ - { - char *profilepath = xasprintf ("/var/tmp/%s.profile", PROFILE_LIB); - unlink (profilepath); - free (profilepath); - } + unlink (profilepath); support_capture_subprogram_self_sgid (SETGID_CHILD); - return 0; + /* And clean up afterwards if necessary. */ + unlink (profilepath); } + + free (profilepath); + free (debugoutputpath); + return 0; } #define TEST_FUNCTION_ARGV do_test diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h index 97857a11aa..33755179f3 100644 --- a/sysdeps/generic/unsecvars.h +++ b/sysdeps/generic/unsecvars.h @@ -16,6 +16,7 @@ "LD_ORIGIN_PATH\0" \ "LD_PRELOAD\0" \ "LD_PROFILE\0" \ + "LD_PROFILE_OUTPUT\0" \ "LD_SHOW_AUXV\0" \ "LD_VERBOSE\0" \ "LD_WARN\0" \