From patchwork Tue Mar 11 13:36:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 872459 Delivered-To: patch@linaro.org Received: by 2002:a05:6504:4124:b0:290:25b2:841c with SMTP id u36csp1962742ltt; Tue, 11 Mar 2025 06:37:43 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCXrhyeSVEqH51MsTym4MLP8CRyyf+ksP7fLL/TUoJez62HjTGsf3RUsqh3ZZhEhzcMcDUWV9g==@linaro.org X-Google-Smtp-Source: AGHT+IGFFDGc90MPp4QmRkw4wIzE77Juob60AUg3BaDu4vaquBd/Racvi/81i8at09th9AtgnhQe X-Received: by 2002:ac8:5753:0:b0:475:39:9d35 with SMTP id d75a77b69052e-476994cc583mr51723201cf.14.1741700263228; Tue, 11 Mar 2025 06:37:43 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1741700263; cv=pass; d=google.com; s=arc-20240605; b=S4NZ05aOIjjT32HEsBGgjGvmh85h7/A3QclSs6yE+bzz5X1bM6eV9aMBu0M2QXYErs JzyESTJoGQejuK/3W9SBVGOeRzlQe7beSp8T8wvNhl1vgrz6DD/99VFef55fkYDUD46n rV+LgOplHU8BbxXJGqRsl7G8b5kMDD2AmL3rGWluR2aqYssXkzN/AG+BFxlvIDJfALmQ cIRu8L/yo7o2zE1f+6uaZRJhjoGwFEVAGPwIbg0SPav930nSQwZJDwjNLxqgDPL6cpRO WGRkkKtol3525Z5YqP/Yc8G+LGiVxpP3f5bdCU9ngk/aMSn+EjYxc96XMdDIijE6+UKf uqoA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:cc:to:from:dkim-signature :dkim-filter:arc-filter:dmarc-filter:delivered-to:dkim-filter; bh=kOf2AbMDbpohmFRTrSVfXji9ZgX+W3jF3jF2UfBMupQ=; fh=ZUYdiu42Otzfm5hZWyt+f/1EKkTvfpBtKLfgfG0qAuk=; b=Qf6tC/A4A4XsLIZd1BNZIvwDIQgXHDNrDvnG2Ki687bfoEkjFx0IAqkWMHm9TqZDxU OmX9I9C9djVw9fljbqZT2F2lqQ1HC2sjTdg/ivxrd41wxtGPv+4K2rB/zIh93w9iQvcC yR9ozFaCNym8n0CVIs8JrKbu2FU12qqV2u5s1fTDcaVzPfvhG5+3KhJW8gyF3uK8Oz4z C4tKTt19y5Cjwhl19qpW5InmN+exU9CeFgvUbdSERXLuPh3BOZmVHyHeeTf8e9I3kLqa 61DmkmXJTb3vdbTWE6mhd/ybt1i56ODlmo42eivtny/AlogQy4zrBlfKbnnhUuuuB2+a zvXQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=mWfCvbIO; arc=pass (i=1); spf=pass (google.com: domain of libc-alpha-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="libc-alpha-bounces~patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id d75a77b69052e-47687f59166si41896631cf.303.2025.03.11.06.37.43 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Mar 2025 06:37:43 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=mWfCvbIO; arc=pass (i=1); spf=pass (google.com: domain of libc-alpha-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="libc-alpha-bounces~patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6EE7B3858294 for ; Tue, 11 Mar 2025 13:37:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6EE7B3858294 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=mWfCvbIO X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pl1-x62f.google.com (mail-pl1-x62f.google.com [IPv6:2607:f8b0:4864:20::62f]) by sourceware.org (Postfix) with ESMTPS id 4C5A43858288 for ; Tue, 11 Mar 2025 13:37:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4C5A43858288 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linaro.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4C5A43858288 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::62f ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1741700231; cv=none; b=sSPgxo0lE8mVczTojRUCXYwGwm0mw9mwmNtK+JM29K+TEcInZdf49JvUgwn37UYMqCrUmHTgeDfd2a/C/jA9phjm74pLm8/f5PWMPrKIXNbSr0eNTprZAErJNQAQ47HveeXaf9pD1++tgkL6DczifMs8wIa5Q4YsTvmUqBYPnq0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1741700231; c=relaxed/simple; bh=bqAvf12hW+dkaBnORnoAE6Qzstj2aPsb7QnZ2sDwqgA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=nrMII9iNyP9jsGF3blG3vBJWnJs+P+FZ2ZlLz3FVJhOwcFueEuwJ35hEBz9+k1AgYxQmMQZJjQbLF1lWPVyhaUemg56nkxMe+CyhZA1VUpOEdyL+cX4J4X57DidgzCAj2O57qsEmvM1abU2evRiWjnyJJvacQ+FWmjzhZ9DnY5Q= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4C5A43858288 Received: by mail-pl1-x62f.google.com with SMTP id d9443c01a7336-22401f4d35aso96180395ad.2 for ; Tue, 11 Mar 2025 06:37:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1741700230; x=1742305030; darn=sourceware.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=kOf2AbMDbpohmFRTrSVfXji9ZgX+W3jF3jF2UfBMupQ=; b=mWfCvbIORcbjx6ttc1/c94BkJ74zofmMhVC0I6qac/USVhBSJX3LDF/2mvR4F4MTuo 3uotrRp7fkGNmszwzoPlvrCCs2gyFGzhsvCNsHCPgU0PLSTj7PEqbMsYf9LnpMt+yqlR rZ9IjJ2TDBpn5Nzr/m692KOT8xy2HjB3g7NRGMXoSmBX/hCCXX8uAPKNa8BqQdpfWmtN OFHiZ1wyZ2xEq6dmVReOVjGHs2KznsBUyo5zYIKDOscJX2nLdzR/TAMsHN//aDUytVW3 HyYoqebjHuuwT7Sv0cFIxH9l04eKC9qtKcEImLioMHbSdOdoq95k6bhVxIIbP2xhgBZI t7LQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741700230; x=1742305030; 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=kOf2AbMDbpohmFRTrSVfXji9ZgX+W3jF3jF2UfBMupQ=; b=T4evuoi99OQgvm4ZxpwBo/wJ7CS+PkJmrW2PL5f8pfXgd697msz/HdGA+DNWZHZlWG d0uhr+TM1NHpTpP2SHVj5WD6Cl/XcTEVrM5wTpSJgKp9rh1jYxw3/TgGfOpWWuaRjPHl ge6e2E14rgGimVP31OdU7os9WDScjiEPhFZmj+LpCSuHD83EJVhnug8LkUzoGn7Vrs2E F4D+fFxbq/Mk8I3vB31LyBG9kTQwf+VRYLazSS5sRwZkK39pa87D73/0N20upUHQUy+l IuuBFxH1SY7KdVLNOOdLou0Drf/LBHA/hmxbduVErFOmSSQsWvuSUNLybUjNUiBwPbpY 1uOg== X-Gm-Message-State: AOJu0YwcInVp4GcxKN2NukWK3bZdPBmUDzyGSaOwIlSY2GAjmgoKRvLg qi1/za+BDBbfGGayVM0b3vDY+NcPKE2TcZUE07eq8yHkrbfTDQg2hrQuraurDLk1zabqNDu5NUW 8 X-Gm-Gg: ASbGncvdvNaVKGKNNfj2nFKvz8MCL0on8QNnJRM58aAJF8A0tH55fR1TN+g6SOVNgIP pryLCbuS67t7gWAOXlf7c0QZ2V5Y1VZDBAbG4LDN0ZGV1biQegJEjmqQV5fV8TRYPf0zmFwCOaG BlIo6776IlygXlRPiqioLfTR5S7eDKt0Ol+VzIkucVIRWms/yiLKqRtZxwjSqbg0hbuJT9uE/pT BswEf5gb3uTRkCkJKi2DnPFJTace+gV8qKDvMWdMhgGoyT3G6IYQw2xz2Z9ccKdO82nj3i5MMM+ qWiKx5zPcPsA3xIIM8If0xsiamAevichNBqLsP0EBaa5WBwDMWJsUNI= X-Received: by 2002:a17:902:d2cc:b0:224:22fb:9460 with SMTP id d9443c01a7336-22592e44a40mr45614245ad.30.1741700229768; Tue, 11 Mar 2025 06:37:09 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:1ebf:8b5:8f5b:dd39:866]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22410a93fe5sm97141215ad.206.2025.03.11.06.37.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Mar 2025 06:37:09 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Cc: Geoffrey Thomas Subject: [PATCH v2] elf: Canonicalize $ORIGIN in an explicit ld.so invocation [BZ 25263] Date: Tue, 11 Mar 2025 10:36:32 -0300 Message-ID: <20250311133703.4059892-1-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 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~patch=linaro.org@sourceware.org When an executable is invoked directly, we calculate $ORIGIN by calling readlink on /proc/self/exe, which the Linux kernel resolves to the target of any symlinks. However, if an executable is run through ld.so, we cannot use /proc/self/exe and instead use the path given as an argument. This leads to a different calculation of $ORIGIN, which is most notable in that it causes ldd to behave differently (e.g., by not finding a library) from directly running the program. To make the behavior consistent, take advantage of the fact that the kernel also resolves /proc/self/fd/ symlinks to the target of any symlinks in the same manner, so once we have opened the main executable in order to load it, replace the user-provided path with the result of calling readlink("/proc/self/fd/N"). (On non-Linux platforms this resolution does not happen and so no behavior change is needed.) Co-authored-by: Geoffrey Thomas --- elf/Makefile | 22 +++++++++++ elf/dl-load.c | 6 +++ elf/dl-origin.c | 6 +++ elf/liborigin-mod.c | 1 + elf/tst-origin.c | 26 +++++++++++++ elf/tst-origin.sh | 60 +++++++++++++++++++++++++++++ sysdeps/generic/ldsodefs.h | 4 ++ sysdeps/mach/hurd/Makefile | 2 + sysdeps/unix/sysv/linux/dl-origin.c | 23 +++++++++++ 9 files changed, 150 insertions(+) create mode 100644 elf/liborigin-mod.c create mode 100644 elf/tst-origin.c create mode 100755 elf/tst-origin.sh diff --git a/elf/Makefile b/elf/Makefile index 67052b5694..53cf154894 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -455,6 +455,7 @@ tests += \ tst-noload \ tst-non-directory-path \ tst-null-argv \ + tst-origin \ tst-p_align1 \ tst-p_align2 \ tst-p_align3 \ @@ -762,6 +763,7 @@ modules-names += \ libmarkermod5-3 \ libmarkermod5-4 \ libmarkermod5-5 \ + liborigin-mod \ libtracemod1-1 \ libtracemod2-1 \ libtracemod3-1 \ @@ -3433,3 +3435,23 @@ LDFLAGS-tst-version-hash-zero-linkmod.so = \ $(objpfx)tst-version-hash-zero-refmod.so: \ $(objpfx)tst-version-hash-zero-linkmod.so tst-version-hash-zero-refmod.so-no-z-defs = yes + +$(objpfx)tst-origin: $(objpfx)tst-origin.o $(objpfx)liborigin-mod.so + $(LINK.o) -o $@ -B$(csu-objpfx) $(LDFLAGS.so) $< \ + -Wl,-rpath,\$$ORIGIN \ + -L$(subst :, -L,$(rpath-link)) -Wl,--no-as-needed -lorigin-mod +$(objpfx)liborigin-mod.so: $(objpfx)liborigin-mod.os + $(LINK.o) -shared -o $@ -B$(csu-objpfx) $(LDFLAGS.so) \ + $(LDFLAGS-soname-fname) \ + $< +$(objpfx)tst-origin.out: tst-origin.sh $(objpfx)tst-origin + $(SHELL) \ + $< \ + '$(common-objpfx)' \ + '$(test-wrapper-env)' \ + '$(run-program-env)' \ + '$(rpath-link)' \ + tst-origin \ + liborigin-mod.so \ + > $@; \ + $(evaluate-test) diff --git a/elf/dl-load.c b/elf/dl-load.c index 4998652adf..6b7e9799f3 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -965,6 +965,12 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, { assert (nsid == LM_ID_BASE); memset (&id, 0, sizeof (id)); + char *realname_can = _dl_canonicalize (fd); + if (realname_can != NULL) + { + free (realname); + realname = realname_can; + } } else { diff --git a/elf/dl-origin.c b/elf/dl-origin.c index 9f6b921b01..812f5dbb28 100644 --- a/elf/dl-origin.c +++ b/elf/dl-origin.c @@ -47,3 +47,9 @@ _dl_get_origin (void) return result; } + +char * +_dl_canonicalize (int fd) +{ + return NULL; +} diff --git a/elf/liborigin-mod.c b/elf/liborigin-mod.c new file mode 100644 index 0000000000..aa6d4c27df --- /dev/null +++ b/elf/liborigin-mod.c @@ -0,0 +1 @@ +void foo (void) {} diff --git a/elf/tst-origin.c b/elf/tst-origin.c new file mode 100644 index 0000000000..734b2e81f6 --- /dev/null +++ b/elf/tst-origin.c @@ -0,0 +1,26 @@ +/* Test if $ORIGIN works correctly with symlinks (BZ 25263) + Copyright (C) 2025 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 + . */ + +extern void foo (void); + +int +main (int argc, char *argv[]) +{ + foo (); + return 0; +} diff --git a/elf/tst-origin.sh b/elf/tst-origin.sh new file mode 100755 index 0000000000..2555d3ed9e --- /dev/null +++ b/elf/tst-origin.sh @@ -0,0 +1,60 @@ +#!/bin/sh +# Test if $ORIGIN works correctly with symlinks (BZ 25263) +# Copyright (C) 2025 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 +# . + +set -e + +objpfx=$1 +test_wrapper_env=$2 +run_program_env=$3 +library_path=$4 +test_program=$5 +test_library=$6 + +cleanup() +{ + # Move the binary and library back to build directory + mv $tmpdir/sub/$test_program ${objpfx}elf + mv $tmpdir/sub/$test_library ${objpfx}elf + + rm -rf $tmpdir +} + +tmpdir=$(mktemp -d "${objpfx}elf/tst-origin.XXXXXXXXXX") +#trap cleanup 0 + +mkdir ${tmpdir}/sub + +# Remove the dependency from $library_path +mv ${objpfx}elf/$test_program $tmpdir/sub +mv ${objpfx}elf/$test_library $tmpdir/sub + +cd ${tmpdir} +ln -s sub/$test_program $test_program + +${test_wrapper_env} \ +${run_program_env} \ +${objpfx}elf/ld.so --library-path "$library_path" \ + ./$test_program 2>&1 && rc=0 || rc=$? + +# Also check if ldd resolves the dependency +LD_TRACE_LOADED_OBJECTS=1 \ +${objpfx}elf/ld.so --library-path "$library_path" \ + ./$test_program 2>&1 | grep 'not found' && rc=1 || rc=0 + +exit $rc diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 8465cbaa9b..19494b82ee 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -1223,6 +1223,10 @@ extern struct link_map * _dl_get_dl_main_map (void) attribute_hidden; /* Find origin of the executable. */ extern const char *_dl_get_origin (void) attribute_hidden; +/* Return the canonalized path name from the opened file descriptor FD, + or NULL otherwise. */ +extern char * _dl_canonicalize (int fd) attribute_hidden; + /* Count DSTs. */ extern size_t _dl_dst_count (const char *name) attribute_hidden; diff --git a/sysdeps/mach/hurd/Makefile b/sysdeps/mach/hurd/Makefile index 13e5cea4c2..4b69b40065 100644 --- a/sysdeps/mach/hurd/Makefile +++ b/sysdeps/mach/hurd/Makefile @@ -300,6 +300,8 @@ ifeq ($(subdir),elf) check-execstack-xfail += ld.so libc.so libpthread.so # We always create a thread for signals test-xfail-tst-single_threaded-pthread-static = yes +# Bug 25263 +test-xfail-tst-origin = yes CFLAGS-tst-execstack.c += -DDEFAULT_RWX_STACK=1 endif diff --git a/sysdeps/unix/sysv/linux/dl-origin.c b/sysdeps/unix/sysv/linux/dl-origin.c index decdd8ae9e..3c52ba51a6 100644 --- a/sysdeps/unix/sysv/linux/dl-origin.c +++ b/sysdeps/unix/sysv/linux/dl-origin.c @@ -21,6 +21,7 @@ #include #include #include +#include /* On Linux >= 2.1 systems which have the dcache implementation we can get the path of the application from the /proc/self/exe symlink. Try this @@ -72,3 +73,25 @@ _dl_get_origin (void) return result; } + +/* On Linux, readlink on the magic symlinks in /proc/self/fd also has + the same behavior of returning the canonical path from the dcache. + If it does not work, we do not bother to canonicalize. */ + +char * +_dl_canonicalize (int fd) +{ + struct fd_to_filename fdfilename; + char canonical[PATH_MAX]; + char *path = __fd_to_filename (fd, &fdfilename); + int size = INTERNAL_SYSCALL_CALL (readlinkat, AT_FDCWD, path, + canonical, PATH_MAX - 1); + + /* Check if the path was truncated. */ + if (size >= 0 && size < PATH_MAX - 1) + { + canonical[size] = '\0'; + return __strdup (canonical); + } + return NULL; +}