aboutsummaryrefslogtreecommitdiff
path: root/stdio-common
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2025-02-18 15:58:16 -0500
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2025-03-13 16:50:16 -0300
commit9b646f5dc933dfa019f2ed7f80b6198b43e31f62 (patch)
treef9f36d3010ff3ae93287aae0e945bfb8d23efba5 /stdio-common
parentdded0d20f67ba1925ccbcb9cf28f0c75febe0dbe (diff)
downloadglibc-9b646f5dc933dfa019f2ed7f80b6198b43e31f62.zip
glibc-9b646f5dc933dfa019f2ed7f80b6198b43e31f62.tar.gz
glibc-9b646f5dc933dfa019f2ed7f80b6198b43e31f62.tar.bz2
elf: Canonicalize $ORIGIN in an explicit ld.so invocation [BZ 25263]
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.) The __fd_to_filename requires _fitoa_word and _itoa_word, which for 32-bits pulls a lot of definitions from _itoa.c (due _ITOA_NEEDED being defined). To simplify the build move the required function to a new file, _fitoa_word.c. Checked on x86_64-linux-gnu and i686-linux-gnu. Co-authored-by: Geoffrey Thomas <geofft@ldpreload.com> Reviewed-by: Geoffrey Thomas <geofft@ldpreload.com> Tested-by: Geoffrey Thomas <geofft@ldpreload.com>
Diffstat (limited to 'stdio-common')
-rw-r--r--stdio-common/Makefile3
-rw-r--r--stdio-common/_fitoa_word.c59
-rw-r--r--stdio-common/_itoa.c43
3 files changed, 62 insertions, 43 deletions
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index b68e922..d3733d0 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -59,6 +59,7 @@ headers := \
# headers
routines := \
+ _fitoa_word \
_itoa \
_itowa \
asprintf \
@@ -663,6 +664,8 @@ CFLAGS-dprintf.c += $(config-cflags-wno-ignored-attributes)
# off for non-shared builds.
CFLAGS-_itoa.o = $(no-stack-protector)
CFLAGS-_itoa.op = $(no-stack-protector)
+CFLAGS-_fitoa_word.o = $(no-stack-protector)
+CFLAGS-_fitoa_word.op = $(no-stack-protector)
CFLAGS-scanf13.c += $(test-config-cflags-wno-fortify-source)
diff --git a/stdio-common/_fitoa_word.c b/stdio-common/_fitoa_word.c
new file mode 100644
index 0000000..8064b1e
--- /dev/null
+++ b/stdio-common/_fitoa_word.c
@@ -0,0 +1,59 @@
+/* Internal function for converting integers to ASCII.
+ Copyright (C) 1994-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
+ <https://www.gnu.org/licenses/>. */
+
+#include <_itoa.h>
+
+char *
+_itoa_word (_ITOA_WORD_TYPE value, char *buflim,
+ unsigned int base, int upper_case)
+{
+ const char *digits = (upper_case
+ ? _itoa_upper_digits
+ : _itoa_lower_digits);
+
+ switch (base)
+ {
+#define SPECIAL(Base) \
+ case Base: \
+ do \
+ *--buflim = digits[value % Base]; \
+ while ((value /= Base) != 0); \
+ break
+
+ SPECIAL (10);
+ SPECIAL (16);
+ SPECIAL (8);
+ default:
+ do
+ *--buflim = digits[value % base];
+ while ((value /= base) != 0);
+ }
+ return buflim;
+}
+#undef SPECIAL
+
+char *
+_fitoa_word (_ITOA_WORD_TYPE value, char *buf, unsigned int base,
+ int upper_case)
+{
+ char tmpbuf[sizeof (value) * 4]; /* Worst case length: base 2. */
+ char *cp = _itoa_word (value, tmpbuf + sizeof (value) * 4, base, upper_case);
+ while (cp < tmpbuf + sizeof (value) * 4)
+ *buf++ = *cp++;
+ return buf;
+}
diff --git a/stdio-common/_itoa.c b/stdio-common/_itoa.c
index 51c3ab9..08859f0 100644
--- a/stdio-common/_itoa.c
+++ b/stdio-common/_itoa.c
@@ -162,38 +162,6 @@ const struct base_table_t _itoa_base_table[] attribute_hidden =
};
#endif
-#if IS_IN (libc)
-char *
-_itoa_word (_ITOA_WORD_TYPE value, char *buflim,
- unsigned int base, int upper_case)
-{
- const char *digits = (upper_case
- ? _itoa_upper_digits
- : _itoa_lower_digits);
-
- switch (base)
- {
-#define SPECIAL(Base) \
- case Base: \
- do \
- *--buflim = digits[value % Base]; \
- while ((value /= Base) != 0); \
- break
-
- SPECIAL (10);
- SPECIAL (16);
- SPECIAL (8);
- default:
- do
- *--buflim = digits[value % base];
- while ((value /= base) != 0);
- }
- return buflim;
-}
-#undef SPECIAL
-#endif /* IS_IN (libc) */
-
-
#if _ITOA_NEEDED
char *
_itoa (unsigned long long int value, char *buflim, unsigned int base,
@@ -460,17 +428,6 @@ _itoa (unsigned long long int value, char *buflim, unsigned int base,
}
#endif
-char *
-_fitoa_word (_ITOA_WORD_TYPE value, char *buf, unsigned int base,
- int upper_case)
-{
- char tmpbuf[sizeof (value) * 4]; /* Worst case length: base 2. */
- char *cp = _itoa_word (value, tmpbuf + sizeof (value) * 4, base, upper_case);
- while (cp < tmpbuf + sizeof (value) * 4)
- *buf++ = *cp++;
- return buf;
-}
-
#if _ITOA_NEEDED
char *
_fitoa (unsigned long long value, char *buf, unsigned int base, int upper_case)