mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-10 05:59:39 +08:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e51a6bf18e | ||
|
|
b50e24aea3 | ||
|
|
c0a1c6e06d |
File diff suppressed because it is too large
Load Diff
@@ -480,7 +480,7 @@ build the GNU C Library:
|
||||
GCC 12.1 or higher is required. In general it is recommended to
|
||||
use the newest version of the compiler that is known to work for
|
||||
building the GNU C Library, as newer compilers usually produce
|
||||
better code. As of release time, GCC 16.1.1 is the newest compiler
|
||||
better code. As of release time, GCC 15.2.1 is the newest compiler
|
||||
verified to work to build the GNU C Library.
|
||||
|
||||
For multi-arch support it is recommended to use a GCC which has
|
||||
@@ -502,7 +502,7 @@ build the GNU C Library:
|
||||
|
||||
You must use GNU 'binutils' (as and ld) to build the GNU C Library.
|
||||
No other assembler or linker has the necessary functionality at the
|
||||
moment. As of release time, GNU 'binutils' 2.46.1 is the newest
|
||||
moment. As of release time, GNU 'binutils' 2.45.1 is the newest
|
||||
verified to work to build the GNU C Library.
|
||||
|
||||
* GNU 'texinfo' 4.7 or later
|
||||
@@ -511,7 +511,7 @@ build the GNU C Library:
|
||||
need this version of the 'texinfo' package. Earlier versions do
|
||||
not understand all the tags used in the document, and the
|
||||
installation mechanism for the info files is not present or works
|
||||
differently. As of release time, 'texinfo' 7.3 is the newest
|
||||
differently. As of release time, 'texinfo' 7.2 is the newest
|
||||
verified to work to build the GNU C Library.
|
||||
|
||||
* GNU 'awk' 3.1.2, or higher
|
||||
@@ -519,9 +519,13 @@ build the GNU C Library:
|
||||
'awk' is used in several places to generate files. Some 'gawk'
|
||||
extensions are used, including the 'asorti' function, which was
|
||||
introduced in version 3.1.2 of 'gawk'. As of release time, 'gawk'
|
||||
version 5.4.1 is the newest verified to work to build the GNU C
|
||||
version 5.3.2 is the newest verified to work to build the GNU C
|
||||
Library.
|
||||
|
||||
Testing the GNU C Library requires 'gawk' to be compiled with
|
||||
support for high precision arithmetic via the 'MPFR'
|
||||
multiple-precision floating-point computation library.
|
||||
|
||||
* GNU 'bison' 2.7 or later
|
||||
|
||||
'bison' is used to generate the 'yacc' parser code in the 'intl'
|
||||
@@ -532,19 +536,19 @@ build the GNU C Library:
|
||||
|
||||
Perl is not required, but if present it is used in some tests and
|
||||
the 'mtrace' program, to build the GNU C Library manual. As of
|
||||
release time 'perl' version 5.44.0 is the newest verified to work
|
||||
release time 'perl' version 5.42.0 is the newest verified to work
|
||||
to build the GNU C Library.
|
||||
|
||||
* GNU 'sed' 3.02 or newer
|
||||
|
||||
'Sed' is used in several places to generate files. Most scripts
|
||||
work with any version of 'sed'. As of release time, 'sed' version
|
||||
4.10 is the newest verified to work to build the GNU C Library.
|
||||
4.9 is the newest verified to work to build the GNU C Library.
|
||||
|
||||
* Python 3.4 or later
|
||||
|
||||
Python is required to build the GNU C Library. As of release time,
|
||||
Python 3.14.6 is the newest verified to work for building and
|
||||
Python 3.14.0 is the newest verified to work for building and
|
||||
testing the GNU C Library.
|
||||
|
||||
* PExpect 4.0
|
||||
@@ -630,7 +634,7 @@ components of the GNU C Library installation to be in '/lib' and some in
|
||||
Library with '--prefix=/usr'. If you set some other prefix or allow it
|
||||
to default to '/usr/local', then all the components are installed there.
|
||||
|
||||
As of release time, Linux version 7.1 is the newest stable version
|
||||
As of release time, Linux version 6.12 is the newest stable version
|
||||
verified to work to build the GNU C Library.
|
||||
|
||||
Reporting Bugs
|
||||
|
||||
+1
-28
@@ -165,15 +165,6 @@ rtlddir = $(slibdir)
|
||||
endif
|
||||
inst_rtlddir = $(install_root)$(rtlddir)
|
||||
|
||||
# Directory referenced by the libc.so linker script (AS_NEEDED entry) for
|
||||
# the dynamic linker at build time. This points at the location where the
|
||||
# loader is actually installed so the linker can resolve it while building
|
||||
# against libc. It defaults to rtlddir (where it differs, the loader is
|
||||
# installed in rtlddir-build but identified/loaded at runtime via rtlddir).
|
||||
ifndef rtlddir-build
|
||||
rtlddir-build = $(rtlddir)
|
||||
endif
|
||||
|
||||
# Prefix to put on files installed in $(libdir). For libraries `libNAME.a',
|
||||
# the prefix is spliced between `lib' and the name, so the linker switch
|
||||
# `-l$(libprefix)NAME' finds the library; for other files the prefix is
|
||||
@@ -791,14 +782,6 @@ run-built-tests = yes
|
||||
endif
|
||||
endif
|
||||
|
||||
# Whether the timing-sensitive test runs are serialized: each is run with
|
||||
# .NOTPARALLEL and, at the top level, ordered after the rest of the test run.
|
||||
# This is the default; 'make check-parallel' clears it to run every test
|
||||
# concurrently.
|
||||
ifndef serialize-tests
|
||||
serialize-tests = yes
|
||||
endif
|
||||
|
||||
# Whether to build the static math tests
|
||||
ifndef build-math-static-tests
|
||||
build-math-static-tests = no
|
||||
@@ -832,15 +815,8 @@ $(subst $(empty) ,:,$(strip $(patsubst -Wl$(comma)-rpath-link=%, %,\
|
||||
run-via-rtld-prefix = \
|
||||
$(if $(strip $(filter $(notdir $(built-program-file)), \
|
||||
$(tests-static) $(xtests-static))),, $(rtld-prefix))
|
||||
# $(container-via-rtld-prefix) is like $(run-via-rtld-prefix), but for the
|
||||
# support/test-container helper, which is always dynamically linked even
|
||||
# when the test it launches is static. It must therefore always run
|
||||
# through the newly built loader, unlike $(run-via-rtld-prefix) which is
|
||||
# empty for tests listed in tests-static or xtests-static.
|
||||
container-via-rtld-prefix = $(rtld-prefix)
|
||||
else
|
||||
run-via-rtld-prefix =
|
||||
container-via-rtld-prefix =
|
||||
endif
|
||||
# $(run-program-env) is the default environment variable settings to
|
||||
# use when running a program built with the newly built library.
|
||||
@@ -907,7 +883,6 @@ endif
|
||||
|
||||
ifeq (yes,$(build-hardcoded-path-in-tests))
|
||||
test-via-rtld-prefix =
|
||||
test-container-via-rtld-prefix =
|
||||
test-program-prefix-before-env = $(test-wrapper-env)
|
||||
test-program-prefix-after-env =
|
||||
test-program-prefix = $(test-program-prefix-before-env) $(run-program-env) \
|
||||
@@ -919,7 +894,6 @@ test-program-cmd = $(test-program-cmd-before-env) $(run-program-env) \
|
||||
host-test-program-cmd = $(built-program-file)
|
||||
else
|
||||
test-via-rtld-prefix = $(run-via-rtld-prefix)
|
||||
test-container-via-rtld-prefix = $(container-via-rtld-prefix)
|
||||
test-program-prefix-before-env = $(run-program-prefix-before-env)
|
||||
test-program-prefix-after-env = $(run-program-prefix-after-env)
|
||||
test-program-prefix = $(run-program-prefix)
|
||||
@@ -959,9 +933,8 @@ endif
|
||||
installed-modules = nonlib nscd ldconfig locale_programs \
|
||||
iconvprogs libnss_files libnss_compat libnss_db libnss_hesiod \
|
||||
libutil libpcprofile libnsl
|
||||
+time64-flags = -D_TIME_BITS=64
|
||||
+extra-time-flags = $(if $(filter $(installed-modules),\
|
||||
$(in-module)),$(+time64-flags) -D_FILE_OFFSET_BITS=64)
|
||||
$(in-module)),-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64)
|
||||
|
||||
# We might want to compile with some stack-protection flag.
|
||||
ifneq ($(stack-protector),)
|
||||
|
||||
@@ -54,6 +54,9 @@ configure: configure.ac aclocal.m4; $(autoconf-it)
|
||||
endif # $(AUTOCONF) = no
|
||||
|
||||
|
||||
# We don't want to run anything here in parallel.
|
||||
.NOTPARALLEL:
|
||||
|
||||
# These are the targets that are made by making them in each subdirectory.
|
||||
+subdir_targets := subdir_lib objects objs others subdir_mostlyclean \
|
||||
subdir_clean subdir_distclean subdir_realclean \
|
||||
@@ -126,13 +129,6 @@ lib-noranlib: subdir_lib
|
||||
ifeq (yes,$(build-shared))
|
||||
# Build the shared object from the PIC object library.
|
||||
lib: $(common-objpfx)libc.so $(common-objpfx)linkobj/libc.so
|
||||
ifdef libc.so-version
|
||||
# Every program linked in the others pass lists the versioned name
|
||||
# (through link-libc-between-gnulib) as a prerequisite, and the rule
|
||||
# creating the symbolic link is visible in every sub-make. Build it
|
||||
# here once so the concurrent sub-makes do not race to create it.
|
||||
lib: $(common-objpfx)libc.so$(libc.so-version)
|
||||
endif
|
||||
endif # $(build-shared)
|
||||
|
||||
# Used to build testrun.sh.
|
||||
@@ -494,159 +490,6 @@ subdir=$(@D)$(if $($(@D)-srcdir),\
|
||||
endef
|
||||
|
||||
.PHONY: $(+subdir_targets) $(all-subdirs-targets)
|
||||
|
||||
# Encode the topological ordering computed by scripts/gen-sorted.awk as
|
||||
# explicit dependencies between the per-subdirectory targets, so that
|
||||
# independent subdirectories build concurrently. In summary:
|
||||
#
|
||||
# * Every subdirectory depends on the first sorted one (csu, or mach on
|
||||
# Hurd): its sub-make also materializes the shared generated files in
|
||||
# $(common-objpfx) (abi-versions.h, sysd-syscalls, before-compile
|
||||
# headers, ...) that concurrent sub-makes would otherwise race to
|
||||
# create.
|
||||
#
|
||||
# * The edges requested by the Depend files (emitted by gen-sorted.awk
|
||||
# as subdir-deps-*) are preserved.
|
||||
#
|
||||
# * elf stays last for the object-building classes, as in the sorted
|
||||
# list: its rtld link consumes $(common-objpfx)libc_pic.a, which
|
||||
# aggregates every other subdirectory's objects, and its rtld-Rules
|
||||
# recursion compiles into the other subdirectories' object
|
||||
# directories. The others/tests/xtests classes have no such
|
||||
# dependency (the pass barriers below provide everything they need),
|
||||
# so elf is unordered there.
|
||||
#
|
||||
# * Only target classes without cross-directory file conflicts use this
|
||||
# sparse ordering; everything else (install, clean, abi, stubs) keeps
|
||||
# the previous total order via a serial chain.
|
||||
|
||||
+elf_last_subdir_targets := \
|
||||
subdir_lib objects \
|
||||
objs \
|
||||
subdir_objs \
|
||||
# +elf_last_subdir_targets
|
||||
+parallel_subdir_targets := \
|
||||
$(+elf_last_subdir_targets) \
|
||||
others \
|
||||
tests \
|
||||
xtests \
|
||||
# +parallel_subdir_targets
|
||||
+serial_subdir_targets := $(filter-out $(+parallel_subdir_targets),\
|
||||
$(+subdir_targets))
|
||||
|
||||
# The tests and xtests classes run, rather than build, the per-directory
|
||||
# test programs; once the 'others' pass barrier below has built the tree
|
||||
# they are mutually independent and carry no cross-directory ordering.
|
||||
# Keeping them out of the generated-file and Depend edges below is what
|
||||
# lets 'make subdir/tests' run only that subdirectory's tests.
|
||||
+barrier_only_subdir_targets := tests xtests
|
||||
+ordered_parallel_subdir_targets := \
|
||||
$(filter-out $(+barrier_only_subdir_targets),$(+parallel_subdir_targets))
|
||||
|
||||
# The subdirectories that generate shared files in $(common-objpfx)
|
||||
# consumed by the rest of the build without explicit dependencies: csu
|
||||
# provides the gen-as-const headers, and on Hurd the mach and hurd
|
||||
# directories generate the MiG RPC headers (every other subdirectory
|
||||
# otherwise runs a nested make in hurd/ to create them, racing under
|
||||
# parallel recursion; see sysdeps/mach/hurd/Makefile). Run them serially,
|
||||
# in their sorted order (mach, hurd, csu).
|
||||
+subdir-pregen := $(filter mach hurd csu,$(subdirs))
|
||||
+subdir-rest := $(filter-out $(+subdir-pregen),$(subdirs))
|
||||
|
||||
$(foreach t,$(+ordered_parallel_subdir_targets),$(eval \
|
||||
$(addsuffix /$(t),$(+subdir-rest)): $(addsuffix /$(t),$(+subdir-pregen))))
|
||||
+subdir-pregen-prev :=
|
||||
$(foreach d,$(+subdir-pregen),$(foreach t,$(+ordered_parallel_subdir_targets),$(eval \
|
||||
$(d)/$(t): $(addsuffix /$(t),$(+subdir-pregen-prev))))\
|
||||
$(eval +subdir-pregen-prev := $(d)))
|
||||
# For the classes where elf is forced last, edges pointing to elf are
|
||||
# dropped: the sorted list always overrides such Depend requests today
|
||||
# (e.g. support/Depend), and the elf-last edges below would otherwise
|
||||
# create a cycle. The remaining classes honor them.
|
||||
$(foreach t,$(+elf_last_subdir_targets),$(foreach d,$(+subdir-rest),$(eval \
|
||||
$(d)/$(t): $(addsuffix /$(t),\
|
||||
$(filter-out elf,$(filter $(subdirs),$(subdir-deps-$(d))))))))
|
||||
$(foreach t,$(filter-out $(+elf_last_subdir_targets),\
|
||||
$(+ordered_parallel_subdir_targets)),\
|
||||
$(foreach d,$(+subdir-rest),$(eval \
|
||||
$(d)/$(t): $(addsuffix /$(t),$(filter $(subdirs),$(subdir-deps-$(d)))))))
|
||||
ifneq (,$(filter elf,$(subdirs)))
|
||||
$(foreach t,$(+elf_last_subdir_targets),$(eval \
|
||||
elf/$(t): $(addsuffix /$(t),$(filter-out elf,$(subdirs)))))
|
||||
endif
|
||||
|
||||
# The archive rules in Makerules list every stamp file as a
|
||||
# prerequisite of libc_pic.a, which the elf sub-make evaluates for the
|
||||
# librtld.map link, but a sub-make can only create its own directory's
|
||||
# stamps. Create the top-level ones before the fan-out.
|
||||
$(foreach t,$(+elf_last_subdir_targets),$(eval \
|
||||
$(addsuffix /$(t),$(subdirs)): \
|
||||
$(foreach o,$(object-suffixes-for-libc),$(common-objpfx)stamp$(o))))
|
||||
|
||||
# Pass barriers: a subdirectory 'others' build links programs against
|
||||
# the libraries, so the 'lib' pass (including the top-level libc.so
|
||||
# link) must have completed.
|
||||
# 'tests' and 'xtests' additionally require the 'others' pass. The
|
||||
# testroot used by the container tests performs a full installation in
|
||||
# its recipe, which must not run concurrently with the build passes.
|
||||
$(addsuffix /others,$(subdirs)): lib
|
||||
$(addsuffix /tests,$(subdirs)) $(addsuffix /xtests,$(subdirs)): others
|
||||
$(objpfx)testroot.pristine/install.stamp: | others
|
||||
|
||||
# Timing-sensitive test runs: the threading tests (nptl/htl) and the realtime
|
||||
# tests (rt) are perturbed by the machine load, so run them after the rest of
|
||||
# the test run has finished and one group at a time. Those subdirectories
|
||||
# also serialize their own tests (.NOTPARALLEL in their Makefiles).
|
||||
#
|
||||
# This only orders a full-suite run ('make check'/'tests'); a targeted
|
||||
# 'make subdir/tests' is left alone. And it only orders the test run
|
||||
# (run-built-tests=yes); the "build the tests" pass (run-built-tests=no)
|
||||
# is left fully parallel, so every test program still builds concurrently.
|
||||
# serialize-tests=no ('make check-parallel') drops the ordering entirely.
|
||||
ifeq ($(run-built-tests),yes)
|
||||
ifeq (yes,$(serialize-tests))
|
||||
ifneq (,$(filter tests xtests check xcheck,$(MAKECMDGOALS)))
|
||||
+late-test-subdirs := $(filter nptl htl,$(subdirs)) $(filter rt,$(subdirs))
|
||||
+test-run-prev := \
|
||||
$(addsuffix /tests,$(filter-out $(+late-test-subdirs),$(subdirs)))
|
||||
$(foreach d,$(+late-test-subdirs),\
|
||||
$(eval $(d)/tests: $(+test-run-prev))\
|
||||
$(eval +test-run-prev += $(d)/tests))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
# The top-level libc.so and linkobj/libc_pic.a rules list these
|
||||
# subdirectory-built files as prerequisites, but no rule at this level
|
||||
# builds them. The explicit empty recipe (';') is required, a
|
||||
# prerequisite-only rule would send make on an implicitrule search and
|
||||
# have this level compile them itself with the wrong context.
|
||||
ifneq (,$(filter elf,$(subdirs)))
|
||||
$(elf-objpfx)ld.so $(elf-objpfx)sofini.os $(elf-objpfx)interp.os: \
|
||||
| elf/subdir_lib ;
|
||||
endif
|
||||
ifneq (,$(filter sunrpc,$(subdirs)))
|
||||
# Makerules explicit adds librpc_compat_pic.a as a dependency of
|
||||
# libc_pic.a.
|
||||
$(common-objpfx)sunrpc/librpc_compat_pic.a: | sunrpc/subdir_lib ;
|
||||
endif
|
||||
# Hurd sysdedp Makeilfe links libc.so against the lib*user-link.so
|
||||
# objects, built by the %-link.so: %_pic.a pattern rule from archives
|
||||
# that only the mach and hurd sub-makes create.
|
||||
ifneq (,$(filter mach,$(subdirs)))
|
||||
$(common-objpfx)mach/libmachuser_pic.a: | mach/subdir_lib ;
|
||||
endif
|
||||
ifneq (,$(filter hurd,$(subdirs)))
|
||||
$(common-objpfx)hurd/libhurduser_pic.a: | hurd/subdir_lib ;
|
||||
endif
|
||||
endif
|
||||
|
||||
# The remaining target classes keep the old total order.
|
||||
+subdir-chain-prev :=
|
||||
$(foreach d,$(subdirs),$(foreach t,$(+serial_subdir_targets),$(eval \
|
||||
$(d)/$(t): $(addsuffix /$(t),$(+subdir-chain-prev))))\
|
||||
$(eval +subdir-chain-prev := $(d)))
|
||||
|
||||
# Targets to clean things up to various degrees.
|
||||
|
||||
@@ -697,41 +540,26 @@ $(objpfx)check-local-headers.out: scripts/check-local-headers.sh
|
||||
$(evaluate-test)
|
||||
|
||||
ifneq "$(headers)" ""
|
||||
# Special test of all the installed headers in this directory. See
|
||||
# Rules for the per-header split rationale.
|
||||
# Special test of all the installed headers in this directory.
|
||||
tests-special += $(objpfx)check-installed-headers-c.out
|
||||
libof-check-installed-headers-c := testsuite
|
||||
+cih-c-iouts := $(patsubst %,$(objpfx)check-installed-headers-c/%.iout,\
|
||||
$(headers))
|
||||
$(+cih-c-iouts): $(objpfx)check-installed-headers-c/%.iout: \
|
||||
$(objpfx)check-installed-headers-c.out: \
|
||||
scripts/check-installed-headers.sh $(headers)
|
||||
$(make-target-directory)
|
||||
($(SHELL) $(..)scripts/check-installed-headers.sh c $(supported-fortify) \
|
||||
"$(CC) $(test-config-cflags-finput-charset-ascii) \
|
||||
$(filter-out -std=%,$(CFLAGS)) -D_ISOMAC $(+includes)" \
|
||||
$*; echo $$? > $@-ret) > $@T; \
|
||||
mv -f $@T $@
|
||||
$(objpfx)check-installed-headers-c.out: $(+cih-c-iouts)
|
||||
cat $^ > $@; \
|
||||
! grep -qv '^0$$' $(+cih-c-iouts:%=%-ret); \
|
||||
$(SHELL) $(..)scripts/check-installed-headers.sh c $(supported-fortify) \
|
||||
"$(CC) $(test-config-cflags-finput-charset-ascii) \
|
||||
$(filter-out -std=%,$(CFLAGS)) -D_ISOMAC $(+includes)" \
|
||||
$(headers) > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
ifneq "$(CXX)" ""
|
||||
tests-special += $(objpfx)check-installed-headers-cxx.out
|
||||
libof-check-installed-headers-cxx := testsuite
|
||||
+cih-cxx-iouts := $(patsubst %,$(objpfx)check-installed-headers-cxx/%.iout,\
|
||||
$(headers))
|
||||
$(+cih-cxx-iouts): $(objpfx)check-installed-headers-cxx/%.iout: \
|
||||
$(objpfx)check-installed-headers-cxx.out: \
|
||||
scripts/check-installed-headers.sh $(headers)
|
||||
$(make-target-directory)
|
||||
($(SHELL) $(..)scripts/check-installed-headers.sh c++ $(supported-fortify) \
|
||||
"$(CXX) $(test-config-cxxflags-finput-charset-ascii) \
|
||||
$(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
|
||||
$*; echo $$? > $@-ret) > $@T; \
|
||||
mv -f $@T $@
|
||||
$(objpfx)check-installed-headers-cxx.out: $(+cih-cxx-iouts)
|
||||
cat $^ > $@; \
|
||||
! grep -qv '^0$$' $(+cih-cxx-iouts:%=%-ret); \
|
||||
$(SHELL) $(..)scripts/check-installed-headers.sh c++ $(supported-fortify) \
|
||||
"$(CXX) $(test-config-cxxflags-finput-charset-ascii) \
|
||||
$(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
|
||||
$(headers) > $@; \
|
||||
$(evaluate-test)
|
||||
endif # $(CXX)
|
||||
|
||||
@@ -820,13 +648,8 @@ else
|
||||
LINKS_DSO_PROGRAM = links-dso-program
|
||||
endif
|
||||
|
||||
# The testroot is only used by the container tests, which are not run
|
||||
# when run-built-tests is no; skip the installation entirely in that
|
||||
# case.
|
||||
ifeq ($(run-built-tests),yes)
|
||||
$(tests-container) $(addsuffix /tests,$(subdirs)) : \
|
||||
$(objpfx)testroot.pristine/install.stamp
|
||||
endif
|
||||
$(objpfx)testroot.pristine/install.stamp :
|
||||
test -d $(objpfx)testroot.pristine || \
|
||||
mkdir $(objpfx)testroot.pristine
|
||||
@@ -877,11 +700,7 @@ endif
|
||||
touch $(objpfx)testroot.pristine/install.stamp
|
||||
|
||||
tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
|
||||
# The build-only first pass of the two-pass 'make check' (see Makerules)
|
||||
# passes tests-summary=no: the merge and summary are left to the second
|
||||
# pass, which folds in this pass's $(tests-special) results.
|
||||
tests: $(tests-special)
|
||||
ifneq ($(tests-summary),no)
|
||||
$(..)scripts/merge-test-results.sh -s $(objpfx) "" \
|
||||
$(sort $(tests-special-notdir:.out=)) \
|
||||
> $(objpfx)subdir-tests.sum
|
||||
@@ -889,14 +708,11 @@ ifneq ($(tests-summary),no)
|
||||
$(sort $(subdirs) .) \
|
||||
> $(objpfx)tests.sum
|
||||
$(call summarize-tests,tests.sum)
|
||||
endif
|
||||
xtests:
|
||||
ifneq ($(tests-summary),no)
|
||||
$(..)scripts/merge-test-results.sh -t $(objpfx) subdir-xtests.sum \
|
||||
$(sort $(subdirs)) \
|
||||
> $(objpfx)xtests.sum
|
||||
$(call summarize-tests,xtests.sum, for extra tests)
|
||||
endif
|
||||
|
||||
# The realclean target is just like distclean for the parent, but we want
|
||||
# the subdirs to know the difference in case they care.
|
||||
|
||||
@@ -259,17 +259,7 @@ endif # gen-py-const-headers
|
||||
ifdef gen-as-const-headers
|
||||
# Generating headers for assembly constants.
|
||||
# We need this defined early to get into before-compile before
|
||||
# it's used in sysd-rules, below. The gen-as-const-headers is evaluated
|
||||
# per subdirectory, so the before-compile dependency below only orders
|
||||
# the generated header before the compiles of the subdirectory whose
|
||||
# Makefile adds the .sym directive.
|
||||
# The parallel subdirectory recursion does not order sibling subdirectories,
|
||||
# so a .sym must be added in the subdirectory that compiles its consumers,
|
||||
# or in csu (which runs before the parallel) when it has consumers in
|
||||
# several subdirectories.
|
||||
# It must not add the same .sym in several subdirectories though: their
|
||||
# concurrent sub-makes would race generating the header through the fixed
|
||||
# temporary files below.
|
||||
# it's used in sysd-rules, below.
|
||||
# Define GEN_AS_CONST_HEADERS to avoid circular dependency [BZ #22792].
|
||||
# NB: <tcb-offsets.h> is generated from tcb-offsets.sym to define
|
||||
# offsets and sizes of types in <tls.h> and maybe <pthread.h> which
|
||||
@@ -312,12 +302,7 @@ lib-names-h-abi = gnu/lib-names-$(default-abi).h
|
||||
lib-names-stmp-abi = gnu/lib-names-$(default-abi).stmp
|
||||
before-compile += $(common-objpfx)$(lib-names-h-abi)
|
||||
common-generated += gnu/lib-names.h
|
||||
# The $(inst_includedir)/%.h install rules are defined only where $(headers)
|
||||
# is non-empty, and with parallel subdir recursion a subdir without headers
|
||||
# (e.g. csu) may run before the top level has installed the header.
|
||||
ifndef subdir
|
||||
install-others-nosubdir: $(inst_includedir)/$(lib-names-h-abi)
|
||||
endif
|
||||
$(common-objpfx)gnu/lib-names.h:
|
||||
$(make-target-directory)
|
||||
{ \
|
||||
@@ -758,20 +743,10 @@ all-dt-files := $(foreach o,$(object-suffixes-for-libc),$(+depfiles:.d=$o.dt))
|
||||
$(wildcard $(all-dt-files:.dt=.d))
|
||||
|
||||
# This is a funny rule in that it removes its input file.
|
||||
#
|
||||
# More than one make can convert the .dt files of a single object
|
||||
# directory: the elf rtld-Rules recursion runs a sub-make over every
|
||||
# $(rtld-subdirs) directory, concurrently with that directory's own
|
||||
# sub-make under the parallel subdir recursion. Add the PID of the
|
||||
# shell to the temporary name and claim the input with a rename: only
|
||||
# the run that wins converts and installs the target.
|
||||
%.d: %.dt
|
||||
@dt=$(@:.d=.T)$$$$; \
|
||||
if mv -f $< $$dt 2>/dev/null; then \
|
||||
sed $(sed-remove-objpfx) $$dt > $$dt.new && \
|
||||
mv -f $$dt.new $@ && \
|
||||
rm -f $$dt; \
|
||||
fi
|
||||
@sed $(sed-remove-objpfx) $< > $(@:.d=.T) && \
|
||||
mv -f $(@:.d=.T) $@ && \
|
||||
rm -f $<
|
||||
|
||||
# Avoid the .h.d files for any .sym files whose .h files don't exist yet.
|
||||
# They will be generated when they're needed, and trying too early won't work.
|
||||
@@ -1049,7 +1024,7 @@ $(inst_libdir)/libc.so: $(common-objpfx)format.lds \
|
||||
cat $<; \
|
||||
echo 'GROUP ( $(slibdir)/libc.so$(libc.so-version)' \
|
||||
'$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)$(libc-name))'\
|
||||
' AS_NEEDED (' $(rtlddir-build)/$(rtld-installed-name) ') )' \
|
||||
' AS_NEEDED (' $(rtlddir)/$(rtld-installed-name) ') )' \
|
||||
) > $@.new
|
||||
mv -f $@.new $@
|
||||
|
||||
@@ -1209,55 +1184,12 @@ ALL_BUILD_CFLAGS = $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) -D_GNU_SOURCE \
|
||||
-DIS_IN_build -include $(common-objpfx)config.h
|
||||
|
||||
# Support the GNU standard name for this target.
|
||||
# Special target xcheck runs tests which cannot be run unconditionally;
|
||||
# maintainers should use this target.
|
||||
.PHONY: check xcheck
|
||||
|
||||
# Building and running a subdirectory's tests are fused in its sub-make,
|
||||
# and run-built-tests is fixed for a make instance, so the only way to
|
||||
# build every test program with the recursion fully parallel while the
|
||||
# run still honors the per-subdirectory .NOTPARALLEL (nptl/htl/rt) and the
|
||||
# run-time ordering is to use two passes. At the top level, 'make check'
|
||||
# therefore builds the test programs (run-built-tests=no, recursion fully
|
||||
# parallel) and then runs them (run-built-tests=yes). 'make tests' and a
|
||||
# subdirectory's own 'check' stay single-pass.
|
||||
# The first pass still runs the static checks ($(tests-special): abi,
|
||||
# conformtest, installed headers, ...), so tests-summary=no makes it skip
|
||||
# the results merge and summary: an unexpected FAIL there would otherwise
|
||||
# abort 'check' before the second pass runs any built test, and even a
|
||||
# clean run would print a misleading partial summary. The .test-result
|
||||
# files persist, so the second pass folds those results into the one
|
||||
# complete summary at the end.
|
||||
check-twopass :=
|
||||
ifndef subdir
|
||||
ifeq (yes,$(run-built-tests))
|
||||
check-twopass := yes
|
||||
endif
|
||||
endif
|
||||
ifeq (yes,$(check-twopass))
|
||||
check:
|
||||
$(MAKE) run-built-tests=no tests-summary=no tests
|
||||
$(MAKE) run-built-tests=yes tests
|
||||
xcheck:
|
||||
$(MAKE) run-built-tests=no tests-summary=no xtests
|
||||
$(MAKE) run-built-tests=yes xtests
|
||||
else
|
||||
.PHONY: check
|
||||
check: tests
|
||||
# Special target to run tests which cannot be run unconditionally.
|
||||
# Maintainers should use this target.
|
||||
.PHONY: xcheck
|
||||
xcheck: xtests
|
||||
endif
|
||||
|
||||
# 'make check-parallel' runs the whole suite with maximum concurrency:
|
||||
# serialize-tests=no drops the per-subdirectory .NOTPARALLEL and the run-time
|
||||
# ordering, so every test builds and runs in parallel. A single pass suffices
|
||||
# (there is no .NOTPARALLEL to work around, so the test programs already build
|
||||
# concurrently).
|
||||
# This is faster on an idle machine, at the cost of possible flakiness in the
|
||||
# timing-sensitive tests under the heavier load.
|
||||
.PHONY: check-parallel xcheck-parallel
|
||||
check-parallel:
|
||||
$(MAKE) serialize-tests=no tests
|
||||
xcheck-parallel:
|
||||
$(MAKE) serialize-tests=no xtests
|
||||
|
||||
# Also handle test inputs in sysdeps.
|
||||
vpath %.input $(sysdirs)
|
||||
@@ -1267,7 +1199,7 @@ vpath %.input $(sysdirs)
|
||||
include $(o-iterator)
|
||||
define o-iterator-doit
|
||||
$(foreach f,$(tests-time64) $(xtests-time64),\
|
||||
$(objpfx)$(f)$(o)): CFLAGS += $(+time64-flags) -D_FILE_OFFSET_BITS=64
|
||||
$(objpfx)$(f)$(o)): CFLAGS += -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
|
||||
endef
|
||||
object-suffixes-left := $(all-object-suffixes)
|
||||
include $(o-iterator)
|
||||
@@ -1443,7 +1375,7 @@ endef
|
||||
# Also remove the dependencies and generated source files.
|
||||
common-clean: common-mostlyclean
|
||||
-rm -f $(addprefix $(objpfx),$(generated))
|
||||
-rm -f $(objpfx)*.d $(objpfx)*.dt $(objpfx)*.T[0-9]*
|
||||
-rm -f $(objpfx)*.d $(objpfx)*.dt
|
||||
-rm -fr $(addprefix $(objpfx),$(generated-dirs))
|
||||
-rm -f $(addprefix $(common-objpfx),$(common-generated))
|
||||
-rm -f $(gen-as-const-headers:%.sym=$(common-objpfx)%.h)
|
||||
|
||||
@@ -5,101 +5,48 @@ See the end for copying conditions.
|
||||
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
|
||||
using `glibc' in the "product" field.
|
||||
|
||||
Version 2.45
|
||||
|
||||
Major new features:
|
||||
|
||||
[Add new features here]
|
||||
|
||||
Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
[Add deprecations, removals and changes affecting compatibility here]
|
||||
|
||||
Changes to build and runtime requirements:
|
||||
|
||||
[Add changes to build and runtime requirements here]
|
||||
|
||||
Security related changes:
|
||||
|
||||
The following CVEs were fixed in this release, details of which can be
|
||||
found in the advisories directory of the release tarball:
|
||||
|
||||
[The release manager will add the list generated by
|
||||
scripts/process-advisories.sh just before the release.]
|
||||
|
||||
The following bugs were resolved with this release:
|
||||
|
||||
[The release manager will add the list generated by
|
||||
scripts/list-fixed-bugs.py just before the release.]
|
||||
|
||||
Version 2.44
|
||||
|
||||
Major new features:
|
||||
|
||||
* System-wide tunables can be applied using /etc/tunables.conf and
|
||||
running ldconfig. Specific tunable settings and the
|
||||
/etc/tunables.conf file format and path are not part of the stable
|
||||
library interfaces and may change between releases.
|
||||
|
||||
* A new tunable, glibc.elf.thp, is added to map read-only segments with
|
||||
Transparent Huge Pages (THP) if THP is not disabled in the kernel. When
|
||||
Transparent Huge Pages (THP) if THP isn't disable in kernel. When
|
||||
glibc.elf.thp is set to 1, malloc uses the actual kernel THP mode
|
||||
instead of defaulting to madvise mode and madvise_thp will stop issuing
|
||||
MADV_HUGEPAGE if kernel THP mode is always.
|
||||
|
||||
* The THP page size in malloc is capped to MAX_THP_PAGESIZE. If the THP
|
||||
page size is above MAX_THP_PAGESIZE, THP in malloc is disabled.
|
||||
* THP page size in malloc is capped to MAX_THP_PAGESIZE. If THP page
|
||||
size is above MAX_THP_PAGESIZE, THP in malloc is disabled.
|
||||
|
||||
* Additional optimized and correctly rounded mathematical functions have
|
||||
been imported from the CORE-MATH project, in particular cosh, sinh, and
|
||||
tanh.
|
||||
|
||||
* Many additional improvements to existing functions have been synchronized
|
||||
from the CORE-MATH project.
|
||||
* The SVID handling for cosh and sinh were moved to compat symbols, allowing
|
||||
improvements in performance.
|
||||
|
||||
* For C++26, the assert macro is now variadic, allowing more complex
|
||||
arguments containing commas (which however still must evaluate to a single
|
||||
value).
|
||||
|
||||
* The SVID error handling for cosh and sinh was moved to compatibility
|
||||
symbols, allowing improvements in performance.
|
||||
* New locale added: hrx_BR (Hunsrik language spoken in Brazil).
|
||||
|
||||
* Static PIE is now supported for arm-*-linux-gnueabi. It requires toolchain
|
||||
support to correctly set the expected linker options.
|
||||
|
||||
* On AArch64 targets that support the Guarded Control Stack extension all GCS
|
||||
* On AArch64 targets that support Guarded Control Stack extension all GCS
|
||||
operations (including status, write on shadow stack, and push to shadow
|
||||
stack) are locked after enabling GCS with ENFORCED or OVERRIDE GCS policy.
|
||||
When a GCS operation is locked, a program cannot change this operation
|
||||
status via the prctl syscall. This prevents disabling or corrupting the
|
||||
GCS shadow stack during runtime.
|
||||
|
||||
* On AArch64 targets, log, exp, sin, cas, sinh, cosh, asinh, acosh, atanh
|
||||
single and double precision special cases have been vectorized for SVE and
|
||||
AdvSIMD, and vector variants of powr have been added.
|
||||
|
||||
* On RISC-V targets, vector extension optimized variants of memcmp, memccpy,
|
||||
memchr, memcpy, memmove, stpncpy, strcmp, strchr, strcpy, strncmp, strncpy,
|
||||
strlen, and strrchr have been added.
|
||||
|
||||
* On PowerPC, memchr optimized for Power10 has been re-added.
|
||||
|
||||
* Support for LoongArch32 has been added.
|
||||
|
||||
* Pre-built ld.so.cache files can be installed with ldconfig.
|
||||
|
||||
* A new locale has been added: hrx_BR (Hunsrik language spoken in Brazil).
|
||||
status via prctl syscall. This prevents disabling or corrupting GCS
|
||||
shadow stack during runtime.
|
||||
|
||||
Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
* Although malloc and related functions currently return pointers
|
||||
aligned to alignof (max_align_t), the documentation now says future
|
||||
versions of glibc may relax alignment requirements for small allocations.
|
||||
For example, a future malloc(1) might return a pointer with odd
|
||||
For example, a future malloc (1) might return a pointer with odd
|
||||
alignment, because no object of size 1 can have a fundamental
|
||||
alignment greater than 1.
|
||||
|
||||
* The s390-linux-gnu (31bit) configuration is no longer supported.
|
||||
* The s390-linux-gnu (31bit) configuration is no longer supported.
|
||||
|
||||
* The --enable-memory-tagging configure option has been removed.
|
||||
The corresponding AArch64-specific functionality that was previously
|
||||
@@ -110,6 +57,10 @@ Deprecated and removed features, and other changes affecting compatibility:
|
||||
remaining behavior was to suppress the link-time warnings on the NSS
|
||||
interface functions in libc.a, which are now emitted unconditionally.
|
||||
|
||||
Changes to build and runtime requirements:
|
||||
|
||||
[Add changes to build and runtime requirements here]
|
||||
|
||||
Security related changes:
|
||||
|
||||
The following CVEs were fixed in this release, details of which can be
|
||||
@@ -129,114 +80,8 @@ found in the advisories directory of the release tarball:
|
||||
|
||||
The following bugs were resolved with this release:
|
||||
|
||||
[2363] libc: EOPNOTSUPP and ENOTSUP in errno.h must be different,
|
||||
according to SUSv3
|
||||
[3794] manual: iconv: //TRANSLIT and //IGNORE feature not documented
|
||||
[15792] dynamic-link: [arm] ARM dynamic linker should save/restore
|
||||
coprocessor registers
|
||||
[20331] libc: fts ignores errors from readdir()
|
||||
[20680] dynamic-link: ifunc resolver cannot access the thread pointer
|
||||
with static linking
|
||||
[22944] libc: fts cannot traverse paths which have a length longer
|
||||
than USHRT_MAX
|
||||
[25257] libc: sotruss: fix error message for '--f' argument
|
||||
[25770] locale: newlocale memory leak in LOCPATH parsing and on error
|
||||
paths
|
||||
[27582] libc: x86_64: IFUNC in static user programs may crash when
|
||||
built with -fstack-protector-all
|
||||
[28218] dynamic-link: ld.so: ifunc resolver calls a lazy PLT. When
|
||||
does it work?
|
||||
[28817] libc: static-pie ifunc resolver tls failure
|
||||
[28940] nss: __nss_database_get doesn't check for allocation failure
|
||||
[30136] manual: Please document behaviour of iconv(3) when input is
|
||||
untranslatable
|
||||
[30304] nptl: nptl/tst-pthread-gdb-attach test fails with new libc
|
||||
shared library version
|
||||
[30769] malloc: malloc_trim is not working correctly for arenas other
|
||||
than arena 0
|
||||
[30976] dynamic-link: rtld: resolve ifunc relocations after
|
||||
JUMP_SLOT/GLOB_DAT/etc
|
||||
[30992] libc: alpha: setrlimit() with negative values besides
|
||||
RLIM_INFINITY returns EPERM
|
||||
[31901] libc: elf/tst-glibc-hwcaps-prepend-cache fails on i686
|
||||
[33226] math: math-vector-fortran.h vs not ffast-math
|
||||
[33626] libc: execvpe should skip inaccessible $PATH components
|
||||
[33650] build: abilist.awk doesn't handle unversioned defined symbols
|
||||
[33785] stdio: New streams are linked into global list before they are
|
||||
fully initialized
|
||||
[33848] build: Build fails at openat2.h, redefinition of 'struct
|
||||
open_how'
|
||||
[33882] libc: Recursion in nftw() causes stack overflow(CWE-674)
|
||||
[33904] build: error: '__vasprintf_chk' undeclared here
|
||||
[33921] build: Building with Linux-7.0-rc1 errors on OPEN_TREE_CLONE
|
||||
[33935] stdio: _IO_wfile_doallocate not linked correctly when linking
|
||||
glibc statically
|
||||
[33980] locale: iconv: ibm139x trigger assertion error when converting
|
||||
to internal while lack enough room (CVE-2026-4046)
|
||||
[33985] build: ld: cannot find -lgcc_s: No such file or directory
|
||||
[33999] stdio: libio: potential dangling _IO_save_base or memory leak
|
||||
in wgenops.c
|
||||
[34006] stdio: libio: inconsistent fmemopen_write behavior on last \0
|
||||
[34008] stdio: stdio-common: scanf %mc pattern will cause heap
|
||||
overflow when width > 1024
|
||||
[34014] nss: gethostbyaddr and gethostbyaddr_r may incorrectly handle
|
||||
DNS response
|
||||
[34015] nss: gethostbyaddr and gethostbyaddr_r return invalid DNS
|
||||
hostnames
|
||||
[34019] stdio: libio: undefined behavior when setbuf on open_memstream
|
||||
[34033] network: resolv/ns_print.c: ns_sprintrrf TSIG path bypasses
|
||||
buflen and can overflow caller buffer
|
||||
[34064] dynamic-link: The unnecessary PT_NOTE check in when loading a
|
||||
binary
|
||||
[34069] network: Buffer overread in ns_sprintrrf with corrupted RDATA
|
||||
field (CVE-2026-6238)
|
||||
[34070] hurd: Calling open ("/dev/tty/", O_RDONLY) causes the program
|
||||
to segfault
|
||||
[34073] regex: regexec can mistakenly match with backrefs and the $
|
||||
anchor
|
||||
[34079] dynamic-link: THP segment load aligns all PT_LOAD segments to
|
||||
THP page size
|
||||
[34080] dynamic-link: Support THP segment load with THP enabled with
|
||||
madvise
|
||||
[34083] dynamic-link: __get_thp_mode and __get_thp_size are called
|
||||
twice
|
||||
[34090] libc: wordexp WRDE_APPEND rollback restores stale we_wordv,
|
||||
leading to invalid free in wordfree
|
||||
[34098] libc: Missing SUPPORT_STATIC_PIE in arm32
|
||||
[34129] string: x86: Non-temporal memset unreachable on AMD Zen 3/4/5
|
||||
[34144] libc: ld.so clobbers VFP registers during runtime linking
|
||||
[34154] network: Segfault in sock_eq after res_init() returns -1, due
|
||||
to stale _u._ext.nscount in __res_iclose
|
||||
[34156] dynamic-link: dlsym(RTLD_DEFAULT, ...) from a constructor
|
||||
SIGSEGVs when tail-called
|
||||
[34164] dynamic-link: elf: IFUNC resolvers do not see static TLS
|
||||
initialization
|
||||
[34170] dynamic-link: elf: IFUNC resolver reading global-
|
||||
dynamic/TLSDESC __thread variable crashes inside __tls_get_addr
|
||||
[34183] math: fma produces wrong results
|
||||
[34192] nptl: pthread_setname_np opens /proc/<tid>/comm with O_RDWR
|
||||
instead of O_WRONLY|O_CLOEXEC
|
||||
[34196] libc: elf: static dlopen: pointer guard of the loaded
|
||||
ld.so/libc.so is left uninitialized
|
||||
[34197] dynamic-link: elf: Stack canary and pointer guard are
|
||||
recoverable from AT_RANDOM (getauxval)
|
||||
[34205] libc: aarch64: SIGSEGV in tunable_strcmp in static-pie
|
||||
binaries run with a string tunable
|
||||
[34208] stdio: scanf not pushback after matching failure
|
||||
[34210] libc: elf/tst-glibc-hwcaps-prepend-cache fails on
|
||||
armv7a-unknown-linux-gnueabihf
|
||||
[34236] locale: Non-representable transliteration still causes iconv
|
||||
to exit with 1 if //TRANSLIT is specified
|
||||
[34289] network: ns_sprintrrf uses p_class, p_type internally
|
||||
[34311] build: THP tests failed to link
|
||||
[34347] libc: Incorrect trailing bitfield word of struct tcp_info
|
||||
[34348] dynamic-link: FAIL: elf/tst-thp-1 if THP is disabled in kernel
|
||||
[34351] build: Random test failures
|
||||
[34355] build: [2.44 Regression] "make check -j7 subdirs=stdio-common"
|
||||
no longer works
|
||||
[34396] libc: sparc64-unknown-linux-gnu , Gentoo: >200 test failures,
|
||||
SIGILL in many binaries
|
||||
[34398] string: Truncated strncpy on s390x z900 ifunc variant
|
||||
[The release manager will add the list generated by
|
||||
scripts/list-fixed-bugs.py just before the release.]
|
||||
|
||||
Version 2.43
|
||||
|
||||
|
||||
@@ -80,24 +80,15 @@ common-generated += dummy.o dummy.c
|
||||
|
||||
ifneq "$(headers)" ""
|
||||
# Test that all of the headers installed by this directory can be compiled
|
||||
# in isolation. Each header gets its own intermediate target so that the
|
||||
# it can run concurrently under -j; the .out target concatenates the per-header
|
||||
# results in the original $(headers) order.
|
||||
# in isolation.
|
||||
tests-special += $(objpfx)check-installed-headers-c.out
|
||||
libof-check-installed-headers-c := testsuite
|
||||
+cih-c-iouts := $(patsubst %,$(objpfx)check-installed-headers-c/%.iout,\
|
||||
$(headers))
|
||||
$(+cih-c-iouts): $(objpfx)check-installed-headers-c/%.iout: \
|
||||
$(objpfx)check-installed-headers-c.out: \
|
||||
$(..)scripts/check-installed-headers.sh $(headers)
|
||||
$(make-target-directory)
|
||||
($(SHELL) $(..)scripts/check-installed-headers.sh c $(supported-fortify) \
|
||||
"$(CC) $(test-config-cflags-finput-charset-ascii) \
|
||||
$(filter-out -std=%,$(CFLAGS)) -D_ISOMAC $(+includes)" \
|
||||
$*; echo $$? > $@-ret) > $@T; \
|
||||
mv -f $@T $@
|
||||
$(objpfx)check-installed-headers-c.out: $(+cih-c-iouts)
|
||||
cat $^ > $@; \
|
||||
! grep -qv '^0$$' $(+cih-c-iouts:%=%-ret); \
|
||||
$(SHELL) $(..)scripts/check-installed-headers.sh c $(supported-fortify) \
|
||||
"$(CC) $(test-config-cflags-finput-charset-ascii) \
|
||||
$(filter-out -std=%,$(CFLAGS)) -D_ISOMAC $(+includes)" \
|
||||
$(headers) > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
ifneq "$(CXX)" ""
|
||||
@@ -105,19 +96,12 @@ ifneq "$(CXX)" ""
|
||||
# in isolation as C++.
|
||||
tests-special += $(objpfx)check-installed-headers-cxx.out
|
||||
libof-check-installed-headers-cxx := testsuite
|
||||
+cih-cxx-iouts := $(patsubst %,$(objpfx)check-installed-headers-cxx/%.iout,\
|
||||
$(headers))
|
||||
$(+cih-cxx-iouts): $(objpfx)check-installed-headers-cxx/%.iout: \
|
||||
$(objpfx)check-installed-headers-cxx.out: \
|
||||
$(..)scripts/check-installed-headers.sh $(headers)
|
||||
$(make-target-directory)
|
||||
($(SHELL) $(..)scripts/check-installed-headers.sh c++ $(supported-fortify) \
|
||||
"$(CXX) $(test-config-cxxflags-finput-charset-ascii) \
|
||||
$(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
|
||||
$*; echo $$? > $@-ret) > $@T; \
|
||||
mv -f $@T $@
|
||||
$(objpfx)check-installed-headers-cxx.out: $(+cih-cxx-iouts)
|
||||
cat $^ > $@; \
|
||||
! grep -qv '^0$$' $(+cih-cxx-iouts:%=%-ret); \
|
||||
$(SHELL) $(..)scripts/check-installed-headers.sh c++ $(supported-fortify) \
|
||||
"$(CXX) $(test-config-cxxflags-finput-charset-ascii) \
|
||||
$(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
|
||||
$(headers) > $@; \
|
||||
$(evaluate-test)
|
||||
endif # $(CXX)
|
||||
|
||||
@@ -429,7 +413,7 @@ $(objpfx)%.out: /dev/null $(objpfx)% # Make it 2nd arg for canned sequence.
|
||||
# and pid namespaces) in which to run, should be added to
|
||||
# tests-container.
|
||||
$(tests-container:%=$(objpfx)%.out): $(objpfx)%.out : $(if $(wildcard $(objpfx)%.files),$(objpfx)%.files,/dev/null) $(objpfx)%
|
||||
$(test-wrapper-env) $(run-program-env) $(test-container-via-rtld-prefix) \
|
||||
$(test-wrapper-env) $(run-program-env) $(test-via-rtld-prefix) \
|
||||
$(common-objpfx)support/test-container env $(run-program-env) $($*-ENV) $(test-tunables) \
|
||||
$(host-test-program-cmd) $($*-ARGS) > $@; \
|
||||
$(evaluate-test)
|
||||
@@ -467,9 +451,8 @@ py-env := PYTHONPATH=$(py-const-dir):$(..)scripts:$${PYTHONPATH}
|
||||
# The pretty printer files and test_common_printers.py must be present for all.
|
||||
$(tests-printers-out): $(objpfx)%.out: $(objpfx)% %.py %.c $(pretty-printers) \
|
||||
$(..)scripts/test_printers_common.py
|
||||
$(test-wrapper-env) $(py-env) sh -c \
|
||||
'command -v $(firstword $(PYTHON)) > /dev/null 2>&1 || exit 77; \
|
||||
exec $(PYTHON) $*.py $*.c $(objpfx)$* $(pretty-printers)' > $@; \
|
||||
$(test-wrapper-env) $(py-env) \
|
||||
$(PYTHON) $*.py $*.c $(objpfx)$* $(pretty-printers) > $@; \
|
||||
$(evaluate-test)
|
||||
endif
|
||||
|
||||
|
||||
+1
-2
@@ -113,7 +113,6 @@ gnulib:
|
||||
stdlib/setenv.c
|
||||
stdlib/strtoll.c
|
||||
stdlib/strtoul.c
|
||||
# Merged from gnulib 2026-08-27, (gnulib commit ec224ee81b)
|
||||
stdlib/tst-stdc_rotate_left.c
|
||||
stdlib/tst-stdc_rotate_right.c
|
||||
# Merged from gnulib 2014-6-26, needs merge back
|
||||
@@ -281,7 +280,7 @@ core-math:
|
||||
sysdeps/ieee754/dbl-64/s_erf.c
|
||||
# src/binary64/erfc/erfc.c, revision 55e9869e
|
||||
sysdeps/ieee754/dbl-64/s_erfc.c
|
||||
# src/binary64/tanh/tanh.c, revision bb39e4fa
|
||||
# src/binary64/tanh/tanh.c, revision 8ea8ea35
|
||||
sysdeps/ieee754/dbl-64/s_tanh.c
|
||||
# src/binary32/acos/acosf.c, revision 56dd347
|
||||
sysdeps/ieee754/flt-32/e_acosf.c
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
wordexp with WRDE_APPEND may result in an invalid call to free()
|
||||
|
||||
Calling wordexp with WRDE_APPEND in conjunction with an invalid expansion
|
||||
(where an error like WRDE_BADCHAR would be returned) can create a stale
|
||||
address in the wordexp_t that can cause an invalid free from wordfree.
|
||||
This affects the GNU C Library version 2.0 to version 2.43.
|
||||
|
||||
In WRDE_APPEND mode, wordexp saves the caller-visible wordexp_t state
|
||||
before appending the processing input. If the word expansion grows
|
||||
we_wordv via realloc, and realloc requires moving we_wordv to a new memory
|
||||
location (instead of expanding in-place), and the expansion later fails,
|
||||
the rollback fails to properly restore all previous we_wordv values and
|
||||
may add stale pointers into the caller-visible state. A subsequent
|
||||
wordfree may then issue an invalid call to free().
|
||||
|
||||
CVE-Id: CVE-2026-6368
|
||||
Public-Date: 2026-07-14
|
||||
Vulnerable-Commit: 8f2ece695d8822e9ecc63ecd157e90bf17a6fe65 (1.93-260)
|
||||
Reported-by: shinobu
|
||||
@@ -1,18 +0,0 @@
|
||||
Buffer overflow in fopen mode argument processing
|
||||
|
||||
Passing an effectively empty string to the `,ccs=` syntax extension of
|
||||
the mode argument in the `fopen` function in the GNU C Library version
|
||||
2.45 or earlier may result in a heap buffer overflow when the mode
|
||||
string input to the function is attacker controlled.
|
||||
|
||||
This usage pattern is not seen in applications in common GNU or Linux
|
||||
distributions and applications that process user-supplied values for
|
||||
`ccs` should not pass them through without validation.
|
||||
|
||||
CVE-Id: CVE-2026-18374
|
||||
Public-Date: 2026-08-27
|
||||
Vulnerable-Commit: 129d706d77587e4d6627cc1ebef9be0f7cbc65f0
|
||||
Fix-Commit: 9765a538ebf8661a6e5578e01e35a3dd30db7eb4 (2.45)
|
||||
Fix-Commit: cca93e5d88d3d4ed073c03100467696f652269e7 (2.45)
|
||||
Reported-by: AISLE in partnership with Red Hat
|
||||
CVSS: CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L - 4.9
|
||||
+1
-4
@@ -45,9 +45,6 @@ Reported-By:
|
||||
The entity that reported this issue. There could be multiple entries, one for
|
||||
each reporter.
|
||||
|
||||
CVSS:
|
||||
CVSS score for the issue.
|
||||
|
||||
Adding an Advisory
|
||||
------------------
|
||||
|
||||
@@ -60,7 +57,7 @@ An advisory for a CVE needs to be added on the master branch in two steps:
|
||||
backports. Ask for the GLIBC-SA advisory number from the security
|
||||
team.
|
||||
|
||||
2. Finish all backports on release branches and then back on the master
|
||||
2. Finish all backports on release branches and then back on the msater
|
||||
branch, add all commit refs to the advisory using the Fix-Commit
|
||||
tags. Don't bother adding the release-version subscript since the
|
||||
next step will overwrite it.
|
||||
|
||||
@@ -33,11 +33,6 @@ routines := \
|
||||
assert-perr \
|
||||
# routines
|
||||
|
||||
# Called during static library initialization, so turn stack-protection
|
||||
# off for non-shared builds.
|
||||
CFLAGS-__libc_assert_fail.o = $(no-stack-protector)
|
||||
CFLAGS-__libc_assert_fail.op = $(no-stack-protector)
|
||||
|
||||
tests := \
|
||||
test-assert \
|
||||
test-assert-2 \
|
||||
|
||||
+3
-25
@@ -409,9 +409,9 @@ $(addprefix $(objpfx)bench-,calloc-thread): $(libm-benchtests)
|
||||
# Rules to build and execute the benchmarks. Do not put any benchmark
|
||||
# parameters beyond this point.
|
||||
|
||||
# Benchmark programs must not run concurrently, however building them is
|
||||
# safe in parallel. So '.NOTPARALLEL:' is used only when benchmarks run
|
||||
# or when more than one group is going to run.
|
||||
# We don't want the benchmark programs to run in parallel since that could
|
||||
# affect their performance.
|
||||
.NOTPARALLEL:
|
||||
|
||||
bench-extra-objs = json-lib.o
|
||||
|
||||
@@ -622,30 +622,8 @@ $(bench-link-targets): %: %.o $(objpfx)json-lib.o \
|
||||
$(bench-link-targets): LDFLAGS += $(link-bench-bind-now)
|
||||
|
||||
$(objpfx)bench-%.c: %-inputs $(bench-deps)
|
||||
$(make-target-directory)
|
||||
{ if [ -n "$($*-INCLUDE)" ]; then \
|
||||
cat $($*-INCLUDE); \
|
||||
fi; \
|
||||
$(PYTHON) scripts/bench.py $(patsubst %-inputs,%,$<); } > $@-tmp
|
||||
mv -f $@-tmp $@
|
||||
|
||||
# Serialize the benchmark runs so their timing is not perturbed by a
|
||||
# concurrent workload, while still building every benchmark program in parallel.
|
||||
# Ordering is only needed when more than one benchmark group run: the combined
|
||||
# 'bench' goal runs all three groups, and the bench* goals can also be combined
|
||||
# on a single command line. A lone group needs no ordering -- make builds its
|
||||
# programs in parallel and then runs its single recipe, which cannot overlap a
|
||||
# compile.
|
||||
ifneq (,$(filter bench,$(MAKECMDGOALS)))
|
||||
bench-run-active := bench-set bench-func bench-malloc
|
||||
else
|
||||
bench-run-active := $(filter bench-set bench-func bench-malloc,$(MAKECMDGOALS))
|
||||
endif
|
||||
|
||||
ifneq (,$(word 2,$(bench-run-active)))
|
||||
# Hold every active run until all benchmark programs have been built.
|
||||
$(bench-run-active): | bench-build
|
||||
# And then run the active groups strictly one at a time.
|
||||
bench-func: | $(filter bench-set,$(bench-run-active))
|
||||
bench-malloc: | $(filter bench-set bench-func,$(bench-run-active))
|
||||
endif
|
||||
|
||||
@@ -48,7 +48,7 @@ do_one_test (json_ctx_t *json_ctx, impl_t *impl, const CHAR *s,
|
||||
const CHAR *rej, RES_TYPE exp_res)
|
||||
{
|
||||
RES_TYPE res = CALL (impl, s, rej);
|
||||
size_t i, iters = CHARBYTES > 1 ? INNER_LOOP_ITERS : INNER_LOOP_ITERS_LARGE;
|
||||
size_t i, iters = INNER_LOOP_ITERS8 / CHARBYTES;
|
||||
timing_t start, stop, cur;
|
||||
|
||||
if (res != exp_res)
|
||||
|
||||
@@ -41,8 +41,7 @@ static void
|
||||
do_one_test (json_ctx_t *json_ctx, impl_t *impl, const CHAR *s,
|
||||
const CHAR *acc, size_t exp_res)
|
||||
{
|
||||
size_t res = CALL (impl, s, acc), i;
|
||||
size_t iters = CHARBYTES > 1 ? INNER_LOOP_ITERS : INNER_LOOP_ITERS_LARGE;
|
||||
size_t res = CALL (impl, s, acc), i, iters = INNER_LOOP_ITERS8 / CHARBYTES;
|
||||
timing_t start, stop, cur;
|
||||
|
||||
if (res != exp_res)
|
||||
|
||||
+2405
-3006
File diff suppressed because it is too large
Load Diff
+4911
-3006
File diff suppressed because it is too large
Load Diff
+3446
-2004
File diff suppressed because it is too large
Load Diff
+3
-11
@@ -60,14 +60,6 @@ vpath %.c ../locale/programs
|
||||
|
||||
include ../Rules
|
||||
|
||||
# The catalog-generation tests below run gencat under specific locales,
|
||||
# and tst-catgets reads the resulting catalog, so the build must wait for
|
||||
# those locales to be generated. Without this dependency a parallel build
|
||||
# races catgets against localedata and gencat can run before the locale
|
||||
# exists (it then falls back to C and the test fails).
|
||||
LOCALES := de_DE.ISO-8859-1 hr_HR.ISO-8859-2 ja_JP.SJIS
|
||||
include ../gen-locales.mk
|
||||
|
||||
$(objpfx)gencat: $(gencat-modules:%=$(objpfx)%.o)
|
||||
|
||||
catgets-CPPFLAGS := -DNLSPATH='"$(localedir)/%L/%N:$(localedir)/%L/LC_MESSAGES/%N:$(localedir)/%l/%N:$(localedir)/%l/LC_MESSAGES/%N:"'
|
||||
@@ -103,7 +95,7 @@ tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de \
|
||||
ifeq ($(run-built-tests),yes)
|
||||
# This test just checks whether the program produces any error or not.
|
||||
# The result is not tested.
|
||||
$(objpfx)test1.cat: test1.msg $(objpfx)gencat $(gen-locales)
|
||||
$(objpfx)test1.cat: test1.msg $(objpfx)gencat
|
||||
$(built-program-cmd-before-env) \
|
||||
$(run-program-env) LC_ALL=hr_HR.ISO-8859-2 \
|
||||
$(built-program-cmd-after-env) -H $(objpfx)test1.h $@ $<; \
|
||||
@@ -111,7 +103,7 @@ $(objpfx)test1.cat: test1.msg $(objpfx)gencat $(gen-locales)
|
||||
$(objpfx)test2.cat: test2.msg $(objpfx)gencat
|
||||
$(built-program-cmd) -H $(objpfx)test2.h $@ $<; \
|
||||
$(evaluate-test)
|
||||
$(objpfx)de/libc.cat: $(objpfx)de.msg $(objpfx)gencat $(gen-locales)
|
||||
$(objpfx)de/libc.cat: $(objpfx)de.msg $(objpfx)gencat
|
||||
$(make-target-directory)
|
||||
$(built-program-cmd-before-env) \
|
||||
$(run-program-env) LC_ALL=de_DE.ISO-8859-1 \
|
||||
@@ -124,7 +116,7 @@ $(objpfx)de.msg: xopen-msg.awk $(..)po/de.po
|
||||
LC_ALL=C $(AWK) -f $^ $< > $@
|
||||
|
||||
$(objpfx)test-gencat.out: test-gencat.sh $(objpfx)test-gencat \
|
||||
$(objpfx)sample.SJIS.cat $(gen-locales)
|
||||
$(objpfx)sample.SJIS.cat
|
||||
$(SHELL) $< $(common-objpfx) '$(test-program-cmd-before-env)' \
|
||||
'$(run-program-env)' '$(test-program-cmd-after-env)'; \
|
||||
$(evaluate-test)
|
||||
|
||||
+1
-5
@@ -264,14 +264,10 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||||
_dl_aux_init (auxvec);
|
||||
# endif
|
||||
|
||||
__tunables_init (__environ, argv);
|
||||
__tunables_init (__environ);
|
||||
|
||||
ARCH_INIT_CPU_FEATURES ();
|
||||
|
||||
/* Every string tunable has been consumed by ARCH_INIT_CPU_FEATURES, before
|
||||
any code outside of libc startup runs. */
|
||||
__tunable_seal_strings ();
|
||||
|
||||
/* Do static-pie self relocation for the non-IRELATIVE part after tunables
|
||||
and cpu features are set up. IFUNC entries are deferred until after the
|
||||
TCB and the stack-protector canary are usable, so that an instrumented
|
||||
|
||||
+12
-24
@@ -36,15 +36,10 @@
|
||||
trampoline, read, 3 * fn, and do_test. */
|
||||
#define NUM_FUNCTIONS 7
|
||||
|
||||
/* Avoid the read wrapper frame truncation on targets that add extra frames
|
||||
between it and handle_signal (the cancellable syscall wrappers
|
||||
__syscall_cancel*, or the i686 __kernel_vsyscall entry). */
|
||||
#define MAX_FUNCTIONS 64
|
||||
|
||||
void
|
||||
handle_signal (int signum)
|
||||
{
|
||||
void *addresses[MAX_FUNCTIONS];
|
||||
void *addresses[NUM_FUNCTIONS];
|
||||
char **symbols;
|
||||
int n;
|
||||
int i;
|
||||
@@ -75,30 +70,23 @@ handle_signal (int signum)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip the signal trampoline and any cancellable syscall wrapper frames
|
||||
(__syscall_cancel*) and require the read syscall wrapper to be
|
||||
present (but skip intermediates). */
|
||||
for (i = 1; i < n; i++)
|
||||
if (match (symbols[i], "read")
|
||||
&& !match (symbols[i], "read_nocancel")
|
||||
&& !match (symbols[i], "io_read"))
|
||||
/* Do not check name for signal trampoline or cancellable syscall
|
||||
wrappers (__syscall_cancel*). */
|
||||
for (; i < n - 1; i++)
|
||||
if (match (symbols[i], "read"))
|
||||
break;
|
||||
if (i == n)
|
||||
if (i == n - 1)
|
||||
{
|
||||
FAIL ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* The read wrapper must be followed by the three fn recursion frames. */
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
i++;
|
||||
if (i == n || !match (symbols[i], "fn"))
|
||||
{
|
||||
FAIL ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (; i < n - 1; i++)
|
||||
if (!match (symbols[i], "fn"))
|
||||
{
|
||||
FAIL ();
|
||||
return;
|
||||
}
|
||||
/* Symbol names are not available for static functions, so we do not
|
||||
check do_test. */
|
||||
|
||||
|
||||
+2
-7
@@ -145,13 +145,8 @@ enum
|
||||
RTLD_DI_SERINFOSIZE = 5,
|
||||
|
||||
/* Treat ARG as `char *', and store there the directory name used to
|
||||
expand $ORIGIN in this shared object's dependency file names.
|
||||
Deprecated due to potential for buffer overflows. */
|
||||
RTLD_DI_ORIGIN
|
||||
# ifdef __attribute_deprecated_enum__
|
||||
__attribute_deprecated_enum__ ("Use RTLD_DI_ORIGIN_PATH instead")
|
||||
# endif
|
||||
= 6,
|
||||
expand $ORIGIN in this shared object's dependency file names. */
|
||||
RTLD_DI_ORIGIN = 6,
|
||||
|
||||
RTLD_DI_PROFILENAME = 7, /* Unsupported, defined by Solaris. */
|
||||
RTLD_DI_PROFILEOUT = 8, /* Unsupported, defined by Solaris. */
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <libintl.h>
|
||||
#include <dl-tls.h>
|
||||
#include <shlib-compat.h>
|
||||
#include <libc-diag.h>
|
||||
|
||||
struct dlinfo_args
|
||||
{
|
||||
@@ -64,13 +63,9 @@ dlinfo_doit (void *argsblock)
|
||||
_dl_rtld_di_serinfo (l, args->arg, true);
|
||||
break;
|
||||
|
||||
DIAG_PUSH_NEEDS_COMMENT;
|
||||
DIAG_IGNORE_NEEDS_COMMENT (6.1, "-Wdeprecated-declarations");
|
||||
/* Deprecated via compile-time warning due to buffer overflow risk. */
|
||||
case RTLD_DI_ORIGIN:
|
||||
strcpy (args->arg, l->l_origin);
|
||||
break;
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
|
||||
case RTLD_DI_ORIGIN_PATH:
|
||||
if (l->l_origin != (char *) -1)
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <error.h>
|
||||
#include <support/check.h>
|
||||
#include <libc-diag.h>
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
|
||||
@@ -52,15 +51,11 @@ do_test (void)
|
||||
}
|
||||
}
|
||||
|
||||
DIAG_PUSH_NEEDS_COMMENT;
|
||||
/* Ignore deprecation to be able to test deprecated request type. */
|
||||
DIAG_IGNORE_NEEDS_COMMENT (6.1, "-Wdeprecated-declarations");
|
||||
char origin[8192]; /* >= PATH_MAX, in theory */
|
||||
TRY (RTLD_DI_ORIGIN, origin)
|
||||
{
|
||||
printf ("origin: %s\n", origin);
|
||||
}
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
|
||||
const char *origin_path;
|
||||
TRY (RTLD_DI_ORIGIN_PATH, &origin_path)
|
||||
|
||||
+5
-123
@@ -225,7 +225,6 @@ ldconfig-modules := \
|
||||
readlib \
|
||||
static-stubs \
|
||||
stringtable \
|
||||
tunconf \
|
||||
xmalloc \
|
||||
xstrdup \
|
||||
# ldconfig-modules
|
||||
@@ -280,7 +279,6 @@ tests-static-normal := \
|
||||
# tests-static-normal
|
||||
|
||||
tests-static-internal := \
|
||||
tst-assert-startup-static \
|
||||
tst-atrandom-scrub-static \
|
||||
tst-dl-printf-static \
|
||||
tst-dl_find_object-static \
|
||||
@@ -291,10 +289,9 @@ tests-static-internal := \
|
||||
tst-tls1-static-non-pie \
|
||||
tst-tunables \
|
||||
tst-tunables-enable_secure \
|
||||
tst-tunables-seal-static \
|
||||
# tests-static-internal
|
||||
|
||||
ifeq (yesyes,$(have-gcc-ifunc)$(have-ssp))
|
||||
ifeq (yes,$(have-gcc-ifunc))
|
||||
tests-static-internal += \
|
||||
tst-ifunc-resolver-protector-static \
|
||||
tst-ifunc-resolver-protector-static-non-pie \
|
||||
@@ -338,7 +335,6 @@ tests-internal := \
|
||||
$(tests-static-internal) \
|
||||
tst-tls1 \
|
||||
tst-tls_tp_offset \
|
||||
tst-tunconf1 \
|
||||
# tests-internal
|
||||
|
||||
tests-static := $(tests-static-normal) $(tests-static-internal)
|
||||
@@ -349,17 +345,6 @@ tests-static += \
|
||||
tst-tls9-static \
|
||||
# tests-static
|
||||
|
||||
tst-tunconf1-TUNABLES-only = \
|
||||
glibc.malloc.tcache_count=5 \
|
||||
glibc.malloc.perturb=41 \
|
||||
glibc.malloc.mmap_threshold=10002 \
|
||||
glibc.malloc.trim_threshold=10002 \
|
||||
glibc.malloc.arena_max=300
|
||||
tst-tunconf1-ENV = \
|
||||
MALLOC_MMAP_MAX_=200 \
|
||||
MALLOC_TOP_PAD_=200 \
|
||||
MALLOC_ARENA_MAX=400
|
||||
|
||||
static-dlopen-environment = \
|
||||
LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx)dlfcn
|
||||
tst-tls9-static-ENV = $(static-dlopen-environment)
|
||||
@@ -568,7 +553,6 @@ tests-internal += \
|
||||
tst-audit19a \
|
||||
tst-create_format1 \
|
||||
tst-dl-hwcaps_split \
|
||||
tst-dl-path-normalize \
|
||||
tst-dl_find_object \
|
||||
tst-dl_find_object-threads \
|
||||
tst-dlmopen2 \
|
||||
@@ -582,7 +566,6 @@ tests-internal += \
|
||||
tst-tls6 \
|
||||
tst-tls7 \
|
||||
tst-tls8 \
|
||||
tst-tunables-seal \
|
||||
unload \
|
||||
unload2 \
|
||||
# tests-internal
|
||||
@@ -594,17 +577,13 @@ endif
|
||||
tests-container += \
|
||||
tst-dlopen-self-container \
|
||||
tst-dlopen-tlsmodid-container \
|
||||
tst-ldconfig-cache \
|
||||
tst-origin-secure \
|
||||
tst-pldd \
|
||||
tst-preload-pthread-libc \
|
||||
tst-ptrguard-static-dlopen \
|
||||
tst-rootdir \
|
||||
tst-tunconf1 \
|
||||
# tests-container
|
||||
|
||||
test-srcs = \
|
||||
tst-origin-secure-victim \
|
||||
tst-pathopt \
|
||||
tst-sprof-basic \
|
||||
# tests-srcs
|
||||
@@ -733,7 +712,6 @@ tests-special += $(tests-execstack-special-$(have-z-execstack))
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += \
|
||||
$(objpfx)tst-ldconfig-X.out \
|
||||
$(objpfx)tst-ldconfig-install.out \
|
||||
$(objpfx)tst-ldconfig-p.out \
|
||||
$(objpfx)tst-ldconfig-soname.out \
|
||||
$(objpfx)tst-rtld-help.out \
|
||||
@@ -756,9 +734,6 @@ one-hundred = $(foreach x,0 1 2 3 4 5 6 7 8 9, \
|
||||
0$x 1$x 2$x 3$x 4$x 5$x 6$x 7$x 8$x 9$x)
|
||||
tst-tls-many-dynamic-modules := \
|
||||
$(foreach n,$(one-hundred),tst-tls-manydynamic$(n)mod)
|
||||
tst-ldconfig-cache-modules := \
|
||||
$(foreach n,01 02 03 04 05,tst-tls-manydynamic$(n)mod)
|
||||
$(objpfx)tst-ldconfig-cache.out: $(tst-ldconfig-cache-modules:%=$(objpfx)%.so)
|
||||
tst-tls-many-dynamic-modules-dep-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 \
|
||||
14 15 16 17 18 19
|
||||
tst-tls-many-dynamic-modules-dep = \
|
||||
@@ -783,7 +758,7 @@ test-extras += \
|
||||
tst-tlsmod18a \
|
||||
# test-extras
|
||||
|
||||
ifeq (yesyes,$(have-gcc-ifunc)$(have-ssp))
|
||||
ifeq (yes,$(have-gcc-ifunc))
|
||||
# The resolver helper needs <tls.h> for the TCB-canary STACK_CHK_GUARD
|
||||
# macro, so it must be compiled with MODULE_NAME=testsuite_internal.
|
||||
extra-test-objs += \
|
||||
@@ -845,7 +820,6 @@ modules-names += \
|
||||
libtracemod3-1 \
|
||||
libtracemod4-1 \
|
||||
libtracemod5-1 \
|
||||
libtst-origin-secure-mod \
|
||||
ltglobmod1 \
|
||||
ltglobmod2 \
|
||||
neededobj1 \
|
||||
@@ -1041,7 +1015,6 @@ modules-names += \
|
||||
tst-nodeps2-mod \
|
||||
tst-non-directory-mod \
|
||||
tst-null-argv-lib \
|
||||
tst-origin-secure-evilmod \
|
||||
tst-p_alignmod-base \
|
||||
tst-p_alignmod3 \
|
||||
tst-ptrguard-static-dlopen-mod \
|
||||
@@ -1270,17 +1243,6 @@ LDFLAGS-tst-pie-address-static += \
|
||||
$(load-address-ldflag)=$(pde-load-address)
|
||||
endif
|
||||
endif
|
||||
ifeq (yes,$(enable-static-pie))
|
||||
tests-static += \
|
||||
tst-pie-rpath-static \
|
||||
# tests-static
|
||||
tests-container += \
|
||||
tst-pie-rpath-static \
|
||||
# tests-container
|
||||
modules-names += \
|
||||
tst-pie-rpath-mod \
|
||||
# modules-names
|
||||
endif
|
||||
ifeq (yes,$(have-protected-data))
|
||||
tests += vismain
|
||||
tests-pie += vismain
|
||||
@@ -1337,6 +1299,7 @@ tests += \
|
||||
tst-ifunc-plt-bindnow \
|
||||
tst-ifunc-plt-dlopen \
|
||||
tst-ifunc-plt-dlopen-bindnow \
|
||||
tst-ifunc-resolver-protector \
|
||||
tst-ifunc-tls-init \
|
||||
tst-ifunc-tls-init-gd-ld \
|
||||
tst-ifunc-tls-write \
|
||||
@@ -1405,6 +1368,7 @@ modules-names += \
|
||||
ifuncmod6 \
|
||||
tst-ifunc-plt-dep \
|
||||
tst-ifunc-plt-lib \
|
||||
tst-ifunc-resolver-protector-mod \
|
||||
tst-ifunc-tls-init-gd-global-lib \
|
||||
tst-ifunc-tls-init-gd-lib \
|
||||
tst-ifunc-tls-init-ld-lib \
|
||||
@@ -1413,13 +1377,6 @@ modules-names += \
|
||||
tst-ifunc-tls-write-lib \
|
||||
tst-tls-tdata-reloc-lib \
|
||||
# modules-names
|
||||
ifeq (yes,$(have-gcc-ifunc))
|
||||
tests += \
|
||||
tst-ifunc-fault-dep-bindnow \
|
||||
tst-ifunc-fault-dep-lazy \
|
||||
# tests
|
||||
modules-names += tst-ifunc-fault-mod
|
||||
endif
|
||||
ifneq (no,$(have-test-mtls-descriptor))
|
||||
tests += tst-ifunc-tls-init-tlsdesc
|
||||
modules-names += tst-ifunc-tls-init-tlsdesc-lib
|
||||
@@ -1429,10 +1386,6 @@ endif
|
||||
ifeq (no,$(with-lld))
|
||||
modules-names += ifuncmod5
|
||||
endif
|
||||
ifeq ($(have-ssp),yes)
|
||||
tests += tst-ifunc-resolver-protector
|
||||
modules-names += tst-ifunc-resolver-protector-mod
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -1453,7 +1406,6 @@ tests-special += \
|
||||
$(objpfx)check-execstack.out \
|
||||
$(objpfx)check-initfini.out \
|
||||
$(objpfx)check-localplt.out \
|
||||
$(objpfx)check-symbol-version.out \
|
||||
$(objpfx)check-textrel.out \
|
||||
$(objpfx)check-wx-segment.out \
|
||||
# tests-special
|
||||
@@ -1489,7 +1441,6 @@ ifndef avoid-generated
|
||||
# Makefile fragment to be included.
|
||||
define include_dsosort_tests
|
||||
$(objpfx)$(1).generated-makefile: $(1)
|
||||
$$(make-target-directory)
|
||||
$(PYTHON) $(..)scripts/dso-ordering-test.py \
|
||||
--description-file $$< --objpfx $(objpfx) --output-makefile $$@T
|
||||
mv $$@T $$@
|
||||
@@ -1498,7 +1449,6 @@ endef
|
||||
# Likewise, where the .def file itself is generated.
|
||||
define include_dsosort_tests_objpfx
|
||||
$(objpfx)$(1).generated-makefile: $(objpfx)$(1)
|
||||
$$(make-target-directory)
|
||||
$(PYTHON) $(..)scripts/dso-ordering-test.py \
|
||||
--description-file $$< --objpfx $(objpfx) --output-makefile $$@T
|
||||
mv $$@T $$@
|
||||
@@ -1517,15 +1467,12 @@ $(eval $(call include_dsosort_tests,dso-sort-tests-1.def))
|
||||
$(eval $(call include_dsosort_tests,dso-sort-tests-2.def))
|
||||
|
||||
$(objpfx)dso-sort-tests-all2.def: dso-sort-tests-all.py
|
||||
$(make-target-directory)
|
||||
$(PYTHON) $< 2 > $@
|
||||
|
||||
$(objpfx)dso-sort-tests-all3.def: dso-sort-tests-all.py
|
||||
$(make-target-directory)
|
||||
$(PYTHON) $< 3 > $@
|
||||
|
||||
$(objpfx)dso-sort-tests-all4.def: dso-sort-tests-all.py
|
||||
$(make-target-directory)
|
||||
$(PYTHON) $< 4 > $@
|
||||
|
||||
$(eval $(call include_dsosort_tests_objpfx,dso-sort-tests-all2.def))
|
||||
@@ -1603,9 +1550,7 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os)
|
||||
# when compiled for libc.
|
||||
rtld-stubbed-symbols = \
|
||||
__libc_assert_fail \
|
||||
__libc_single_threaded_internal \
|
||||
__syscall_cancel_arch \
|
||||
__syscall_do_cancel \
|
||||
__syscall_cancel \
|
||||
calloc \
|
||||
free \
|
||||
malloc \
|
||||
@@ -1622,7 +1567,6 @@ endif
|
||||
# These symbols might be emitted by the compiler when fortify is enabled
|
||||
# (through builtins).
|
||||
rtld-stubbed-symbols += \
|
||||
__GI___chk_fail \
|
||||
__GI___vfprintf_chk \
|
||||
__GI___vsprintf_chk \
|
||||
__GI___vsyslog_chk \
|
||||
@@ -2400,12 +2344,6 @@ $(objpfx)check-initfini.out: $(..)scripts/check-initfini.awk \
|
||||
$(evaluate-test)
|
||||
generated += check-initfini.out
|
||||
|
||||
$(objpfx)check-symbol-version.out: $(..)scripts/check-symbol-version.awk \
|
||||
$(all-built-dso:=.dynsym)
|
||||
LC_ALL=C $(AWK) -f $^ > $@; \
|
||||
$(evaluate-test)
|
||||
generated += check-symbol-version.out
|
||||
|
||||
$(objpfx)tst-dlopenrpath: $(objpfx)tst-dlopenrpathmod.so
|
||||
CFLAGS-tst-dlopenrpath.c += -DPFX=\"$(objpfx)\"
|
||||
LDFLAGS-tst-dlopenrpathmod.so += -Wl,-rpath,\$$ORIGIN/test-subdir
|
||||
@@ -2583,27 +2521,6 @@ $(objpfx)tst-ifunc-fault-bindnow.out: $(objpfx)tst-ifunc-fault-bindnow \
|
||||
$(objpfx)ld.so
|
||||
$(tst-ifunc-fault-script)
|
||||
|
||||
LDFLAGS-tst-ifunc-fault-dep-lazy = -Wl,-z,lazy
|
||||
LDFLAGS-tst-ifunc-fault-dep-bindnow = -Wl,-z,now
|
||||
define tst-ifunc-fault-dep-script
|
||||
( $(test-wrapper) $(rtld-prefix) --verify $< \
|
||||
&& $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 $(rtld-prefix) $< \
|
||||
&& $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 LD_DEBUG=unused \
|
||||
$(rtld-prefix) $< \
|
||||
&& $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 LD_WARN=yes LD_BIND_NOW=1 \
|
||||
$(rtld-prefix) $< \
|
||||
) > $@; $(evaluate-test)
|
||||
endef
|
||||
$(objpfx)tst-ifunc-fault-dep-lazy: $(objpfx)tst-ifunc-fault-mod.so
|
||||
$(objpfx)tst-ifunc-fault-dep-bindnow: $(objpfx)tst-ifunc-fault-mod.so
|
||||
$(objpfx)tst-ifunc-fault-dep-lazy.out: $(objpfx)tst-ifunc-fault-dep-lazy \
|
||||
$(objpfx)tst-ifunc-fault-mod.so $(objpfx)ld.so
|
||||
$(tst-ifunc-fault-dep-script)
|
||||
$(objpfx)tst-ifunc-fault-dep-bindnow.out: \
|
||||
$(objpfx)tst-ifunc-fault-dep-bindnow \
|
||||
$(objpfx)tst-ifunc-fault-mod.so $(objpfx)ld.so
|
||||
$(tst-ifunc-fault-dep-script)
|
||||
|
||||
LDFLAGS-tst-ifunc-plt-lib.so = -Wl,-z,lazy
|
||||
|
||||
tst-ifunc-plt-bindnow-ENV = LD_BIND_NOW=1
|
||||
@@ -2907,11 +2824,6 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig
|
||||
'$(run-program-env)' > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-ldconfig-install.out : tst-ldconfig-install.sh $(objpfx)ldconfig
|
||||
$(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' \
|
||||
'$(run-program-env)' > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-ldconfig-p.out : tst-ldconfig-p.sh $(objpfx)ldconfig
|
||||
$(SHELL) $< '$(common-objpfx)' '$(sysconfdir)' '$(test-wrapper-env)' \
|
||||
'$(run-program-env)' > $@; \
|
||||
@@ -3203,9 +3115,6 @@ $(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps
|
||||
tst-tunables-ARGS = -- $(host-test-program-cmd)
|
||||
tst-tunables-enable_secure-ARGS = -- $(host-test-program-cmd)
|
||||
|
||||
CFLAGS-tst-tunables-seal-static.c += $(CFLAGS-tst-tunables-seal.c)
|
||||
tst-tunables-seal-static-TUNABLES += $(tst-tunables-seal-TUNABLES)
|
||||
|
||||
$(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so
|
||||
$(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \
|
||||
'$(run_program_env)' > $(objpfx)/tst-rtld-list-tunables.out
|
||||
@@ -3796,30 +3705,3 @@ $(objpfx)tst-dl-debug-exclude.out: tst-dl-debug-exclude.sh \
|
||||
$(objpfx)tst-recursive-tls > $@; \
|
||||
$(evaluate-test)
|
||||
endif
|
||||
|
||||
CFLAGS-tst-assert-startup-static.c += $(no-stack-protector)
|
||||
LDFLAGS-tst-assert-startup-static += -Wl,-z,muldefs
|
||||
|
||||
$(objpfx)tst-assert-startup-static.out: $(objpfx)tst-assert-startup-static
|
||||
$(test-program-cmd-before-env) \
|
||||
$(run-program-env) \
|
||||
$< > $@ 2>&1; echo "status: $$?" >> $@; \
|
||||
grep -q 'Fatal glibc error: tst-assert-startup-static' $@ \
|
||||
&& grep -q '^status: 134$$' $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
LDFLAGS-tst-pie-rpath-static += -Wl,-rpath,\$$ORIGIN/tst-pie-rpath-static-subdir
|
||||
$(objpfx)tst-pie-rpath-static.out: $(objpfx)tst-pie-rpath-mod.so
|
||||
|
||||
LDFLAGS-libtst-origin-secure-mod.so += -Wl,-soname,libtst-origin-secure-mod.so
|
||||
LDFLAGS-tst-origin-secure-evilmod.so += -Wl,-soname,libtst-origin-secure-mod.so
|
||||
$(objpfx)tst-origin-secure-victim: $(objpfx)libtst-origin-secure-mod.so
|
||||
# The number of "../" here must match the layout invariants described in
|
||||
# tst-origin-secure.c.
|
||||
LDFLAGS-tst-origin-secure-victim += \
|
||||
-Wl,--no-as-needed \
|
||||
-Wl,-rpath,\$$ORIGIN/sub/../../../../..$(slibdir)/tst-origin-secure \
|
||||
-Wl,--disable-new-dtags
|
||||
$(objpfx)tst-origin-secure.out: $(objpfx)tst-origin-secure-victim \
|
||||
$(objpfx)libtst-origin-secure-mod.so \
|
||||
$(objpfx)tst-origin-secure-evilmod.so
|
||||
|
||||
+2
-106
@@ -36,7 +36,6 @@
|
||||
#include <dl-cache.h>
|
||||
#include <version.h>
|
||||
#include <stringtable.h>
|
||||
#include <tunconf.h>
|
||||
|
||||
/* Used to store library names, paths, and other strings. */
|
||||
static struct stringtable strings;
|
||||
@@ -276,8 +275,7 @@ check_new_cache (struct cache_file_new *cache)
|
||||
|
||||
/* Print the extension information in *EXT. */
|
||||
static void
|
||||
print_extensions (struct cache_extension_all_loaded *ext,
|
||||
const char *cache_data)
|
||||
print_extensions (struct cache_extension_all_loaded *ext)
|
||||
{
|
||||
if (ext->sections[cache_extension_tag_generator].base != NULL)
|
||||
{
|
||||
@@ -286,65 +284,6 @@ print_extensions (struct cache_extension_all_loaded *ext,
|
||||
ext->sections[cache_extension_tag_generator].size, stdout);
|
||||
putchar ('\n');
|
||||
}
|
||||
if (ext->sections[cache_extension_tag_tunables].base != NULL)
|
||||
{
|
||||
struct tunable_header_cached *thc;
|
||||
struct tunable_entry_cached *tec;
|
||||
int i, count;
|
||||
|
||||
thc = (struct tunable_header_cached *)
|
||||
ext->sections[cache_extension_tag_tunables].base;
|
||||
tec = thc->tunables;
|
||||
count = thc->num_tunables;
|
||||
printf("tunables sig 0x%08x ver 0x%08x count %u\n",
|
||||
thc->signature, thc->version, thc->num_tunables);
|
||||
/* Check that COUNT won't overflow our data block. */
|
||||
assert (ext->sections[cache_extension_tag_tunables].base
|
||||
+ ext->sections[cache_extension_tag_tunables].size
|
||||
== (void *) & tec[count]);
|
||||
for (i = 0; i < count; ++ i)
|
||||
{
|
||||
printf (" [%d] %s = %s [flags 0x%08x (",
|
||||
i,
|
||||
cache_data + tec[i].name_offset,
|
||||
cache_data + tec[i].value_offset,
|
||||
tec[i].flags);
|
||||
if (tec[i].flags & TUNCONF_FLAG_PARSED)
|
||||
printf ("parsed,");
|
||||
if (tec[i].flags & TUNCONF_FLAG_NEGATIVE)
|
||||
printf ("negative,");
|
||||
if ((tec[i].flags & TUNCONF_FLAG_OVERRIDABLE)
|
||||
== TUNCONF_OVERRIDE_ALLOW)
|
||||
printf ("overridable");
|
||||
else
|
||||
printf ("nonoverridable");
|
||||
switch (tec[i].flags & (TUNCONF_EXCLUDE_SECURE
|
||||
| TUNCONF_EXCLUDE_UNSECURE))
|
||||
{
|
||||
case TUNCONF_EXCLUDE_SECURE:
|
||||
printf(",nonsecure");
|
||||
break;
|
||||
case TUNCONF_EXCLUDE_UNSECURE:
|
||||
printf(",onlysecure");
|
||||
break;
|
||||
case TUNCONF_EXCLUDE_SECURE | TUNCONF_EXCLUDE_UNSECURE:
|
||||
printf(",ignore");
|
||||
break;
|
||||
case 0:
|
||||
printf(",anysecure");
|
||||
break;
|
||||
}
|
||||
switch (tec[i].flags & TUNCONF_FLAG_FILTER)
|
||||
{
|
||||
case TUNCONF_FILTER_PERPROC:
|
||||
printf(",[proc]");
|
||||
break;
|
||||
}
|
||||
if (tec[i].flag_offset != 0)
|
||||
printf (",'%s'", cache_data + tec[i].flag_offset);
|
||||
printf (")]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the whole cache file, if a file contains the new cache format
|
||||
@@ -455,7 +394,7 @@ print_cache (const char *cache_name)
|
||||
cache_new->libs[i].hwcap, hwcaps_string,
|
||||
cache_data + cache_new->libs[i].value);
|
||||
}
|
||||
print_extensions (&ext, cache_data);
|
||||
print_extensions (&ext);
|
||||
}
|
||||
/* Cleanup. */
|
||||
munmap (cache, cache_size);
|
||||
@@ -527,18 +466,6 @@ write_extensions (int fd, uint32_t str_offset,
|
||||
if (p->used)
|
||||
hwcaps_array[p->section_index] = str_offset + p->name->offset;
|
||||
|
||||
struct tunable_header_cached *tunable_data;
|
||||
size_t tunable_size;
|
||||
size_t tunable_aligner = 0;
|
||||
|
||||
tunable_data = get_tunconf_ext (str_offset);
|
||||
|
||||
if (tunable_data == NULL)
|
||||
{
|
||||
/* There is no section for tunables data. */
|
||||
hwcaps_offset -= sizeof (struct cache_extension_section);
|
||||
}
|
||||
|
||||
/* This is the offset of the generator string. */
|
||||
uint32_t generator_offset = hwcaps_offset;
|
||||
if (hwcaps_count == 0)
|
||||
@@ -571,23 +498,6 @@ write_extensions (int fd, uint32_t str_offset,
|
||||
ext->sections[xid].size = hwcaps_size;
|
||||
}
|
||||
|
||||
if (tunable_data != NULL)
|
||||
{
|
||||
uint32_t tunable_offset_ua;
|
||||
uint32_t tunable_offset;
|
||||
|
||||
tunable_size = TUNCONF_SIZE (tunable_data);
|
||||
tunable_offset_ua = generator_offset + strlen (generator);
|
||||
tunable_offset = ALIGN_UP (tunable_offset_ua, 8);
|
||||
tunable_aligner = tunable_offset - tunable_offset_ua;
|
||||
|
||||
++xid;
|
||||
ext->sections[xid].tag = cache_extension_tag_tunables;
|
||||
ext->sections[xid].flags = 0;
|
||||
ext->sections[xid].offset = tunable_offset;
|
||||
ext->sections[xid].size = tunable_size;
|
||||
}
|
||||
|
||||
++xid;
|
||||
ext->count = xid;
|
||||
assert (xid <= cache_extension_count);
|
||||
@@ -599,14 +509,6 @@ write_extensions (int fd, uint32_t str_offset,
|
||||
|| write (fd, generator, strlen (generator)) != strlen (generator))
|
||||
error (EXIT_FAILURE, errno, _("Writing of cache extension data failed"));
|
||||
|
||||
if (tunable_data)
|
||||
{
|
||||
if (write (fd, " ", tunable_aligner) != tunable_aligner
|
||||
|| write (fd, tunable_data, tunable_size) != tunable_size)
|
||||
error (EXIT_FAILURE, errno, _("Writing of cache tunable data failed"));
|
||||
free (tunable_data);
|
||||
}
|
||||
|
||||
free (hwcaps_array);
|
||||
free (ext);
|
||||
}
|
||||
@@ -1204,9 +1106,3 @@ out_fail:
|
||||
free (temp_name);
|
||||
free (file_entries);
|
||||
}
|
||||
|
||||
struct stringtable_entry *
|
||||
cache_store_string (const char *string)
|
||||
{
|
||||
return stringtable_add (&strings, string);
|
||||
}
|
||||
|
||||
+90
-243
@@ -17,7 +17,6 @@
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <intprops.h>
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -27,24 +26,11 @@
|
||||
#include <_itoa.h>
|
||||
#include <dl-hwcaps.h>
|
||||
#include <dl-isa-level.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include "tunconf.h"
|
||||
|
||||
/* This is the starting address and the size of the mmap()ed file. */
|
||||
static struct cache_file *cache;
|
||||
static struct cache_file_new *cache_new;
|
||||
static size_t cachesize;
|
||||
#ifdef SHARED
|
||||
static struct cache_extension_all_loaded ext;
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
typeof ((*(struct __stat64_t64 *)0).st_mtime) mtime;
|
||||
typeof ((*(struct __stat64_t64 *)0).st_ino) ino;
|
||||
typeof ((*(struct __stat64_t64 *)0).st_size) size;
|
||||
typeof ((*(struct __stat64_t64 *)0).st_dev) dev;
|
||||
} cache_file_time, new_cache_file_time;
|
||||
|
||||
#ifdef SHARED
|
||||
/* This is used to cache the priorities of glibc-hwcaps
|
||||
@@ -67,7 +53,6 @@ glibc_hwcaps_priorities_free (void)
|
||||
free (glibc_hwcaps_priorities);
|
||||
glibc_hwcaps_priorities = NULL;
|
||||
glibc_hwcaps_priorities_allocated = 0;
|
||||
glibc_hwcaps_priorities_length = 0;
|
||||
}
|
||||
|
||||
/* Ordered comparison of a hwcaps string from the cache on the left
|
||||
@@ -99,6 +84,10 @@ glibc_hwcaps_compare (uint32_t left_index, struct dl_hwcaps_priority *right)
|
||||
static void
|
||||
glibc_hwcaps_priorities_init (void)
|
||||
{
|
||||
struct cache_extension_all_loaded ext;
|
||||
if (!cache_extension_load (cache_new, cache, cachesize, &ext))
|
||||
return;
|
||||
|
||||
uint32_t length = (ext.sections[cache_extension_tag_glibc_hwcaps].size
|
||||
/ sizeof (uint32_t));
|
||||
if (length > glibc_hwcaps_priorities_allocated)
|
||||
@@ -385,170 +374,6 @@ _dl_cache_libcmp (const char *p1, const char *p2)
|
||||
return *p1 - *p2;
|
||||
}
|
||||
|
||||
/* Set the cache back to the "no cache" state, which may include
|
||||
cleaning up a loaded cache. */
|
||||
static void
|
||||
_dl_maybe_unload_ldsocache (void)
|
||||
{
|
||||
if (cache != NULL)
|
||||
__munmap (cache, cachesize);
|
||||
|
||||
cache = NULL;
|
||||
cache_new = NULL;
|
||||
cachesize = 0;
|
||||
|
||||
#ifdef SHARED
|
||||
glibc_hwcaps_priorities_free ();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns TRUE if for any reason the cache needs to be reloaded
|
||||
(including, the first time, loaded). */
|
||||
static bool
|
||||
_dl_check_ldsocache_needs_loading (void)
|
||||
{
|
||||
int rv;
|
||||
static bool copy_old_time = 0;
|
||||
struct __stat64_t64 new_cache_file_stat;
|
||||
|
||||
/* Save the previous stat every time. We only care when this
|
||||
changes, and we only stat it here, so we can get away with doing
|
||||
the copy now instead of at every single return statement in this
|
||||
function. However, we only need to copy it if the previous stat
|
||||
succeeded. The only way this could be subverted is if the admin
|
||||
moves the file aside, then moves it back, but CACHE would be set
|
||||
to NULL in the interim so that would be detected. */
|
||||
if (copy_old_time)
|
||||
cache_file_time = new_cache_file_time;
|
||||
rv = __fstatat64_time64 (AT_FDCWD, LD_SO_CACHE, &new_cache_file_stat, 0);
|
||||
copy_old_time = (rv >= 0);
|
||||
|
||||
/* No file to load, but there used to be. Assume user intentionally
|
||||
deleted the cache and act accordingly. */
|
||||
if (rv < 0 && cache != NULL)
|
||||
{
|
||||
_dl_maybe_unload_ldsocache ();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No file to load and no loaded cache, so nothing to do. */
|
||||
if (rv < 0)
|
||||
return false;
|
||||
|
||||
/* Store the fields we check, in order they're likely to differ. We
|
||||
must do this even for the first load (CACHE == NULL below), so that
|
||||
the next call copies an accurate NEW_CACHE_FILE_TIME into
|
||||
CACHE_FILE_TIME and does not spuriously reload the unchanged cache. */
|
||||
new_cache_file_time.mtime = new_cache_file_stat.st_mtime;
|
||||
new_cache_file_time.ino = new_cache_file_stat.st_ino;
|
||||
new_cache_file_time.size = new_cache_file_stat.st_size;
|
||||
new_cache_file_time.dev = new_cache_file_stat.st_dev;
|
||||
|
||||
/* Any file is better than no file (likely the first time
|
||||
through). */
|
||||
if (cache == NULL)
|
||||
return true;
|
||||
|
||||
/* At this point, NEW_CACHE_FILE_TIME is valid as well as
|
||||
CACHE_FILE_TIME, so we compare them. */
|
||||
return (memcmp (&new_cache_file_time, &cache_file_time,
|
||||
sizeof(new_cache_file_time)));
|
||||
}
|
||||
|
||||
/* Attempts to load and validate the cache. On return, CACHE is either
|
||||
unchanged (still loaded or still not loaded) or valid. */
|
||||
static void
|
||||
_dl_maybe_load_ldsocache (void)
|
||||
{
|
||||
struct cache_file *tmp_cache = NULL;
|
||||
struct cache_file_new *tmp_cache_new = NULL;
|
||||
size_t tmp_cachesize = 0;
|
||||
|
||||
/* Read the contents of the file. */
|
||||
void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &tmp_cachesize,
|
||||
PROT_READ);
|
||||
|
||||
/* We can handle three different cache file formats here:
|
||||
- only the new format
|
||||
- the old libc5/glibc2.0/2.1 format
|
||||
- the old format with the new format in it
|
||||
The following checks if the cache contains any of these formats. */
|
||||
if (file != MAP_FAILED && tmp_cachesize > sizeof *cache_new
|
||||
&& memcmp (file, CACHEMAGIC_VERSION_NEW,
|
||||
sizeof CACHEMAGIC_VERSION_NEW - 1) == 0
|
||||
/* Check for corruption, avoiding overflow. */
|
||||
&& ((tmp_cachesize - sizeof *cache_new) / sizeof (struct file_entry_new)
|
||||
>= ((struct cache_file_new *) file)->nlibs))
|
||||
{
|
||||
if (! cache_file_new_matches_endian (file))
|
||||
{
|
||||
__munmap (file, tmp_cachesize);
|
||||
return;
|
||||
}
|
||||
|
||||
tmp_cache_new = file;
|
||||
tmp_cache = file;
|
||||
}
|
||||
else if (file != MAP_FAILED && tmp_cachesize > sizeof *cache
|
||||
&& memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0
|
||||
/* Check for corruption, avoiding overflow. */
|
||||
&& ((tmp_cachesize - sizeof *cache) / sizeof (struct file_entry)
|
||||
>= ((struct cache_file *) file)->nlibs))
|
||||
{
|
||||
size_t offset;
|
||||
/* Looks ok. */
|
||||
tmp_cache = file;
|
||||
|
||||
/* Check for new version. */
|
||||
offset = ALIGN_CACHE (sizeof (struct cache_file)
|
||||
+ tmp_cache->nlibs * sizeof (struct file_entry));
|
||||
|
||||
tmp_cache_new = (struct cache_file_new *) ((void *) tmp_cache + offset);
|
||||
if (tmp_cachesize < (offset + sizeof (struct cache_file_new))
|
||||
|| memcmp (tmp_cache_new->magic, CACHEMAGIC_VERSION_NEW,
|
||||
sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
|
||||
tmp_cache_new = NULL;
|
||||
else
|
||||
{
|
||||
if (! cache_file_new_matches_endian (tmp_cache_new))
|
||||
/* The old-format part of the cache is bogus as well
|
||||
if the endianness does not match. (But it is
|
||||
unclear how the new header can be located if the
|
||||
endianness does not match.) */
|
||||
{
|
||||
__munmap (file, tmp_cachesize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file != MAP_FAILED)
|
||||
__munmap (file, tmp_cachesize);
|
||||
return;
|
||||
}
|
||||
|
||||
struct cache_extension_all_loaded tmp_ext;
|
||||
if (!cache_extension_load (tmp_cache_new, tmp_cache, tmp_cachesize, &tmp_ext))
|
||||
{
|
||||
/* The extension is corrupt, so the cache is corrupt. */
|
||||
__munmap (file, tmp_cachesize);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we've gotten here, the loaded cache is good and we need to
|
||||
save it. */
|
||||
_dl_maybe_unload_ldsocache ();
|
||||
cache = tmp_cache;
|
||||
cache_new = tmp_cache_new;
|
||||
cachesize = tmp_cachesize;
|
||||
#ifdef SHARED
|
||||
ext = tmp_ext;
|
||||
#endif
|
||||
|
||||
assert (cache != NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Look up NAME in ld.so.cache and return the file name stored there, or null
|
||||
if none is found. The cache is loaded if it was not already. If loading
|
||||
@@ -564,14 +389,81 @@ _dl_load_cache_lookup (const char *name)
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
|
||||
_dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
|
||||
|
||||
if (_dl_check_ldsocache_needs_loading ())
|
||||
_dl_maybe_load_ldsocache ();
|
||||
|
||||
if (cache == NULL)
|
||||
{
|
||||
/* Read the contents of the file. */
|
||||
void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
|
||||
PROT_READ);
|
||||
|
||||
/* We can handle three different cache file formats here:
|
||||
- only the new format
|
||||
- the old libc5/glibc2.0/2.1 format
|
||||
- the old format with the new format in it
|
||||
The following checks if the cache contains any of these formats. */
|
||||
if (file != MAP_FAILED && cachesize > sizeof *cache_new
|
||||
&& memcmp (file, CACHEMAGIC_VERSION_NEW,
|
||||
sizeof CACHEMAGIC_VERSION_NEW - 1) == 0
|
||||
/* Check for corruption, avoiding overflow. */
|
||||
&& ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new)
|
||||
>= ((struct cache_file_new *) file)->nlibs))
|
||||
{
|
||||
if (! cache_file_new_matches_endian (file))
|
||||
{
|
||||
__munmap (file, cachesize);
|
||||
file = (void *) -1;
|
||||
}
|
||||
cache_new = file;
|
||||
cache = file;
|
||||
}
|
||||
else if (file != MAP_FAILED && cachesize > sizeof *cache
|
||||
&& memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0
|
||||
/* Check for corruption, avoiding overflow. */
|
||||
&& ((cachesize - sizeof *cache) / sizeof (struct file_entry)
|
||||
>= ((struct cache_file *) file)->nlibs))
|
||||
{
|
||||
size_t offset;
|
||||
/* Looks ok. */
|
||||
cache = file;
|
||||
|
||||
/* Check for new version. */
|
||||
offset = ALIGN_CACHE (sizeof (struct cache_file)
|
||||
+ cache->nlibs * sizeof (struct file_entry));
|
||||
|
||||
cache_new = (struct cache_file_new *) ((void *) cache + offset);
|
||||
if (cachesize < (offset + sizeof (struct cache_file_new))
|
||||
|| memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
|
||||
sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
|
||||
cache_new = (void *) -1;
|
||||
else
|
||||
{
|
||||
if (! cache_file_new_matches_endian (cache_new))
|
||||
{
|
||||
/* The old-format part of the cache is bogus as well
|
||||
if the endianness does not match. (But it is
|
||||
unclear how the new header can be located if the
|
||||
endianness does not match.) */
|
||||
cache = (void *) -1;
|
||||
cache_new = (void *) -1;
|
||||
__munmap (file, cachesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file != MAP_FAILED)
|
||||
__munmap (file, cachesize);
|
||||
cache = (void *) -1;
|
||||
}
|
||||
|
||||
assert (cache != NULL);
|
||||
}
|
||||
|
||||
if (cache == (void *) -1)
|
||||
/* Previously looked for the cache file and didn't find it. */
|
||||
return NULL;
|
||||
|
||||
const char *best;
|
||||
if (cache_new != NULL)
|
||||
if (cache_new != (void *) -1)
|
||||
{
|
||||
const char *string_table = (const char *) cache_new;
|
||||
best = search_cache (string_table, cachesize,
|
||||
@@ -610,67 +502,22 @@ _dl_load_cache_lookup (const char *name)
|
||||
return result;
|
||||
}
|
||||
|
||||
const struct tunable_header_cached *
|
||||
_dl_load_cache_tunables (const char **data)
|
||||
#ifndef MAP_COPY
|
||||
/* If the system does not support MAP_COPY we cannot leave the file open
|
||||
all the time since this would create problems when the file is replaced.
|
||||
Therefore we provide this function to close the file and open it again
|
||||
once needed. */
|
||||
void
|
||||
_dl_unload_cache (void)
|
||||
{
|
||||
struct cache_extension_all_loaded ext;
|
||||
struct tunable_header_cached *thc;
|
||||
struct tunable_entry_cached *tec;
|
||||
int i, count;
|
||||
|
||||
if (_dl_check_ldsocache_needs_loading ())
|
||||
_dl_maybe_load_ldsocache ();
|
||||
|
||||
if (cache_new)
|
||||
*data = (const char *) cache_new;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (!cache_extension_load (cache_new, cache, cachesize, &ext))
|
||||
return NULL;
|
||||
|
||||
/* Validate length/contents here. */
|
||||
if (ext.sections[cache_extension_tag_tunables].size
|
||||
< sizeof(struct tunable_header_cached))
|
||||
return NULL;
|
||||
|
||||
thc = (struct tunable_header_cached *)
|
||||
ext.sections[cache_extension_tag_tunables].base;
|
||||
|
||||
/* Reject data produced by a different tunable cache format. */
|
||||
if (thc->signature != TUNCONF_SIGNATURE || thc->version != TUNCONF_VERSION)
|
||||
return NULL;
|
||||
|
||||
tec = thc->tunables;
|
||||
count = thc->num_tunables;
|
||||
|
||||
if (ext.sections[cache_extension_tag_tunables].base
|
||||
+ ext.sections[cache_extension_tag_tunables].size
|
||||
!= (void *) & tec[count])
|
||||
return NULL;
|
||||
|
||||
/* Validate each entry. The string table lies between the file entries
|
||||
and the end of the mapping; clamp its end to CACHESIZE so that a bogus
|
||||
len_strings cannot make an offset point outside the mapped file. */
|
||||
size_t s_start = (const char *) (&cache_new->libs[cache_new->nlibs]) - *data;
|
||||
size_t s_end;
|
||||
if (s_start >= cachesize
|
||||
|| INT_ADD_WRAPV (s_start, cache_new->len_strings, &s_end))
|
||||
return NULL;
|
||||
if (s_end > cachesize)
|
||||
s_end = cachesize;
|
||||
for (i = 0; i < count; i ++)
|
||||
if (cache != NULL && cache != (struct cache_file *) -1)
|
||||
{
|
||||
if (thc->tunables[i].name_offset < s_start
|
||||
|| thc->tunables[i].name_offset >= s_end
|
||||
|| thc->tunables[i].value_offset < s_start
|
||||
|| thc->tunables[i].value_offset >= s_end)
|
||||
return NULL;
|
||||
if (thc->tunables[i].flag_offset != 0
|
||||
&& (thc->tunables[i].flag_offset < s_start
|
||||
|| thc->tunables[i].flag_offset >= s_end))
|
||||
return NULL;
|
||||
__munmap (cache, cachesize);
|
||||
cache = NULL;
|
||||
}
|
||||
|
||||
return thc;
|
||||
#ifdef SHARED
|
||||
/* This marks the glibc_hwcaps_priorities array as out-of-date. */
|
||||
glibc_hwcaps_priorities_length = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
+59
-28
@@ -34,7 +34,6 @@
|
||||
#include <gnu/lib-names.h>
|
||||
#include <dl-tunables.h>
|
||||
#include <dl-scratch-buffer.h>
|
||||
#include <dl-path-normalize.h>
|
||||
|
||||
#include "dynamic-link.h"
|
||||
#include "get-dynamic-info.h"
|
||||
@@ -92,30 +91,67 @@ static const size_t system_dirs_len[] =
|
||||
};
|
||||
#define nsystem_dirs_len array_length (system_dirs_len)
|
||||
|
||||
/* Return true if the normalized path NPATH of length NLEN is rooted in one of
|
||||
the trusted system directories. The system_dirs entries carry a trailing
|
||||
'/'; NPATH matches an entry when it shares the entry's leading component
|
||||
sequence and then either ends or continues with '/'. For instance,
|
||||
"/lib64" and "/lib64/x" match "/lib64/" but "/lib64x" does not. */
|
||||
static bool
|
||||
path_is_trusted (const char *npath, size_t nlen)
|
||||
is_trusted_path_normalize (const char *path, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return false;
|
||||
|
||||
struct dl_scratch_buffer scratch = dl_scratch_buffer_init ();
|
||||
dl_scratch_buffer_allocate (&scratch, len + 2, 0);
|
||||
char *npath = scratch.data;
|
||||
char *wnp = npath;
|
||||
while (*path != '\0')
|
||||
{
|
||||
if (path[0] == '/')
|
||||
{
|
||||
if (path[1] == '.')
|
||||
{
|
||||
if (path[2] == '.' && (path[3] == '/' || path[3] == '\0'))
|
||||
{
|
||||
while (wnp > npath && *--wnp != '/')
|
||||
;
|
||||
path += 3;
|
||||
continue;
|
||||
}
|
||||
else if (path[2] == '/' || path[2] == '\0')
|
||||
{
|
||||
path += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (wnp > npath && wnp[-1] == '/')
|
||||
{
|
||||
++path;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
*wnp++ = *path++;
|
||||
}
|
||||
|
||||
if (wnp == npath || wnp[-1] != '/')
|
||||
*wnp++ = '/';
|
||||
|
||||
bool result = false;
|
||||
const char *trun = system_dirs;
|
||||
|
||||
for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
|
||||
{
|
||||
/* Compare against the entry without its trailing '/'. */
|
||||
size_t dirlen = system_dirs_len[idx] - 1;
|
||||
|
||||
if (nlen >= dirlen
|
||||
&& memcmp (trun, npath, dirlen) == 0
|
||||
&& (npath[dirlen] == '/' || npath[dirlen] == '\0'))
|
||||
return true;
|
||||
if (wnp - npath >= system_dirs_len[idx]
|
||||
&& memcmp (trun, npath, system_dirs_len[idx]) == 0)
|
||||
{
|
||||
/* Found it. */
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
trun += system_dirs_len[idx] + 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
dl_scratch_buffer_free (&scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Given a substring starting at INPUT, just after the DST '$' start
|
||||
@@ -299,21 +335,16 @@ _dl_dst_substitute (struct link_map *l, const char *input, char *result)
|
||||
checked for trust, the authors of the binaries themselves are
|
||||
trusted to have designed this correctly. Only $ORIGIN is tested in
|
||||
this way because it may be manipulated in some ways with hard
|
||||
links.
|
||||
|
||||
_dl_normalize_path replaces the expansion with its normalized form
|
||||
in place, so that the path that is opened is exactly the path that
|
||||
was validated. */
|
||||
links. */
|
||||
if (__glibc_unlikely (check_for_trusted)
|
||||
&& !is_trusted_path_normalize (result, wp - result))
|
||||
{
|
||||
*result = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
*wp = '\0';
|
||||
|
||||
if (__glibc_unlikely (check_for_trusted))
|
||||
{
|
||||
size_t nlen = _dl_normalize_path (result);
|
||||
if (!path_is_trusted (result, nlen))
|
||||
*result = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1288,7 +1319,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
if (l->l_ld != NULL)
|
||||
l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
|
||||
|
||||
elf_get_dynamic_info (l, false);
|
||||
elf_get_dynamic_info (l, false, false);
|
||||
|
||||
/* Make sure we are not dlopen'ing an object that has the
|
||||
DF_1_NOOPEN flag set, or a PIE object. */
|
||||
|
||||
@@ -163,6 +163,14 @@ __libc_fatal (const char *message)
|
||||
}
|
||||
rtld_hidden_def (__libc_fatal)
|
||||
|
||||
void
|
||||
__attribute__ ((noreturn))
|
||||
__chk_fail (void)
|
||||
{
|
||||
_exit (127);
|
||||
}
|
||||
rtld_hidden_def (__chk_fail)
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Define (weakly) our own assert failure function which doesn't use stdio.
|
||||
If we are linked into the user program (-ldl), the normal __assert_fail
|
||||
|
||||
+62
-19
@@ -367,6 +367,53 @@ resize_tls_slotinfo (struct link_map *new)
|
||||
return any_tls;
|
||||
}
|
||||
|
||||
/* Second stage of TLS update, after resize_tls_slotinfo. This
|
||||
function does not raise any exception. It should only be called if
|
||||
resize_tls_slotinfo returned true. */
|
||||
static void
|
||||
update_tls_slotinfo (struct link_map *new)
|
||||
{
|
||||
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
_dl_add_to_slotinfo (new->l_searchlist.r_list[i], true);
|
||||
|
||||
size_t newgen = GL(dl_tls_generation) + 1;
|
||||
if (__glibc_unlikely (newgen == 0))
|
||||
_dl_fatal_printf (N_("\
|
||||
TLS generation counter wrapped! Please report this."));
|
||||
/* Can be read concurrently. */
|
||||
atomic_store_release (&GL(dl_tls_generation), newgen);
|
||||
|
||||
/* We need a second pass for static tls data, because
|
||||
_dl_update_slotinfo must not be run while calls to
|
||||
_dl_add_to_slotinfo are still pending. */
|
||||
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
{
|
||||
struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
|
||||
if (imap->l_need_tls_init && imap->l_tls_blocksize > 0)
|
||||
{
|
||||
/* For static TLS we have to allocate the memory here and
|
||||
now, but we can delay updating the DTV. */
|
||||
imap->l_need_tls_init = 0;
|
||||
#ifdef SHARED
|
||||
/* Update the slot information data for the current
|
||||
generation. */
|
||||
|
||||
/* FIXME: This can terminate the process on memory
|
||||
allocation failure. It is not possible to raise
|
||||
exceptions from this context; to fix this bug,
|
||||
_dl_update_slotinfo would have to be split into two
|
||||
operations, similar to resize_scopes and update_scopes
|
||||
above. This is related to bug 16134. */
|
||||
_dl_update_slotinfo (imap->l_tls_modid, newgen);
|
||||
#endif
|
||||
|
||||
_dl_init_static_tls (imap);
|
||||
assert (imap->l_need_tls_init == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark the objects as NODELETE if required. This is delayed until
|
||||
after dlopen failure is not possible, so that _dl_close can clean
|
||||
up objects if necessary. */
|
||||
@@ -624,26 +671,17 @@ dl_open_worker_begin (void *a)
|
||||
if (mode & RTLD_GLOBAL)
|
||||
add_to_global_resize (new);
|
||||
|
||||
/* Register the new modules in the DTV slotinfo and bump the TLS
|
||||
generation counter *before* relocation, so an IFUNC resolver firing
|
||||
during the relocation loop below can reach its DSO's __thread storage
|
||||
via __tls_get_addr / TLSDESC. Without this, the new module is not yet
|
||||
in GL(dl_tls_dtv_slotinfo_list), so the resolver's dynamic-TLS lookup
|
||||
fails to find it and faults. The static-TLS image itself is copied
|
||||
lazily on first access, and if relocation later fails, the subsequent
|
||||
_dl_close_worker cleans up these slotinfo entries via remove_slotinfo. */
|
||||
/* Install the new modules in the DTV slotinfo and initialise their
|
||||
static TLS *before* relocation, so an IFUNC resolver firing during
|
||||
the relocation loop below can reach its DSO's __thread storage via
|
||||
__tls_get_addr / TLSDESC. Without this, the resolver's TLS access
|
||||
for a just-loaded module would index into an unallocated DTV slot
|
||||
and crash. If relocation later fails, the subsequent _dl_close_worker
|
||||
cleans up these slotinfo entries via remove_slotinfo. */
|
||||
if (any_tls)
|
||||
{
|
||||
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
_dl_add_to_slotinfo (new->l_searchlist.r_list[i], true);
|
||||
|
||||
size_t newgen = GL(dl_tls_generation) + 1;
|
||||
if (__glibc_unlikely (newgen == 0))
|
||||
_dl_fatal_printf (N_("\
|
||||
TLS generation counter wrapped! Please report this."));
|
||||
/* Can be read concurrently. */
|
||||
atomic_store_release (&GL(dl_tls_generation), newgen);
|
||||
}
|
||||
/* FIXME: This calls _dl_update_slotinfo, which aborts the process
|
||||
on memory allocation failure. See bug 16134. */
|
||||
update_tls_slotinfo (new);
|
||||
|
||||
/* Perform relocation. This can trigger lazy binding in IFUNC
|
||||
resolvers. For NODELETE mappings, these dependencies are not
|
||||
@@ -860,6 +898,11 @@ no more namespaces available for dlmopen()"));
|
||||
struct dl_exception exception;
|
||||
int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
|
||||
|
||||
#if defined USE_LDCONFIG && !defined MAP_COPY
|
||||
/* We must unmap the cache file. */
|
||||
_dl_unload_cache ();
|
||||
#endif
|
||||
|
||||
/* Do this for both the error and success cases. The old value has
|
||||
only been determined if the namespace ID was assigned (i.e., it
|
||||
is not __LM_ID_CALLER). In the success case, we actually may
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/* In-place lexical path normalization for the dynamic loader.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _DL_PATH_NORMALIZE_H
|
||||
#define _DL_PATH_NORMALIZE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Lexically normalize the null-terminated PATH in place and return the
|
||||
length of the result (excluding the terminating NUL byte):
|
||||
|
||||
- Runs of '/' are collapsed to a single '/'.
|
||||
|
||||
- "." components are removed.
|
||||
|
||||
- A ".." component removes the preceding component if there is one and it
|
||||
is not itself a preserved "..". In an absolute path a surplus ".." at
|
||||
the root is dropped ("/../a" normalizes to "/a"), in a relative path
|
||||
leading ".." components are preserved ("../a" stays "../a", "a/../../b"
|
||||
normalizes to "../b").
|
||||
|
||||
- The result has no trailing '/' except for the root path "/" itself
|
||||
("/a/" normalizes to "/a").
|
||||
|
||||
- The result is empty if and only if every component cancels or is removed
|
||||
("", ".", "a/.." all normalize to "").
|
||||
|
||||
The PATH is written in place, and the internal write cursor never runs
|
||||
ahead of the read cursor. Only bytes within the strlen (PATH) + 1 storage
|
||||
are accessed. */
|
||||
static inline size_t
|
||||
_dl_normalize_path (char *path)
|
||||
{
|
||||
/* The root '/' of an absolute path is not removed. */
|
||||
char *pstart = path + (path[0] == '/');
|
||||
const char *rnp = pstart;
|
||||
char *wnp = pstart;
|
||||
/* End of the prefix a ".." may not remove. Either the root '/', or, for
|
||||
relative paths, the original start of the string extended by any
|
||||
preserved leading ".." components. */
|
||||
char *limit = pstart;
|
||||
|
||||
while (*rnp != '\0')
|
||||
{
|
||||
/* Collapse consecutive separators. */
|
||||
if (*rnp == '/')
|
||||
{
|
||||
++rnp;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* [RNP, REND) is the next input component. */
|
||||
const char *rend = rnp;
|
||||
while (*rend != '\0' && *rend != '/')
|
||||
++rend;
|
||||
size_t clen = rend - rnp;
|
||||
|
||||
/* Drop '.' component. */
|
||||
if (clen == 1 && rnp[0] == '.')
|
||||
;
|
||||
else if (clen == 2 && rnp[0] == '.' && rnp[1] == '.')
|
||||
{
|
||||
if (wnp > limit)
|
||||
{
|
||||
/* Remove the last component along with the '/' separating it
|
||||
from its predecessor (the root '/' of an absolute path is
|
||||
retained). */
|
||||
while (wnp > limit && wnp[-1] != '/')
|
||||
--wnp;
|
||||
if (wnp > pstart)
|
||||
--wnp;
|
||||
}
|
||||
else if (pstart == path)
|
||||
{
|
||||
/* No component is left and the original path is relative:
|
||||
keep the unresolvable ".." (it becomes part of the
|
||||
preserved prefix). */
|
||||
if (wnp > pstart)
|
||||
*wnp++ = '/';
|
||||
*wnp++ = '.';
|
||||
*wnp++ = '.';
|
||||
limit = wnp;
|
||||
}
|
||||
/* Otherwise the path is absolute and the surplus ".." at the
|
||||
root is dropped ("/../a" normalizes to "/a"). */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wnp > pstart)
|
||||
*wnp++ = '/';
|
||||
memmove (wnp, rnp, clen);
|
||||
wnp += clen;
|
||||
}
|
||||
|
||||
rnp = rend;
|
||||
}
|
||||
|
||||
*wnp = '\0';
|
||||
return wnp - path;
|
||||
}
|
||||
|
||||
#endif /* _DL_PATH_NORMALIZE_H */
|
||||
@@ -72,19 +72,15 @@ _dl_relocate_static_pie (void)
|
||||
/* Read our own dynamic section and fill in the info array. */
|
||||
main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
|
||||
|
||||
elf_get_dynamic_info (main_map, false);
|
||||
elf_get_dynamic_info (main_map, false, true);
|
||||
|
||||
# ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
|
||||
ELF_MACHINE_BEFORE_RTLD_RELOC (main_map, main_map->l_info);
|
||||
# endif
|
||||
|
||||
/* Relocate ourselves so we can do normal function calls and data access
|
||||
using the global offset table. IRELATIVE entries are deferred.
|
||||
Lazy binding is never used here, so edr_lazy comes back as 0 and the
|
||||
deferred pass can hardcode the same value. */
|
||||
int edr_lazy = 0;
|
||||
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, main_map, NULL, edr_lazy,
|
||||
0, 0);
|
||||
using the global offset table. IRELATIVE entries are deferred. */
|
||||
ELF_DYNAMIC_RELOCATE_NOIFUNC (main_map, NULL, 0, 0);
|
||||
|
||||
/* Initialize _r_debug_extended. */
|
||||
struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
|
||||
@@ -102,9 +98,7 @@ void
|
||||
_dl_relocate_static_pie_ifunc (void)
|
||||
{
|
||||
struct link_map *main_map = _dl_get_dl_main_map ();
|
||||
int edr_lazy = 0;
|
||||
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, main_map, NULL, edr_lazy,
|
||||
0, 0);
|
||||
ELF_DYNAMIC_RELOCATE_IFUNC (main_map, NULL, 0, 0);
|
||||
main_map->l_relocated = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
+42
-103
@@ -37,47 +37,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* Return the number of bytes that would be allocated in the static
|
||||
TLS block for MAP. If the available space is insufficient, return a
|
||||
value greater than the available space to indicate failure. OFFSET_OUT
|
||||
is updated with the TLS offset of the map. */
|
||||
static inline size_t
|
||||
__attribute__ ((always_inline))
|
||||
_dl_static_tls_allocation (struct link_map *map, size_t *offset_out)
|
||||
{
|
||||
#if TLS_TCB_AT_TP
|
||||
size_t freebytes = GLRO(dl_tls_static_size) - GL(dl_tls_static_used);
|
||||
if (freebytes < TLS_TCB_SIZE)
|
||||
return TLS_TCB_SIZE + map->l_tls_blocksize;
|
||||
freebytes -= TLS_TCB_SIZE;
|
||||
|
||||
size_t blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
|
||||
if (freebytes < blsize)
|
||||
return TLS_TCB_SIZE + blsize;
|
||||
|
||||
size_t n = (freebytes - blsize) / map->l_tls_align;
|
||||
|
||||
/* Account optional static TLS surplus usage. */
|
||||
size_t use = freebytes - n * map->l_tls_align - map->l_tls_firstbyte_offset;
|
||||
*offset_out = GL(dl_tls_static_used) + use;
|
||||
return use;
|
||||
#elif TLS_DTV_AT_TP
|
||||
/* dl_tls_static_used includes the TCB at the beginning. */
|
||||
size_t offset = (ALIGN_UP(GL(dl_tls_static_used)
|
||||
- map->l_tls_firstbyte_offset,
|
||||
map->l_tls_align)
|
||||
+ map->l_tls_firstbyte_offset);
|
||||
size_t used = offset + map->l_tls_blocksize;
|
||||
|
||||
/* Account optional static TLS surplus usage. */
|
||||
size_t use = used - GL(dl_tls_static_used);
|
||||
*offset_out = offset;
|
||||
return use;
|
||||
#else
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We are trying to perform a static TLS relocation in MAP, but it was
|
||||
dynamically loaded. This can only work if there is enough surplus in
|
||||
the static TLS area already allocated for each running thread. If this
|
||||
@@ -95,30 +54,57 @@ _dl_try_allocate_static_tls (struct link_map *map, bool optional)
|
||||
/* If we've already used the variable with dynamic access, or if the
|
||||
alignment requirements are too high, fail. */
|
||||
if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
|
||||
|| map->l_tls_align > GLRO(dl_tls_static_align))
|
||||
|| map->l_tls_align > GLRO (dl_tls_static_align))
|
||||
{
|
||||
fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
size_t use = _dl_static_tls_allocation (map, &offset);
|
||||
#if TLS_TCB_AT_TP
|
||||
size_t freebytes = GLRO (dl_tls_static_size) - GL(dl_tls_static_used);
|
||||
if (freebytes < TLS_TCB_SIZE)
|
||||
goto fail;
|
||||
freebytes -= TLS_TCB_SIZE;
|
||||
|
||||
if (use > GLRO(dl_tls_static_size) - GL(dl_tls_static_used))
|
||||
size_t blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
|
||||
if (freebytes < blsize)
|
||||
goto fail;
|
||||
|
||||
size_t n = (freebytes - blsize) / map->l_tls_align;
|
||||
|
||||
/* Account optional static TLS surplus usage. */
|
||||
size_t use = freebytes - n * map->l_tls_align - map->l_tls_firstbyte_offset;
|
||||
if (optional && use > GL(dl_tls_static_optional))
|
||||
goto fail;
|
||||
else if (optional)
|
||||
GL(dl_tls_static_optional) -= use;
|
||||
|
||||
size_t offset = GL(dl_tls_static_used) + use;
|
||||
|
||||
map->l_tls_offset = GL(dl_tls_static_used) = offset;
|
||||
#elif TLS_DTV_AT_TP
|
||||
/* dl_tls_static_used includes the TCB at the beginning. */
|
||||
size_t offset = (ALIGN_UP(GL(dl_tls_static_used)
|
||||
- map->l_tls_firstbyte_offset,
|
||||
map->l_tls_align)
|
||||
+ map->l_tls_firstbyte_offset);
|
||||
size_t used = offset + map->l_tls_blocksize;
|
||||
|
||||
if (used > GLRO (dl_tls_static_size))
|
||||
goto fail;
|
||||
|
||||
/* Account optional static TLS surplus usage. */
|
||||
size_t use = used - GL(dl_tls_static_used);
|
||||
if (optional && use > GL(dl_tls_static_optional))
|
||||
goto fail;
|
||||
else if (optional)
|
||||
GL(dl_tls_static_optional) -= use;
|
||||
|
||||
map->l_tls_offset = offset;
|
||||
#if TLS_TCB_AT_TP
|
||||
GL(dl_tls_static_used) = offset;
|
||||
#elif TLS_DTV_AT_TP
|
||||
map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
|
||||
GL(dl_tls_static_used) = offset + map->l_tls_blocksize;
|
||||
GL(dl_tls_static_used) = used;
|
||||
#else
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
#endif
|
||||
|
||||
/* Initialise the static TLS region, the map may not yet be l_relocated (a
|
||||
@@ -145,57 +131,13 @@ _dl_try_allocate_static_tls (struct link_map *map, bool optional)
|
||||
not be inlined as much as possible. */
|
||||
void
|
||||
__attribute_noinline__
|
||||
_dl_allocate_static_tls (struct link_map *map, struct link_map *sym_map,
|
||||
const ElfW(Sym) *sym)
|
||||
_dl_allocate_static_tls (struct link_map *map)
|
||||
{
|
||||
if (sym_map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
|
||||
|| _dl_try_allocate_static_tls (sym_map, false))
|
||||
if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
|
||||
|| _dl_try_allocate_static_tls (map, false))
|
||||
{
|
||||
const char *symname = "unknown";
|
||||
const char *def_map_info = "";
|
||||
const char *def_map_name = "";
|
||||
struct dl_exception exception;
|
||||
|
||||
if (sym != NULL)
|
||||
{
|
||||
const char *strtab
|
||||
= (const char *) D_PTR (sym_map, l_info[DT_STRTAB]);
|
||||
symname = strtab + sym->st_name;
|
||||
if (symname[0] == '\0')
|
||||
symname = "unknown";
|
||||
}
|
||||
|
||||
if (sym_map != map)
|
||||
{
|
||||
def_map_info = " defined in ";
|
||||
def_map_name = DSO_FILENAME (sym_map->l_name);
|
||||
}
|
||||
|
||||
if (sym_map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
|
||||
{
|
||||
/* XXX We cannot translate the message. */
|
||||
_dl_exception_create_format (
|
||||
&exception, DSO_FILENAME (map->l_name),
|
||||
"cannot allocate memory in static TLS block: "
|
||||
"%s%s%s: previously used as global-dynamic",
|
||||
symname, def_map_info, def_map_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t offset = 0;
|
||||
size_t requested = _dl_static_tls_allocation (sym_map, &offset);
|
||||
size_t available
|
||||
= (GLRO(dl_tls_static_size) - GL(dl_tls_static_used));
|
||||
|
||||
/* XXX We cannot translate the message. */
|
||||
_dl_exception_create_format (
|
||||
&exception, DSO_FILENAME (map->l_name),
|
||||
"cannot allocate memory in static TLS block: "
|
||||
"%s%s%s: requested %zx, available %zx",
|
||||
symname, def_map_info, def_map_name, requested, available);
|
||||
}
|
||||
|
||||
_dl_signal_exception (0, &exception, N_("TLS allocation error"));
|
||||
_dl_signal_error (0, map->l_name, NULL, N_("\
|
||||
cannot allocate memory in static TLS block"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,9 +278,7 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
|
||||
IFUNC resolvers. Without this, a resolver would see the unrelocated
|
||||
initialiser bytes that were placed into the slot by the early
|
||||
_dl_allocate_tls_init. */
|
||||
int edr_lazy = lazy;
|
||||
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, l, scope, edr_lazy,
|
||||
consider_profiling, skip_ifunc);
|
||||
ELF_DYNAMIC_RELOCATE_NOIFUNC (l, scope, lazy, consider_profiling);
|
||||
|
||||
#ifdef SHARED
|
||||
/* Re-initialise the static TLS slot with the .tdata so the IRELATIVE
|
||||
@@ -351,8 +291,7 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
|
||||
_dl_init_static_tls (l);
|
||||
#endif
|
||||
|
||||
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, l, scope, edr_lazy,
|
||||
0, skip_ifunc);
|
||||
ELF_DYNAMIC_RELOCATE_IFUNC (l, scope, lazy, skip_ifunc);
|
||||
|
||||
if ((consider_profiling || consider_symbind)
|
||||
&& l->l_info[DT_PLTRELSZ] != NULL)
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
PTR_MANGLE/DEMANGLE, further impairing performance of small, common
|
||||
input cases. A simple if-case with direct function calls appears to
|
||||
be the fastest. */
|
||||
if (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)
|
||||
if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
|
||||
_dl_sort_maps_original (maps, nmaps, force_first, for_fini);
|
||||
else
|
||||
_dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
|
||||
|
||||
+2
-2
@@ -33,10 +33,10 @@
|
||||
&& ((sym_map)->l_tls_offset \
|
||||
!= FORCED_DYNAMIC_TLS_OFFSET), 1))
|
||||
|
||||
#define CHECK_STATIC_TLS(map, sym_map, sym) \
|
||||
#define CHECK_STATIC_TLS(map, sym_map) \
|
||||
do { \
|
||||
if (!HAVE_STATIC_TLS (map, sym_map)) \
|
||||
_dl_allocate_static_tls (map, sym_map, sym); \
|
||||
_dl_allocate_static_tls (sym_map); \
|
||||
} while (0)
|
||||
|
||||
#define TRY_STATIC_TLS(map, sym_map) \
|
||||
|
||||
+6
-3
@@ -697,14 +697,17 @@ _dl_allocate_tls_init (void *result, bool main_thread)
|
||||
For audit modules or dependencies with initial-exec TLS,
|
||||
we can not set the initial TLS image on default loader
|
||||
initialization because it would already be set by the
|
||||
audit setup, which uses the dlopen code. Calls with
|
||||
!main_thread from pthread_create need to initialize TLS
|
||||
for the current thread regardless of namespace. */
|
||||
audit setup, which uses the dlopen code and already
|
||||
clears l_need_tls_init. Calls with !main_thread from
|
||||
pthread_create need to initialize TLS for the current
|
||||
thread regardless of namespace. */
|
||||
if (map->l_ns != LM_ID_BASE && main_thread)
|
||||
continue;
|
||||
memset (__mempcpy (dest, map->l_tls_initimage,
|
||||
map->l_tls_initimage_size), '\0',
|
||||
map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
if (main_thread)
|
||||
map->l_need_tls_init = 0;
|
||||
}
|
||||
|
||||
total += cnt;
|
||||
|
||||
+14
-2
@@ -42,6 +42,20 @@ typedef struct
|
||||
tunable_num_t max;
|
||||
} tunable_type_t;
|
||||
|
||||
/* Security level for tunables. This decides what to do with individual
|
||||
tunables for AT_SECURE binaries. */
|
||||
typedef enum
|
||||
{
|
||||
/* Erase the tunable for AT_SECURE binaries so that child processes don't
|
||||
read it. */
|
||||
TUNABLE_SECLEVEL_SXID_ERASE = 0,
|
||||
/* Ignore the tunable for AT_SECURE binaries, but don't erase it, so that
|
||||
child processes can read it. */
|
||||
TUNABLE_SECLEVEL_SXID_IGNORE = 1,
|
||||
/* Read the tunable. */
|
||||
TUNABLE_SECLEVEL_NONE = 2,
|
||||
} tunable_seclevel_t;
|
||||
|
||||
/* A tunable. */
|
||||
struct _tunable
|
||||
{
|
||||
@@ -51,8 +65,6 @@ struct _tunable
|
||||
tunable_val_t val; /* The value. */
|
||||
bool initialized; /* Flag to indicate that the tunable is
|
||||
initialized. */
|
||||
bool locked; /* If set, modifications are not
|
||||
allowed. */
|
||||
/* Compatibility elements. */
|
||||
const char env_alias[TUNABLE_ALIAS_MAX]; /* The compatibility environment
|
||||
variable name. */
|
||||
|
||||
+3
-215
@@ -37,7 +37,6 @@
|
||||
|
||||
#define TUNABLES_INTERNAL 1
|
||||
#include "dl-tunables.h"
|
||||
#include "tunconf.h"
|
||||
|
||||
static char **
|
||||
get_next_env (char **envp, char **name, char **val, char ***prev_envp)
|
||||
@@ -65,17 +64,6 @@ get_next_env (char **envp, char **name, char **val, char ***prev_envp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set by __tunable_seal_strings once the values of the string tunables are
|
||||
no longer valid. */
|
||||
static bool tunables_strings_sealed attribute_relro;
|
||||
|
||||
static void __attribute__ ((noreturn))
|
||||
tunable_sealed_error (const tunable_t *cur, const char *action)
|
||||
{
|
||||
_dl_fatal_printf ("Fatal glibc error: %s: string tunable %s after "
|
||||
"process initialization\n", cur->name, action);
|
||||
}
|
||||
|
||||
static void
|
||||
do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
|
||||
const tunable_num_t *minp,
|
||||
@@ -83,14 +71,9 @@ do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
|
||||
{
|
||||
tunable_num_t val, min, max;
|
||||
|
||||
if (cur->locked)
|
||||
return;
|
||||
|
||||
switch (cur->type.type_code)
|
||||
{
|
||||
case TUNABLE_TYPE_STRING:
|
||||
if (__glibc_unlikely (tunables_strings_sealed))
|
||||
tunable_sealed_error (cur, "set");
|
||||
cur->val.strval = valp->strval;
|
||||
cur->initialized = true;
|
||||
return;
|
||||
@@ -192,14 +175,6 @@ struct tunable_toset_t
|
||||
|
||||
enum { tunables_list_size = array_length (tunable_list) };
|
||||
|
||||
/* Records tunables that were set from GLIBC_TUNABLES during this call, so
|
||||
that a legacy environment-variable alias does not override them (the
|
||||
canonical GLIBC_TUNABLES form takes precedence over the aliases).
|
||||
A tunable that was set only from the system-wide cache is deliberately not
|
||||
recorded here, so an alias may still override an overridable cache default;
|
||||
a nonoverridable one remains protected by tunable_t::locked. */
|
||||
static bool tunable_set_by_env[tunables_list_size];
|
||||
|
||||
/* Parse the tunable string VALSTRING and set TUNABLES with the found tunables
|
||||
and their respective values. The VALSTRING is parsed in place, with the
|
||||
tunable start and size recorded in TUNABLES.
|
||||
@@ -309,10 +284,6 @@ parse_tunables (const char *valstring)
|
||||
if (!tunable_initialize (tunables[i].t, tunables[i].value,
|
||||
tunables[i].len))
|
||||
parse_tunable_print_error (&tunables[i]);
|
||||
else
|
||||
/* GLIBC_TUNABLES set this tunable; a legacy alias must not
|
||||
override it. */
|
||||
tunable_set_by_env[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +291,7 @@ 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, char **argv)
|
||||
__tunables_init (char **envp)
|
||||
{
|
||||
char *envname = NULL;
|
||||
char *envval = NULL;
|
||||
@@ -331,155 +302,6 @@ __tunables_init (char **envp, char **argv)
|
||||
if (MALLOC_DEFAULT_THP_PAGESIZE > 0)
|
||||
TUNABLE_SET (glibc, malloc, hugetlb, 1);
|
||||
|
||||
#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;
|
||||
#ifdef PATH_MAX
|
||||
char exebuf[PATH_MAX];
|
||||
#else
|
||||
char exebuf[256];
|
||||
#endif
|
||||
const struct tunable_header_cached *thc;
|
||||
const char *td;
|
||||
|
||||
thc = _dl_load_cache_tunables (&td);
|
||||
if (thc != NULL)
|
||||
{
|
||||
for (int t = 0; t < thc->num_tunables; ++ t)
|
||||
{
|
||||
const struct tunable_entry_cached *tec = &( thc->tunables[t] );
|
||||
int tid = tec->tunable_id;
|
||||
const char *name = td + tec->name_offset;
|
||||
const char *value = td + tec->value_offset;
|
||||
|
||||
/* Check that we have the correct tunable, and search by
|
||||
name if needed. We rely on order of operations here to
|
||||
avoid mis-indexing tunables[]. */
|
||||
if (tid < 0 || tid >= tunables_list_size
|
||||
|| strcmp (name, tunable_list[tid].name) != 0)
|
||||
{
|
||||
/* It does not, search by name instead. */
|
||||
tid = -1;
|
||||
for (int i = 0; i < tunables_list_size; i++)
|
||||
{
|
||||
if (strcmp (name, tunable_list[i].name) == 0)
|
||||
{
|
||||
tid = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tid == -1)
|
||||
continue;
|
||||
}
|
||||
/* 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_NONE:
|
||||
break;
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* prog_name and the cached string are both NUL terminated. */
|
||||
if (prog_name)
|
||||
{
|
||||
if (((const char *)(td + tec->flag_offset))[0] == '/')
|
||||
{
|
||||
if (strcmp (prog_name, td + tec->flag_offset) != 0)
|
||||
goto skip_due_to_filter;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp (base_name, td + tec->flag_offset) != 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:
|
||||
/* Unknown filter. */
|
||||
goto skip_due_to_filter;
|
||||
}
|
||||
|
||||
/* If the tunable is set here, any previously set
|
||||
overridability flag is discarded. We need to reset the
|
||||
overridability flag here so we can change the tunable,
|
||||
and may set it later if this tunable also locks it. */
|
||||
tunable_list[tid].locked = false;
|
||||
|
||||
/* 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
|
||||
it, as the mapping will go away if the disk file is
|
||||
updated and the cache is reloaded. */
|
||||
tunable_list[tid].val.strval.str = __strdup (value);
|
||||
tunable_list[tid].val.strval.len = strlen (value);
|
||||
tunable_list[tid].initialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tunable_val_t tval;
|
||||
if (tec->flags & TUNCONF_FLAG_PARSED)
|
||||
{
|
||||
tval.numval = tec->parsed_value;
|
||||
do_tunable_update_val (& tunable_list[tid],
|
||||
&tval, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
tunable_initialize (& tunable_list[tid],
|
||||
value, strlen (value));
|
||||
}
|
||||
}
|
||||
|
||||
/* The overriability flag only applies to tunables
|
||||
which aren't filtered out. */
|
||||
if ((tec->flags & TUNCONF_FLAG_OVERRIDABLE)
|
||||
== TUNCONF_OVERRIDE_DENY)
|
||||
tunable_list[tid].locked = true;
|
||||
|
||||
skip_due_to_filter:;
|
||||
}
|
||||
}
|
||||
#endif /* defined(SHARED) && defined (USE_LDCONFIG) */
|
||||
|
||||
/* Ignore tunables for AT_SECURE programs. */
|
||||
if (__libc_enable_secure)
|
||||
return;
|
||||
@@ -523,13 +345,9 @@ __tunables_init (char **envp, char **argv)
|
||||
|
||||
for (int i = 0; i < tunable_num_env_alias; i++)
|
||||
{
|
||||
/* Skip aliases whose tunable was already set through GLIBC_TUNABLES,
|
||||
which takes precedence over the alias. A value coming only from the
|
||||
system-wide cache does not block the alias here: an overridable cache
|
||||
default may still be overridden, while a nonoverridable one is
|
||||
protected by tunable_t::locked. */
|
||||
/* Skip over tunables that have either been set or already initialized. */
|
||||
if (tunables_env_alias[i].t == NULL
|
||||
|| tunable_set_by_env[tunable_env_alias_list[i]])
|
||||
|| tunables_env_alias[i].t->initialized)
|
||||
continue;
|
||||
|
||||
if (!tunable_initialize (tunables_env_alias[i].t,
|
||||
@@ -642,10 +460,6 @@ __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
|
||||
}
|
||||
case TUNABLE_TYPE_STRING:
|
||||
{
|
||||
/* String tunable values are only valid during early startup; once
|
||||
sealed they must not be read. */
|
||||
if (__glibc_unlikely (tunables_strings_sealed))
|
||||
tunable_sealed_error (cur, "read");
|
||||
*((const struct tunable_str_t **) valp) = &cur->val.strval;
|
||||
break;
|
||||
}
|
||||
@@ -658,29 +472,3 @@ __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
|
||||
}
|
||||
|
||||
rtld_hidden_def (__tunable_get_val)
|
||||
|
||||
/* A string tunable value usually references the GLIBC_TUNABLES (or alias)
|
||||
environment string, which lives in the environment block the kernel places
|
||||
on the initial stack. That memory is owned by the application, which may
|
||||
overwrite it (e.g. setproctitle), so the reference is only safe while no
|
||||
application code has run.
|
||||
A value coming from the system-wide cache is a private copy instead, but
|
||||
it is sealed as well so that the lifetime rule does not depend on where
|
||||
the value came from.
|
||||
Drop the references so that a later access triggers a fatal error. */
|
||||
void
|
||||
__tunable_seal_strings (void)
|
||||
{
|
||||
for (int i = 0; i < tunables_list_size; i++)
|
||||
{
|
||||
tunable_t *cur = &tunable_list[i];
|
||||
|
||||
if (cur->type.type_code != TUNABLE_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
cur->val.strval = (struct tunable_str_t) { NULL, 0 };
|
||||
}
|
||||
|
||||
tunables_strings_sealed = true;
|
||||
}
|
||||
rtld_hidden_def (__tunable_seal_strings)
|
||||
|
||||
+1
-3
@@ -47,21 +47,19 @@ typedef void (*tunable_callback_t) (tunable_val_t *);
|
||||
|
||||
#include "dl-tunable-list.h"
|
||||
|
||||
extern void __tunables_init (char **, char **);
|
||||
extern void __tunables_init (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);
|
||||
extern void __tunable_set_val (tunable_id_t, tunable_val_t *, tunable_num_t *,
|
||||
tunable_num_t *);
|
||||
extern void __tunable_get_default (tunable_id_t id, void *valp);
|
||||
extern void __tunable_seal_strings (void);
|
||||
rtld_hidden_proto (__tunables_init)
|
||||
rtld_hidden_proto (__tunables_print)
|
||||
rtld_hidden_proto (__tunable_is_initialized)
|
||||
rtld_hidden_proto (__tunable_get_val)
|
||||
rtld_hidden_proto (__tunable_set_val)
|
||||
rtld_hidden_proto (__tunable_get_default)
|
||||
rtld_hidden_proto (__tunable_seal_strings)
|
||||
|
||||
/* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and
|
||||
TUNABLE_NAMESPACE are defined. This is useful shorthand to get and set
|
||||
|
||||
@@ -20,35 +20,37 @@
|
||||
#include <ldsodefs.h>
|
||||
#include <libc-lock.h>
|
||||
|
||||
/* This is writev, but with a constraint added and others loosened:
|
||||
/* This is used from only one place: dl-misc.c:_dl_debug_vdprintf.
|
||||
Hence it's in a header with the expectation it will be inlined.
|
||||
|
||||
This is writev, but with a constraint added and others loosened:
|
||||
|
||||
1. Under RTLD_PRIVATE_ERRNO, it must not clobber the private errno
|
||||
when another thread holds the dl_load_lock.
|
||||
2. It's not really obliged to deliver a single atomic write
|
||||
2. It is not obliged to detect and report errors at all.
|
||||
3. It's not really obliged to deliver a single atomic write
|
||||
(though it may be preferable). */
|
||||
|
||||
static inline ssize_t
|
||||
static inline void
|
||||
_dl_writev (int fd, const struct iovec *iov, size_t niov)
|
||||
{
|
||||
/* Note that if __writev is an implementation that calls malloc,
|
||||
this will cause linking problems building the dynamic linker. */
|
||||
|
||||
ssize_t r;
|
||||
#if RTLD_PRIVATE_ERRNO
|
||||
/* We have to take this lock just to be sure we don't clobber the private
|
||||
errno when it's being used by another thread that cares about it.
|
||||
Yet we must be sure not to try calling the lock functions before
|
||||
the thread library is fully initialized. */
|
||||
if (__glibc_unlikely (_dl_starting_up))
|
||||
r = __writev (fd, iov, niov);
|
||||
__writev (fd, iov, niov);
|
||||
else
|
||||
{
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
r = __writev (fd, iov, niov);
|
||||
__writev (fd, iov, niov);
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
}
|
||||
#else
|
||||
r = __writev (fd, iov, niov);
|
||||
__writev (fd, iov, niov);
|
||||
#endif
|
||||
return r == -1 ? -errno : r;
|
||||
}
|
||||
+9
-23
@@ -45,13 +45,7 @@ elf_dynamic_is_Rel_irelative (const ElfW(Rel) *reloc, const ElfW(Sym) *sym)
|
||||
return ((sym != NULL
|
||||
&& ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC
|
||||
&& sym->st_shndx != SHN_UNDEF)
|
||||
|| r_type == ELF_MACHINE_IRELATIVE
|
||||
# ifdef ELF_MACHINE_IRELATIVE_PLT
|
||||
/* Some ports resolve an IFUNC PLT slot for a local resolver with a
|
||||
dedicated reloc that carries no symboli. */
|
||||
|| r_type == ELF_MACHINE_IRELATIVE_PLT
|
||||
# endif
|
||||
);
|
||||
|| r_type == ELF_MACHINE_IRELATIVE);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@@ -79,23 +73,17 @@ elf_dynamic_Rel_audit_symbind (struct link_map *map,
|
||||
/* Perform the relocations in MAP on the running program image as specified
|
||||
by RELTAG, SZTAG. If LAZY is nonzero, this is the first pass on PLT
|
||||
relocations; they should be set up to call _dl_runtime_resolve, rather
|
||||
than fully resolved now. If SKIP_IFUNC is nonzero no IFUNC resolver is
|
||||
called; this is required for the trace modes (ldd -u / ldd -r), which
|
||||
relocate objects.
|
||||
than fully resolved now.
|
||||
|
||||
IRELATIVE entries and relocations against an STT_GNU_IFUNC symbol defined
|
||||
in MAP itself are always skipped (non-bootstrap); they are handled
|
||||
IRELATIVE entries are always skipped (non-bootstrap); they are handled
|
||||
separately by elf_dynamic_do_Rel_irelative after all other relocations
|
||||
for both .rel.dyn and .rel.plt have been processed. Relocations against
|
||||
an IFUNC symbol defined in *another* object are not deferred, since the
|
||||
IFUNC symbol is only known after symbol resolution, and the defining object
|
||||
has already been relocated at this point. */
|
||||
for both .rel.dyn and .rel.plt have been processed. */
|
||||
|
||||
static inline void __attribute__ ((always_inline))
|
||||
elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
ElfW(Addr) reladdr, ElfW(Addr) relsize,
|
||||
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
|
||||
int lazy, int skip_ifunc)
|
||||
int lazy)
|
||||
{
|
||||
const ElfW(Rel) *relative = (const void *) reladdr;
|
||||
const ElfW(Rel) *r = relative + nrelative;
|
||||
@@ -117,7 +105,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
|
||||
const struct r_found_version *rversion = &map->l_versions[ndx];
|
||||
|
||||
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, skip_ifunc);
|
||||
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, 0);
|
||||
}
|
||||
#else /* !RTLD_BOOTSTRAP */
|
||||
#if !defined DO_RELA || !defined ELF_MACHINE_PLT_REL
|
||||
@@ -132,7 +120,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
const ElfW (Sym) *sym = &symtab[ELFW (R_SYM) (r->r_info)];
|
||||
if (elf_dynamic_is_Rel_irelative (r, sym))
|
||||
continue;
|
||||
elf_machine_lazy_rel (map, scope, l_addr, r, skip_ifunc);
|
||||
elf_machine_lazy_rel (map, scope, l_addr, r, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -164,8 +152,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
|
||||
if (elf_dynamic_is_Rel_irelative (r, sym))
|
||||
continue;
|
||||
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg,
|
||||
skip_ifunc);
|
||||
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, 0);
|
||||
elf_dynamic_Rel_audit_symbind (map, scope, r, sym, rversion,
|
||||
r_addr_arg);
|
||||
}
|
||||
@@ -179,8 +166,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
|
||||
if (elf_dynamic_is_Rel_irelative (r, sym))
|
||||
continue;
|
||||
elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg,
|
||||
skip_ifunc);
|
||||
elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg, 0);
|
||||
elf_dynamic_Rel_audit_symbind (map, scope, r, sym, NULL,
|
||||
r_addr_arg);
|
||||
}
|
||||
|
||||
+63
-60
@@ -78,23 +78,18 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
consumes precisely the very end of the DT_REL*, or DT_JMPREL and DT_REL*
|
||||
are completely separate and there is a gap between them. */
|
||||
|
||||
/* Selects which relocations a pass processes. Splitting them allows the
|
||||
caller to interleave TLS / stack-protector setup between the two passes,
|
||||
so IFUNC resolvers see a fully-initialised TCB.
|
||||
|
||||
This is orthogonal to the skip_ifunc argument, which says whether an IFUNC
|
||||
resolver may be run at all and is honoured by every pass. In particular
|
||||
DL_RELOC_NORMAL also runs IFUNC resolvers, for relocations against an
|
||||
IFUNC symbol defined in another object. */
|
||||
enum elf_dynamic_reloc_pass
|
||||
/* This controls which sub-passes _ELF_DYNAMIC_DO_RELOC runs. Used to
|
||||
interleave TLS / stack-protector setup between the two passes so IFUNC
|
||||
resolvers see a fully-initialised TCB. */
|
||||
enum elf_dynamic_reloc_phase
|
||||
{
|
||||
DL_RELOC_ALL = 0, /* Non-IRELATIVE relocations, then IRELATIVE. */
|
||||
DL_RELOC_NORMAL = 1, /* Non-IRELATIVE relocations only. */
|
||||
DL_RELOC_IRELATIVE = 2, /* IRELATIVE relocations only. */
|
||||
DL_RELOC_BOTH = 0, /* Non-IRELATIVE pass then IRELATIVE pass. */
|
||||
DL_RELOC_NOIFUNC = 1, /* Non-IRELATIVE pass only. */
|
||||
DL_RELOC_IFUNC = 2, /* IRELATIVE pass only. */
|
||||
};
|
||||
|
||||
# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, \
|
||||
test_rel, pass) \
|
||||
test_rel, phase) \
|
||||
do { \
|
||||
struct { ElfW(Addr) start, size; \
|
||||
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
|
||||
@@ -141,15 +136,14 @@ enum elf_dynamic_reloc_pass
|
||||
by the linker. */ \
|
||||
if (!DO_RTLD_BOOTSTRAP) \
|
||||
{ \
|
||||
if ((pass) != DL_RELOC_IRELATIVE) \
|
||||
if ((phase) != DL_RELOC_IFUNC) \
|
||||
for (int ranges_index = 0; ranges_index < 2; ++ranges_index) \
|
||||
elf_dynamic_do_##reloc ((map), scope, \
|
||||
ranges[ranges_index].start, \
|
||||
ranges[ranges_index].size, \
|
||||
ranges[ranges_index].nrelative, \
|
||||
ranges[ranges_index].lazy, \
|
||||
skip_ifunc); \
|
||||
if ((pass) != DL_RELOC_NORMAL) \
|
||||
ranges[ranges_index].lazy); \
|
||||
if ((phase) != DL_RELOC_NOIFUNC) \
|
||||
for (int ranges_index = 0; ranges_index < 2; ++ranges_index) \
|
||||
elf_dynamic_do_##reloc##_irelative ((map), scope, \
|
||||
ranges[ranges_index].start, \
|
||||
@@ -164,8 +158,7 @@ enum elf_dynamic_reloc_pass
|
||||
ranges[ranges_index].start, \
|
||||
ranges[ranges_index].size, \
|
||||
ranges[ranges_index].nrelative, \
|
||||
ranges[ranges_index].lazy, \
|
||||
skip_ifunc); \
|
||||
ranges[ranges_index].lazy); \
|
||||
} while (0)
|
||||
|
||||
# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
|
||||
@@ -176,21 +169,37 @@ enum elf_dynamic_reloc_pass
|
||||
|
||||
# if ! ELF_MACHINE_NO_REL
|
||||
# include "do-rel.h"
|
||||
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc, pass) \
|
||||
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) \
|
||||
_ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc, \
|
||||
_ELF_CHECK_REL, pass)
|
||||
_ELF_CHECK_REL, DL_RELOC_BOTH)
|
||||
# define ELF_DYNAMIC_DO_REL_NOIFUNC(map, scope, lazy) \
|
||||
_ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, 0, \
|
||||
_ELF_CHECK_REL, DL_RELOC_NOIFUNC)
|
||||
# define ELF_DYNAMIC_DO_REL_IFUNCONLY(map, scope, lazy, skip_ifunc) \
|
||||
_ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc, \
|
||||
_ELF_CHECK_REL, DL_RELOC_IFUNC)
|
||||
# else
|
||||
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc, pass) /* Nothing. */
|
||||
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) /* Nothing to do. */
|
||||
# define ELF_DYNAMIC_DO_REL_NOIFUNC(map, scope, lazy) /* Nothing to do. */
|
||||
# define ELF_DYNAMIC_DO_REL_IFUNCONLY(map, scope, lazy, skip_ifunc) /* Nothing. */
|
||||
# endif
|
||||
|
||||
# if ! ELF_MACHINE_NO_RELA
|
||||
# define DO_RELA
|
||||
# include "do-rel.h"
|
||||
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc, pass) \
|
||||
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) \
|
||||
_ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc, \
|
||||
_ELF_CHECK_REL, pass)
|
||||
_ELF_CHECK_REL, DL_RELOC_BOTH)
|
||||
# define ELF_DYNAMIC_DO_RELA_NOIFUNC(map, scope, lazy) \
|
||||
_ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, 0, \
|
||||
_ELF_CHECK_REL, DL_RELOC_NOIFUNC)
|
||||
# define ELF_DYNAMIC_DO_RELA_IFUNCONLY(map, scope, lazy, skip_ifunc) \
|
||||
_ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc, \
|
||||
_ELF_CHECK_REL, DL_RELOC_IFUNC)
|
||||
# else
|
||||
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc, pass) /* Nothing. */
|
||||
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) /* Nothing to do. */
|
||||
# define ELF_DYNAMIC_DO_RELA_NOIFUNC(map, scope, lazy) /* Nothing to do. */
|
||||
# define ELF_DYNAMIC_DO_RELA_IFUNCONLY(map, scope, lazy, skip_ifunc) /* Nothing. */
|
||||
# endif
|
||||
|
||||
# define ELF_DYNAMIC_DO_RELR(map) \
|
||||
@@ -231,43 +240,37 @@ enum elf_dynamic_reloc_pass
|
||||
# else
|
||||
# define DO_RTLD_BOOTSTRAP 0
|
||||
# endif
|
||||
/* Perform one relocation pass over MAP. PASS selects which relocations are
|
||||
processed. It is orthogonal to SKIP_IFUNC, which suppresses running IFUNC
|
||||
resolvers in whichever pass is selected.
|
||||
|
||||
Unless PASS is DL_RELOC_IRELATIVE, this also performs the
|
||||
machine-specific PLT/GOT setup, the DT_RELR relocations, and the
|
||||
ELF_DYNAMIC_AFTER_RELOC hook.
|
||||
|
||||
LAZY must be an int lvalue. elf_machine_runtime_setup may downgrade the
|
||||
requested mode (currently only hppa, when it cannot install the lazy
|
||||
trampoline) and it has side effects, so it must run exactly once (the
|
||||
effective mode is stored back into LAZY). A later DL_RELOC_IRELATIVE
|
||||
call must be handed that same lvalue, so that both passes partition the
|
||||
relocation ranges identically. */
|
||||
# define ELF_DYNAMIC_RELOCATE_PASS(pass, map, scope, lazy, consider_profile, \
|
||||
skip_ifunc) \
|
||||
do { \
|
||||
if ((pass) != DL_RELOC_IRELATIVE) \
|
||||
{ \
|
||||
(lazy) = elf_machine_runtime_setup ((map), (scope), (lazy), \
|
||||
(consider_profile)); \
|
||||
if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP) \
|
||||
ELF_DYNAMIC_DO_RELR (map); \
|
||||
} \
|
||||
ELF_DYNAMIC_DO_REL ((map), (scope), (lazy), skip_ifunc, (pass)); \
|
||||
ELF_DYNAMIC_DO_RELA ((map), (scope), (lazy), skip_ifunc, (pass)); \
|
||||
if ((pass) != DL_RELOC_IRELATIVE) \
|
||||
ELF_DYNAMIC_AFTER_RELOC ((map), (lazy)); \
|
||||
} while (0)
|
||||
|
||||
/* Run both passes back to back, for callers with nothing to interleave.
|
||||
Unlike ELF_DYNAMIC_RELOCATE_PASS, LAZY need not be an lvalue. */
|
||||
# define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
|
||||
do { \
|
||||
int edr_lazy = (lazy); \
|
||||
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_ALL, (map), (scope), edr_lazy, \
|
||||
(consider_profile), skip_ifunc); \
|
||||
int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
|
||||
(consider_profile)); \
|
||||
if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP) \
|
||||
ELF_DYNAMIC_DO_RELR (map); \
|
||||
ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \
|
||||
ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc); \
|
||||
ELF_DYNAMIC_AFTER_RELOC ((map), (edr_lazy)); \
|
||||
} while (0)
|
||||
|
||||
/* Like ELF_DYNAMIC_RELOCATE but only processes the non-IRELATIVE pass.
|
||||
The IRELATIVE pass must be completed later via ELF_DYNAMIC_RELOCATE_IFUNC.
|
||||
Used by the static-pie startup so the TCB and stack-protector canary can
|
||||
be initialised between the two passes. */
|
||||
# define ELF_DYNAMIC_RELOCATE_NOIFUNC(map, scope, lazy, consider_profile) \
|
||||
do { \
|
||||
int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
|
||||
(consider_profile)); \
|
||||
if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP) \
|
||||
ELF_DYNAMIC_DO_RELR (map); \
|
||||
ELF_DYNAMIC_DO_REL_NOIFUNC ((map), (scope), edr_lazy); \
|
||||
ELF_DYNAMIC_DO_RELA_NOIFUNC ((map), (scope), edr_lazy); \
|
||||
ELF_DYNAMIC_AFTER_RELOC ((map), (edr_lazy)); \
|
||||
} while (0)
|
||||
|
||||
/* IRELATIVE-only companion to ELF_DYNAMIC_RELOCATE_NOIFUNC. */
|
||||
# define ELF_DYNAMIC_RELOCATE_IFUNC(map, scope, lazy, skip_ifunc) \
|
||||
do { \
|
||||
ELF_DYNAMIC_DO_REL_IFUNCONLY ((map), (scope), (lazy), skip_ifunc); \
|
||||
ELF_DYNAMIC_DO_RELA_IFUNCONLY ((map), (scope), (lazy), skip_ifunc); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -847,7 +847,6 @@ typedef struct
|
||||
#define NT_RISCV_VECTOR 0x901 /* RISC-V vector registers */
|
||||
#define NT_RISCV_TAGGED_ADDR_CTRL 0x902 /* RISC-V tagged
|
||||
address control */
|
||||
#define NT_RISCV_USER_CFI 0x903 /* RISC-V shadow stack state */
|
||||
#define NT_LOONGARCH_CPUCFG 0xa00 /* LoongArch CPU config registers. */
|
||||
#define NT_LOONGARCH_CSR 0xa01 /* LoongArch control and
|
||||
status registers. */
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#include <libc-diag.h>
|
||||
|
||||
static inline void __attribute__ ((unused, always_inline))
|
||||
elf_get_dynamic_info (struct link_map *l, bool bootstrap)
|
||||
elf_get_dynamic_info (struct link_map *l, bool bootstrap,
|
||||
bool static_pie_bootstrap)
|
||||
{
|
||||
#if __ELF_NATIVE_CLASS == 32
|
||||
typedef Elf32_Word d_tag_utype;
|
||||
@@ -34,8 +35,10 @@ elf_get_dynamic_info (struct link_map *l, bool bootstrap)
|
||||
typedef Elf64_Xword d_tag_utype;
|
||||
#endif
|
||||
|
||||
#ifndef STATIC_PIE_BOOTSTRAP
|
||||
if (!bootstrap && l->l_ld == NULL)
|
||||
return;
|
||||
#endif
|
||||
|
||||
ElfW(Dyn) **info = l->l_info;
|
||||
|
||||
@@ -125,7 +128,7 @@ elf_get_dynamic_info (struct link_map *l, bool bootstrap)
|
||||
#endif
|
||||
if (info[DT_RELR] != NULL)
|
||||
assert (info[DT_RELRENT]->d_un.d_val == sizeof (ElfW(Relr)));
|
||||
if (bootstrap)
|
||||
if (bootstrap || static_pie_bootstrap)
|
||||
{
|
||||
assert (info[DT_RUNPATH] == NULL);
|
||||
assert (info[DT_RPATH] == NULL);
|
||||
|
||||
@@ -47,10 +47,8 @@ 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. Will also be called
|
||||
with a NULL line at the start and end of each file, for
|
||||
file-scoped config items.
|
||||
callback - for each non-blank line in the file, this function is called
|
||||
with the line and it's location.
|
||||
*/
|
||||
|
||||
void
|
||||
|
||||
+5
-183
@@ -44,17 +44,12 @@
|
||||
#include <dl-cache.h>
|
||||
#include <dl-hwcaps.h>
|
||||
#include <dl-is_dso.h>
|
||||
#include "tunconf.h"
|
||||
|
||||
|
||||
#ifndef LD_SO_CONF
|
||||
# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
|
||||
#endif
|
||||
|
||||
#ifndef TUNABLES_CONF
|
||||
# define TUNABLES_CONF SYSCONFDIR "/tunables.conf"
|
||||
#endif
|
||||
|
||||
/* Get libc version number. */
|
||||
#include <version.h>
|
||||
|
||||
@@ -109,18 +104,12 @@ static int opt_manual_link;
|
||||
/* Should we ignore an old auxiliary cache file? */
|
||||
static int opt_ignore_aux_cache;
|
||||
|
||||
/* Install a pre-existing cache file instead of generating a new one. */
|
||||
static int opt_install;
|
||||
|
||||
/* Cache file to use. */
|
||||
static char *cache_file;
|
||||
|
||||
/* Configuration file for libraries. */
|
||||
/* Configuration file. */
|
||||
static const char *config_file;
|
||||
|
||||
/* Configuration file for tunables. */
|
||||
static const char *tunconfig_file;
|
||||
|
||||
/* Name and version of program. */
|
||||
static void print_version (FILE *stream, struct argp_state *state);
|
||||
void (*argp_program_version_hook) (FILE *, struct argp_state *)
|
||||
@@ -138,13 +127,11 @@ static const struct argp_option options[] =
|
||||
{ NULL, 'X', NULL, 0, N_("Don't update symbolic links"), 0},
|
||||
{ NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0},
|
||||
{ NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0},
|
||||
{ NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file for libraries"), 0},
|
||||
{ NULL, 't', N_("TUNCONF"), 0, N_("Use TUNCONF as configuration file for tunables"), 0},
|
||||
{ NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
|
||||
{ NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
|
||||
{ NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
|
||||
{ "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0},
|
||||
{ "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
|
||||
{ "install", 'I', NULL, 0, N_("Install pre-existing cache file"), 0},
|
||||
{ NULL, 0, NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
@@ -177,9 +164,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
case 'f':
|
||||
config_file = arg;
|
||||
break;
|
||||
case 't':
|
||||
tunconfig_file = arg;
|
||||
break;
|
||||
case 'i':
|
||||
opt_ignore_aux_cache = 1;
|
||||
break;
|
||||
@@ -213,9 +197,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
else if (strcmp (arg, "new") == 0)
|
||||
opt_format = opt_format_new;
|
||||
break;
|
||||
case 'I':
|
||||
opt_install = 1;
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
@@ -440,11 +421,8 @@ 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)
|
||||
add_dir_callback (const 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
|
||||
@@ -1048,155 +1026,6 @@ search_dirs (void)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
install_cache_file (const char *source_arg)
|
||||
{
|
||||
int e;
|
||||
|
||||
if (source_arg == NULL)
|
||||
error (EXIT_FAILURE, 0, _("Missing source file name"));
|
||||
|
||||
const char *source = (opt_chroot
|
||||
? chroot_canon (opt_chroot, source_arg)
|
||||
: source_arg);
|
||||
if (source == NULL)
|
||||
error (EXIT_FAILURE, errno, _("Can't find %s"), source_arg);
|
||||
|
||||
int src_fd = open (source, O_RDONLY);
|
||||
if (src_fd < 0)
|
||||
error (EXIT_FAILURE, errno, _("Can't open %s"), source);
|
||||
|
||||
char *dest = xmalloc (strlen (cache_file) + 1 + 1);
|
||||
|
||||
/* This matches the temp file created by cache.c, and should be
|
||||
on the same filesystem as the cache file. */
|
||||
sprintf (dest, "%s~", cache_file);
|
||||
int dest_fd;
|
||||
|
||||
struct stat st;
|
||||
if (fstat (src_fd, &st) < 0)
|
||||
error (EXIT_FAILURE, errno, _("Can't stat %s"), source);
|
||||
|
||||
char buf[512];
|
||||
ssize_t r, w = 0, sz = 0;
|
||||
char *bp = buf;
|
||||
|
||||
/* Read the first part of the file and verify it looks
|
||||
reasonable. */
|
||||
while (sz < sizeof (buf)
|
||||
&& (r = read (src_fd, bp, sizeof (buf) - sz)) > 0)
|
||||
{
|
||||
sz += r;
|
||||
bp += r;
|
||||
}
|
||||
if (r < 0)
|
||||
error (EXIT_FAILURE, errno, _("Error reading file %s"), source);
|
||||
|
||||
if (! ((sz >= sizeof (CACHEMAGIC)
|
||||
&& memcmp (buf, CACHEMAGIC,
|
||||
sizeof (CACHEMAGIC) - 1) == 0)
|
||||
|| (sz >= sizeof (CACHEMAGIC_NEW)
|
||||
&& memcmp (buf, CACHEMAGIC_NEW,
|
||||
sizeof (CACHEMAGIC_NEW) - 1) == 0)))
|
||||
{
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("File %s does not look like an ld.so.cache file"),
|
||||
source);
|
||||
}
|
||||
|
||||
/* Now write that first part out. */
|
||||
dest_fd = open (dest, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
|
||||
S_IRUSR|S_IWUSR);
|
||||
if (dest_fd < 0)
|
||||
error (EXIT_FAILURE, errno, _("Can't create %s"), dest);
|
||||
|
||||
r = sz;
|
||||
bp = buf;
|
||||
while (r > 0 && (w = write (dest_fd, bp, r)) > 0)
|
||||
{
|
||||
r -= w;
|
||||
bp += w;
|
||||
}
|
||||
if (w < 0)
|
||||
{
|
||||
e = errno;
|
||||
unlink (dest);
|
||||
close (dest_fd);
|
||||
error (EXIT_FAILURE, e, _("Error writing file %s"), dest);
|
||||
}
|
||||
|
||||
/* At this point, sz contains the number of bytes copied so far.
|
||||
Copy the rest of the file. */
|
||||
while ((r = read (src_fd, buf, sizeof(buf))) > 0)
|
||||
{
|
||||
bp = buf;
|
||||
while (r > 0 && (w = write (dest_fd, bp, r)) > 0)
|
||||
{
|
||||
bp += w;
|
||||
r -= w;
|
||||
sz += w;
|
||||
}
|
||||
if (w <= 0)
|
||||
break;
|
||||
}
|
||||
if (r < 0)
|
||||
{
|
||||
e = errno;
|
||||
unlink (dest);
|
||||
close (dest_fd);
|
||||
error (EXIT_FAILURE, e, _("Error reading file %s"), source);
|
||||
}
|
||||
if (w < 0)
|
||||
{
|
||||
e = errno;
|
||||
unlink (dest);
|
||||
close (dest_fd);
|
||||
error (EXIT_FAILURE, e, _("Error writing file %s"), dest);
|
||||
}
|
||||
|
||||
close (src_fd);
|
||||
|
||||
/* Make sure we copied it all. */
|
||||
if (sz < st.st_size)
|
||||
{
|
||||
unlink (dest);
|
||||
close (dest_fd);
|
||||
error (EXIT_FAILURE, 0, _("Unable to copy file %s to %s"),
|
||||
source, dest);
|
||||
}
|
||||
|
||||
/* Make sure user can always read the cache file */
|
||||
if (fchmod (dest_fd, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
|
||||
{
|
||||
e = errno;
|
||||
unlink (dest);
|
||||
close (dest_fd);
|
||||
error (EXIT_FAILURE, e,
|
||||
_("Changing access rights of %s to %#o failed"), dest,
|
||||
S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
|
||||
}
|
||||
|
||||
if (fsync (dest_fd) != 0)
|
||||
{
|
||||
e = errno;
|
||||
unlink (dest);
|
||||
close (dest_fd);
|
||||
error (EXIT_FAILURE, e, _("Writing to %s failed"), dest);
|
||||
}
|
||||
|
||||
if (rename (dest, cache_file) < 0)
|
||||
{
|
||||
e = errno;
|
||||
unlink (dest);
|
||||
close (dest_fd);
|
||||
error (EXIT_FAILURE, e, _("Can't rename %s to %s"),
|
||||
dest, cache_file);
|
||||
}
|
||||
|
||||
if (close (dest_fd) != 0)
|
||||
error (EXIT_FAILURE, errno, _("Writing to %s failed"), dest);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
@@ -1216,8 +1045,8 @@ main (int argc, char **argv)
|
||||
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
|
||||
|
||||
/* Remaining arguments are additional directories if opt_manual_link
|
||||
and opt_install are not set. */
|
||||
if (remaining != argc && !opt_manual_link && !opt_install)
|
||||
is not set. */
|
||||
if (remaining != argc && !opt_manual_link)
|
||||
{
|
||||
int i;
|
||||
for (i = remaining; i < argc; ++i)
|
||||
@@ -1260,9 +1089,6 @@ main (int argc, char **argv)
|
||||
if (config_file == NULL)
|
||||
config_file = LD_SO_CONF;
|
||||
|
||||
if (tunconfig_file == NULL)
|
||||
tunconfig_file = TUNABLES_CONF;
|
||||
|
||||
if (opt_print_cache)
|
||||
{
|
||||
if (opt_chroot != NULL)
|
||||
@@ -1313,8 +1139,6 @@ main (int argc, char **argv)
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (opt_install)
|
||||
install_cache_file (argv[remaining]);
|
||||
|
||||
if (opt_build_cache)
|
||||
init_cache ();
|
||||
@@ -1340,8 +1164,6 @@ main (int argc, char **argv)
|
||||
|
||||
search_dirs ();
|
||||
|
||||
parse_tunconf (tunconfig_file, opt_chroot);
|
||||
|
||||
if (opt_build_cache)
|
||||
{
|
||||
save_cache (cache_file);
|
||||
|
||||
+7
-8
@@ -545,7 +545,7 @@ _dl_start (void *arg)
|
||||
/* Read our own dynamic section and fill in the info array. */
|
||||
bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
|
||||
bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION;
|
||||
elf_get_dynamic_info (&bootstrap_map, true);
|
||||
elf_get_dynamic_info (&bootstrap_map, true, false);
|
||||
|
||||
#if NO_TLS_OFFSET != 0
|
||||
bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
|
||||
@@ -1671,12 +1671,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
|
||||
_dl_handle_execstack_tunable ();
|
||||
|
||||
/* Every string tunable has been consumed by now (init_cpu_features runs
|
||||
from DL_PLATFORM_INIT, before dl_main). It precedes any code outside
|
||||
the dynamic loader (the audit modules and IFUNC resolvers), and
|
||||
RELRO. */
|
||||
__tunable_seal_strings ();
|
||||
|
||||
/* If the current libname is different from the SONAME, add the
|
||||
latter as well. */
|
||||
{
|
||||
@@ -1700,7 +1694,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
if (! rtld_is_main)
|
||||
{
|
||||
/* Extract the contents of the dynamic section for easy access. */
|
||||
elf_get_dynamic_info (main_map, false);
|
||||
elf_get_dynamic_info (main_map, false, false);
|
||||
|
||||
/* If the main map is libc.so, update the base namespace to
|
||||
refer to this map. If libc.so is loaded later, this happens
|
||||
@@ -2377,6 +2371,11 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
/* Auditing checkpoint: we have added all objects. */
|
||||
_dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
|
||||
|
||||
#if defined USE_LDCONFIG && !defined MAP_COPY
|
||||
/* We must munmap() the cache file. */
|
||||
_dl_unload_cache ();
|
||||
#endif
|
||||
|
||||
/* Once we return, _dl_sysdep_start will invoke
|
||||
the DT_INIT functions and then *USER_ENTRY. */
|
||||
}
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
|
||||
l->l_addr = l->l_map_start - l->l_addr;
|
||||
l->l_map_end += l->l_addr;
|
||||
l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
|
||||
elf_get_dynamic_info (l, false);
|
||||
elf_get_dynamic_info (l, false, false);
|
||||
_dl_setup_hash (l);
|
||||
l->l_relocated = 1;
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/* Check if assert works during program startup.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* The __libc_assert_fail is used internally for assert() calls. */
|
||||
extern _Noreturn __typeof (__assert_fail) __libc_assert_fail;
|
||||
|
||||
/* The __tunables_init is called just before self-relocation and TLS setup,
|
||||
so overriding it is a way to reach the assert code at that point. */
|
||||
void
|
||||
__tunables_init (char **env, char **argv)
|
||||
{
|
||||
/* Inside libc, assert() is redirected to __libc_assert_fail. This test is
|
||||
not built as part of libc, so a plain assert() here would call the public
|
||||
__assert_fail instead, which uses __progname and the translation routines
|
||||
and thus is not what the startup code issues. Call the internal routine
|
||||
directly. */
|
||||
__libc_assert_fail ("error", __FILE__, __LINE__, __func__);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
/* Fail with a different error code than abort. */
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ if [ $fail -ne 0 ]; then
|
||||
echo "Test FAILED"
|
||||
cat "${debug_output}".*
|
||||
rm -f "${debug_output}".*
|
||||
exit $fail
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Test PASSED"
|
||||
|
||||
@@ -43,7 +43,7 @@ rc=$?
|
||||
if test $rc -eq 77; then
|
||||
echo "Test is not supported"
|
||||
rm -f "${output}".*
|
||||
exit $rc
|
||||
exit 77
|
||||
fi
|
||||
|
||||
output=$(ls "${output}".*)
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/* Unit tests for dl-path-normalize.h.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <dl-path-normalize.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/next_to_fault.h>
|
||||
|
||||
static void
|
||||
check_one_guarded (const char *input, const char *expected, bool before)
|
||||
{
|
||||
size_t size = strlen (input) + 1;
|
||||
struct support_next_to_fault ntf
|
||||
= before ? support_next_to_fault_allocate_before (size)
|
||||
: support_next_to_fault_allocate (size);
|
||||
memcpy (ntf.buffer, input, size);
|
||||
|
||||
size_t len = _dl_normalize_path (ntf.buffer);
|
||||
|
||||
TEST_COMPARE (len, strlen (ntf.buffer));
|
||||
TEST_COMPARE_STRING (ntf.buffer, expected);
|
||||
|
||||
support_next_to_fault_free (&ntf);
|
||||
}
|
||||
|
||||
static void
|
||||
check_one (const char *input, const char *expected)
|
||||
{
|
||||
/* Check that _dl_normalize_path does not access the string outside the
|
||||
input argument. It checks for both over-runs and under-runs (the
|
||||
latter for the case of '..' expansions). */
|
||||
check_one_guarded (input, expected, false);
|
||||
check_one_guarded (input, expected, true);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Absolute paths. */
|
||||
check_one ("/", "/");
|
||||
check_one ("//", "/");
|
||||
check_one ("///", "/");
|
||||
check_one ("////", "/");
|
||||
check_one ("/a", "/a");
|
||||
check_one ("/a/", "/a");
|
||||
check_one ("/a//", "/a");
|
||||
check_one ("//a//b//", "/a/b");
|
||||
check_one ("/.", "/");
|
||||
check_one ("/./", "/");
|
||||
check_one ("/./a", "/a");
|
||||
check_one ("/a/./b", "/a/b");
|
||||
check_one ("/a/.", "/a");
|
||||
check_one ("/..", "/");
|
||||
check_one ("/../", "/");
|
||||
check_one ("/../a", "/a");
|
||||
check_one ("/a/..", "/");
|
||||
check_one ("/a/../", "/");
|
||||
check_one ("/a/../..", "/");
|
||||
check_one ("/a/../b", "/b");
|
||||
check_one ("/a/../../b", "/b");
|
||||
check_one ("/a/b/../../c", "/c");
|
||||
check_one ("/a/b/../c", "/a/c");
|
||||
check_one ("/a/b/c/../..", "/a");
|
||||
check_one ("/usr/lib/../lib64", "/usr/lib64");
|
||||
check_one ("/usr/lib/../lib64/", "/usr/lib64");
|
||||
check_one ("/usr/lib/..//lib64/", "/usr/lib64");
|
||||
check_one ("/usr/lib/../../lib64/", "/lib64");
|
||||
|
||||
/* "." and ".." are special only as complete components. */
|
||||
check_one ("/a..", "/a..");
|
||||
check_one ("/..a", "/..a");
|
||||
check_one ("/a/...", "/a/...");
|
||||
check_one ("/.../a", "/.../a");
|
||||
check_one ("/a./b", "/a./b");
|
||||
check_one (".a", ".a");
|
||||
check_one ("a.", "a.");
|
||||
check_one ("..a", "..a");
|
||||
check_one ("...", "...");
|
||||
|
||||
/* Relative paths. */
|
||||
check_one ("", "");
|
||||
check_one (".", "");
|
||||
check_one ("./", "");
|
||||
check_one ("..", "..");
|
||||
check_one ("../", "..");
|
||||
check_one ("a", "a");
|
||||
check_one ("a/", "a");
|
||||
check_one ("a//b", "a/b");
|
||||
check_one ("a..", "a..");
|
||||
check_one ("./a", "a");
|
||||
check_one ("./.", "");
|
||||
check_one ("./..", "..");
|
||||
|
||||
check_one ("a/..", "");
|
||||
check_one ("a/../", "");
|
||||
check_one ("ab/..", "");
|
||||
check_one (".a/..", "");
|
||||
check_one ("a./..", "");
|
||||
check_one (".../..", "");
|
||||
check_one ("a/./..", "");
|
||||
check_one ("a/b/..", "a");
|
||||
check_one ("abc/def/..", "abc");
|
||||
|
||||
/* Appending a component to an emptied relative output must not produce a
|
||||
leading '/' (the path must stay relative). */
|
||||
check_one ("a/../b", "b");
|
||||
check_one ("a/.././b", "b");
|
||||
check_one ("a/../lib64/b", "lib64/b");
|
||||
|
||||
/* Leading ".." components of a relative path are preserved and stack
|
||||
instead of cancelling each other; ordinary components may follow and be
|
||||
removed again afterwards. */
|
||||
check_one ("../a", "../a");
|
||||
check_one ("../..", "../..");
|
||||
check_one ("../../..", "../../..");
|
||||
check_one ("../../a", "../../a");
|
||||
check_one ("../a/..", "..");
|
||||
check_one ("../../a/..", "../..");
|
||||
check_one ("a/../../b", "../b");
|
||||
check_one ("a/b/../../..", "..");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -1,27 +0,0 @@
|
||||
/* Program calling an IFUNC defined in a dependency (BZ 34428).
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
extern void magic (void);
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
/* JMP_SLOT relocation against an undefined symbol. */
|
||||
magic ();
|
||||
return 1;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/* Shared object exporting an IFUNC symbol with a resolver which crashes.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
static void
|
||||
implementation (void)
|
||||
{
|
||||
/* Produce a crash, without depending on any relocations. */
|
||||
volatile char *volatile p = NULL;
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
static __typeof__ (implementation) *
|
||||
__attribute_used__
|
||||
resolver (void)
|
||||
{
|
||||
/* Produce a crash, without depending on any relocations. */
|
||||
volatile char *volatile p = NULL;
|
||||
*p = 0;
|
||||
return implementation;
|
||||
}
|
||||
|
||||
void magic (void) __attribute__ ((ifunc ("resolver")));
|
||||
@@ -1,137 +0,0 @@
|
||||
/* Test ldconfig cache is correctly used when changed.
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* What we're testing for: We initially load ld.so.cache at startup
|
||||
and remember it. If we detect that ld.so.cache has changed, and we
|
||||
can load it successfully, we replace our remember it. If it
|
||||
doesn't change, or if the new version is corrupted, we continue
|
||||
using the old remembered copy. */
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <support/support.h>
|
||||
#include <support/check.h>
|
||||
|
||||
#include <support/xstdio.h>
|
||||
#include <support/xstdlib.h>
|
||||
#include <support/xdlfcn.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
|
||||
/* Verify that we can (or can't) load one of our test objects. */
|
||||
static void
|
||||
try (int i, int invert)
|
||||
{
|
||||
char dlname[100];
|
||||
char symname[100];
|
||||
int (*proc)(int);
|
||||
void *dl;
|
||||
|
||||
/* These match the objects copied by tst-ldconfig-cache.script,
|
||||
copied from tst-tls-manydynamic*.so. */
|
||||
sprintf (dlname, "libcache%d.so", i);
|
||||
sprintf (symname, "set_value_%02d", i);
|
||||
|
||||
dl = dlopen (dlname, RTLD_NOW);
|
||||
|
||||
if (invert)
|
||||
{
|
||||
/* This is a negative test; if the object doesn't load the test
|
||||
passes. */
|
||||
TEST_VERIFY (dl == NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a positive test; if the object doesn't load the test
|
||||
fails. */
|
||||
if (dl == NULL)
|
||||
FAIL_EXIT1 ("error: dlopen: %s\n", dlerror ());
|
||||
}
|
||||
|
||||
proc = xdlsym (dl, symname);
|
||||
/* We don't need to call the symbol, just make sure it exists. */
|
||||
TEST_VERIFY (proc != NULL);
|
||||
|
||||
xdlclose (dl);
|
||||
}
|
||||
|
||||
/* Cause corruption in the cache that should prevent loading it. */
|
||||
static void
|
||||
corrupt (void)
|
||||
{
|
||||
int fd = xopen ("/etc/ld.so.cache", O_RDWR, 0);
|
||||
char bytes[] = { 15, 32, 184, 4 };
|
||||
xwrite (fd, bytes, sizeof(bytes));
|
||||
xclose (fd);
|
||||
}
|
||||
|
||||
/* Regenerate the cache from ld.so.conf. */
|
||||
static void
|
||||
ldconfig (void)
|
||||
{
|
||||
char *cmd = xasprintf("%s/ldconfig -X", support_install_rootsbindir);
|
||||
xsystem (cmd);
|
||||
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
/* Change ld.so.conf to refer to the new directory, and generate a new
|
||||
cache. */
|
||||
static void
|
||||
newpath (const char *p)
|
||||
{
|
||||
FILE *f = xfopen ("/etc/ld.so.conf", "w");
|
||||
fprintf (f, "%s\n", p);
|
||||
xfclose (f);
|
||||
|
||||
ldconfig ();
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Test that the cache we started with can still load objects in
|
||||
/a. */
|
||||
try (1, 0);
|
||||
|
||||
/* Create a new cache that doesn't include /a but corrupt it. Test
|
||||
that we still use the cache with /a in it. */
|
||||
newpath ("/c");
|
||||
corrupt ();
|
||||
try (2, 0);
|
||||
|
||||
/* Regenerate a clean cache with /a in it and verify we can load
|
||||
objects in /a. */
|
||||
newpath ("/a");
|
||||
try (3, 0);
|
||||
|
||||
/* Generate a new cache with /b but not /a and make sure objects
|
||||
in /a can't be loaded. */
|
||||
newpath ("/b");
|
||||
try (3, 1);
|
||||
|
||||
/* But objects in /b can be loaded. */
|
||||
try (4, 0);
|
||||
/* Even multiple times. */
|
||||
try (5, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -1,3 +0,0 @@
|
||||
/lib
|
||||
/lib64
|
||||
/a
|
||||
@@ -1,7 +0,0 @@
|
||||
mkdirp 0755 /a
|
||||
cp $B/elf/tst-tls-manydynamic01mod.so /a/libcache1.so
|
||||
cp $B/elf/tst-tls-manydynamic02mod.so /a/libcache2.so
|
||||
cp $B/elf/tst-tls-manydynamic03mod.so /a/libcache3.so
|
||||
mkdirp 0755 /b
|
||||
cp $B/elf/tst-tls-manydynamic04mod.so /b/libcache4.so
|
||||
cp $B/elf/tst-tls-manydynamic05mod.so /b/libcache5.so
|
||||
@@ -1,125 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Test that ldconfig --install installs a pre-built cache file.
|
||||
# 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
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
|
||||
set -e
|
||||
|
||||
common_objpfx=$1
|
||||
test_wrapper_env=$2
|
||||
run_program_env=$3
|
||||
|
||||
testroot="${common_objpfx}elf/tst-ldconfig-install-directory"
|
||||
cleanup () {
|
||||
rm -rf "$testroot"
|
||||
}
|
||||
trap cleanup 0
|
||||
|
||||
rm -rf "$testroot"
|
||||
mkdir -p "$testroot/etc"
|
||||
|
||||
ldconfig="${common_objpfx}elf/ldconfig"
|
||||
run_ldconfig () {
|
||||
${test_wrapper_env} ${run_program_env} "$ldconfig" "$@"
|
||||
}
|
||||
|
||||
errors=0
|
||||
fail () {
|
||||
echo "error: $1"
|
||||
errors=1
|
||||
}
|
||||
|
||||
# Build a pre-built cache to install.
|
||||
source="$testroot/prebuilt-ld.so.cache"
|
||||
mkdir -p "$testroot/lib"
|
||||
run_ldconfig -X -f /dev/null -C "$source" "$testroot/lib"
|
||||
test -r "$source" || fail "ldconfig did not create the pre-built cache"
|
||||
|
||||
# Pad the source past the 512-byte internal copy buffer so that the multi-block
|
||||
# copy path is exercised, while leaving the cache magic at the start intact.
|
||||
dd if=/dev/zero bs=1024 count=4 >> "$source" 2>/dev/null
|
||||
|
||||
dest="$testroot/etc/ld.so.cache"
|
||||
temp="$dest~"
|
||||
|
||||
run_ldconfig --install -f /dev/null -C "$dest" "$source"
|
||||
|
||||
# The destination must exist and be byte-identical to the source.
|
||||
if test -r "$dest"; then
|
||||
if cmp -s "$source" "$dest"; then
|
||||
echo "info: installed cache matches the source"
|
||||
else
|
||||
fail "installed cache differs from the source"
|
||||
fi
|
||||
else
|
||||
fail "destination cache file was not created"
|
||||
fi
|
||||
|
||||
# The temporary file used during the atomic rename must not be left behind.
|
||||
if test -e "$temp"; then
|
||||
fail "temporary file $temp was left behind"
|
||||
fi
|
||||
|
||||
# The installed cache must be world-readable (0644).
|
||||
if test -r "$dest"; then
|
||||
mode=$(ls -l "$dest" | cut -c1-10)
|
||||
case "$mode" in
|
||||
(-rw-r--r--) echo "info: installed cache has expected permissions" ;;
|
||||
(*) fail "installed cache has unexpected permissions: $mode" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# A second install over an existing cache must also succeed.
|
||||
run_ldconfig --install -f /dev/null -C "$dest" "$source"
|
||||
if cmp -s "$source" "$dest"; then
|
||||
echo "info: re-install over an existing cache works"
|
||||
else
|
||||
fail "re-install produced a different cache"
|
||||
fi
|
||||
|
||||
# Error case: a source file that is not a cache must be rejected, and no
|
||||
# destination must be produced.
|
||||
rm -f "$dest"
|
||||
notcache="$testroot/not-a-cache"
|
||||
echo "this is not an ld.so.cache file" > "$notcache"
|
||||
if run_ldconfig --install -f /dev/null -C "$dest" "$notcache" 2>"$testroot/err"; then
|
||||
fail "ldconfig accepted a file that is not a cache"
|
||||
else
|
||||
if grep -q "does not look like an ld.so.cache file" "$testroot/err"; then
|
||||
echo "info: non-cache source correctly rejected"
|
||||
else
|
||||
fail "unexpected error message for non-cache source"
|
||||
cat "$testroot/err"
|
||||
fi
|
||||
fi
|
||||
test -e "$dest" && fail "destination created from an invalid source"
|
||||
|
||||
# Error case: a missing source argument must be diagnosed.
|
||||
if run_ldconfig --install -f /dev/null -C "$dest" 2>"$testroot/err"; then
|
||||
fail "ldconfig accepted --install without a source file"
|
||||
else
|
||||
grep -q "Missing source file name" "$testroot/err" \
|
||||
|| fail "unexpected error message for missing source"
|
||||
fi
|
||||
|
||||
# Error case: a nonexistent source must be diagnosed.
|
||||
if run_ldconfig --install -f /dev/null -C "$dest" \
|
||||
"$testroot/does-not-exist" 2>"$testroot/err"; then
|
||||
fail "ldconfig accepted a nonexistent source file"
|
||||
fi
|
||||
|
||||
exit $errors
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
/* Plugin to load. */
|
||||
static void *plugin_lib = NULL;
|
||||
/* Plugin function. */
|
||||
static void (*plugin_func) (void);
|
||||
#define LIB_PLUGIN "tst-nodelete-dlclose-plugin.so"
|
||||
|
||||
/* This function is never called but the plugin references it.
|
||||
@@ -53,7 +55,7 @@ primary (void)
|
||||
}
|
||||
dlerror ();
|
||||
|
||||
dlsym (plugin_lib, "plugin_func");
|
||||
plugin_func = (void (*) (void)) dlsym (plugin_lib, "plugin_func");
|
||||
error = dlerror ();
|
||||
if (error != NULL)
|
||||
{
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/* Module for tst-origin-secure (the attacker-controlled copy).
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-origin-secure.h"
|
||||
|
||||
/* If the victim reports this copy, the loader opened the un-normalized rpath
|
||||
and resolved it through the attacker's symlink -- i.e. the trusted-path
|
||||
check was bypassed (bug 34360). */
|
||||
int
|
||||
origin_secure_id (void)
|
||||
{
|
||||
return ORIGIN_SECURE_ID_ATTACKER;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/* Victim program for tst-origin-secure.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-origin-secure.h"
|
||||
|
||||
extern int __libc_enable_secure;
|
||||
|
||||
/* Report both which module was loaded and whether the loader ran in secure
|
||||
mode, so the driver can tell a genuine trusted-path bypass apart from a run
|
||||
that simply was not secure.
|
||||
|
||||
The exit status is the combination of the ORIGIN_SECURE_STATUS_* bits:
|
||||
|
||||
_NONE trusted copy, not secure
|
||||
_ATTACKER attacker copy, not secure (the control run)
|
||||
_SECURE trusted copy, secure (a fixed loader)
|
||||
_SECURE | _ATTACKER attacker copy, secure (the bug: the raw
|
||||
rpath was opened) */
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int status = ORIGIN_SECURE_STATUS_NONE;
|
||||
if (origin_secure_id () == ORIGIN_SECURE_ID_ATTACKER)
|
||||
status |= ORIGIN_SECURE_STATUS_ATTACKER;
|
||||
if (__libc_enable_secure != 0)
|
||||
status |= ORIGIN_SECURE_STATUS_SECURE;
|
||||
return status;
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
/* Test that AT_SECURE $ORIGIN rpath entries are looked up using the
|
||||
normalized (trusted) path, not the raw expansion (bug 34360).
|
||||
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
/* For a SUID/SGID program the loader only honors $ORIGIN in DT_RPATH when
|
||||
the normalized expansion is rooted in a trusted directory. If the loader
|
||||
opens the un-normalized string (that contains "../"), it might disagree
|
||||
as soon as a path component is a symbolic link.
|
||||
|
||||
This test builds the executable with the rpath:
|
||||
|
||||
$ORIGIN/sub/../../../../..SLIBDIR/tst-origin-secure
|
||||
|
||||
and runs it as BASE/a/b/victim, so $ORIGIN is BASE/a/b. Lexically the
|
||||
five "../" pop $ORIGIN/sub back to "/" (BASE is /tmp/tst-origin-secure,
|
||||
so $ORIGIN/sub is the five components tmp, tst-origin-secure, a, b, sub),
|
||||
and the entry normalizes to the trusted SLIBDIR/tst-origin-secure. But
|
||||
"sub" is a symlink pointing six levels deep under BASE, so opening the raw
|
||||
string makes the kernel resolve the "../" through the symlink and land in
|
||||
BASE/x1 SLIBDIR/tst-origin-secure instead.
|
||||
|
||||
The "../" count in the rpath (see the Makefile) is therefore
|
||||
depth(BASE) + 2 (for the "a/b" of $ORIGIN) + 1 (for "sub"); it is
|
||||
independent of SLIBDIR, which is appended whole on both the raw and the
|
||||
normalized side.
|
||||
|
||||
A trusted copy of the module (ORIGIN_SECURE_ID_TRUSTED) is installed in
|
||||
SLIBDIR/tst-origin-secure; an attacker copy (ORIGIN_SECURE_ID_ATTACKER) is
|
||||
placed at the symlink-diverted location. The trusted subdirectory is
|
||||
rooted under SLIBDIR (so it passes the trusted-path check) but is not
|
||||
itself a default loader search directory.
|
||||
|
||||
The victim reports, in its exit status, both which module it loaded and
|
||||
whether it ran in secure mode.
|
||||
|
||||
Secure mode is forced with glibc.rtld.enable_secure=1 so that no real
|
||||
SUID/SGID binary is required. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/xunistd.h>
|
||||
#include "tst-origin-secure.h"
|
||||
|
||||
#define BASE "/tmp/tst-origin-secure"
|
||||
#define SONAME "libtst-origin-secure-mod.so"
|
||||
/* Subdirectory of the trusted SLIBDIR that the rpath normalizes to. It is
|
||||
trusted (rooted under SLIBDIR) but not a default search directory. */
|
||||
#define SUBDIR "tst-origin-secure"
|
||||
|
||||
static int
|
||||
run_victim (char *const *envp)
|
||||
{
|
||||
const char *victim = BASE "/a/b/victim";
|
||||
char *const argv[] = { (char *) victim, NULL };
|
||||
|
||||
struct support_capture_subprocess res
|
||||
= support_capture_subprogram (victim, argv, envp);
|
||||
/* The victim itself prints nothing; forward any loader diagnostics to
|
||||
the test log. */
|
||||
if (res.err.length > 0)
|
||||
printf ("info: victim stderr: %s\n", res.err.buffer);
|
||||
int status = res.status;
|
||||
support_capture_subprocess_free (&res);
|
||||
return WIFEXITED (status) ? WEXITSTATUS (status) : -1;
|
||||
}
|
||||
|
||||
/* With SLIBDIR "/lib64" the container layout is:
|
||||
|
||||
/lib64/tst-origin-secure/libtst-origin-secure-mod.so trusted copy (id 1)
|
||||
BASE/a/b/victim the executable
|
||||
BASE/a/b/sub -> BASE/x1/x2/x3/x4/x5/x6 six levels deep
|
||||
BASE/x1/lib64/tst-origin-secure/libtst-origin-secure-mod.so
|
||||
attacker copy (id 2)
|
||||
BASE/x1/x2/x3/x4/x5/x6/ the symlink target
|
||||
|
||||
The victim's rpath is $ORIGIN/sub + five "../" + /lib64/tst-origin-secure. */
|
||||
static void
|
||||
do_prepare (int argc, char **argv)
|
||||
{
|
||||
const char *slibdir = support_slibdir_prefix;
|
||||
const char *objelf = support_objdir_root;
|
||||
|
||||
char *good_src = xasprintf ("%s/elf/libtst-origin-secure-mod.so", objelf);
|
||||
char *evil_src = xasprintf ("%s/elf/tst-origin-secure-evilmod.so", objelf);
|
||||
char *victim_src = xasprintf ("%s/elf/tst-origin-secure-victim", objelf);
|
||||
|
||||
xmkdirp (BASE "/a/b", 0755);
|
||||
xmkdirp (BASE "/x1/x2/x3/x4/x5/x6", 0755);
|
||||
|
||||
/* Where the trusted copy lives (reached only via the normalized rpath,
|
||||
SLIBDIR/SUBDIR) ... */
|
||||
char *good_dir = xasprintf ("%s/%s", slibdir, SUBDIR);
|
||||
char *good_dst = xasprintf ("%s/%s", good_dir, SONAME);
|
||||
xmkdirp (good_dir, 0755);
|
||||
/* ... and where the raw, symlink-diverted lookup lands. */
|
||||
char *evil_dir = xasprintf ("%s/x1%s/%s", BASE, slibdir, SUBDIR);
|
||||
char *evil_dst = xasprintf ("%s/%s", evil_dir, SONAME);
|
||||
xmkdirp (evil_dir, 0755);
|
||||
|
||||
/* support_copy_file preserves the source mode, so the victim stays
|
||||
executable and the modules readable; no chmod is needed. */
|
||||
support_copy_file (good_src, good_dst);
|
||||
support_copy_file (evil_src, evil_dst);
|
||||
support_copy_file (victim_src, BASE "/a/b/victim");
|
||||
|
||||
unlink (BASE "/a/b/sub");
|
||||
xsymlink (BASE "/x1/x2/x3/x4/x5/x6", BASE "/a/b/sub");
|
||||
|
||||
free (good_src);
|
||||
free (evil_src);
|
||||
free (victim_src);
|
||||
free (good_dir);
|
||||
free (good_dst);
|
||||
free (evil_dir);
|
||||
free (evil_dst);
|
||||
}
|
||||
#define PREPARE do_prepare
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Control run: in normal mode $ORIGIN is honored without the trusted check,
|
||||
so the raw rpath resolves through "sub" and the attacker copy is
|
||||
loaded. */
|
||||
{
|
||||
char *const env[] = { NULL };
|
||||
int rc = run_victim (env);
|
||||
if (rc != ORIGIN_SECURE_STATUS_ATTACKER)
|
||||
FAIL_EXIT1 ("control run returned status %d, expected %d (attacker "
|
||||
"copy, not secure): the $ORIGIN layout does not reproduce "
|
||||
"the divergence between the raw and the normalized rpath",
|
||||
rc, ORIGIN_SECURE_STATUS_ATTACKER);
|
||||
}
|
||||
|
||||
/* Secure run: force AT_SECURE. A fixed loader normalizes the rpath to the
|
||||
trusted SLIBDIR/SUBDIR and loads the trusted copy; a loader with the bug
|
||||
opens the raw path, resolves "sub", and loads the attacker copy. */
|
||||
{
|
||||
char *const env[] = { (char *) "GLIBC_TUNABLES=glibc.rtld.enable_secure=1",
|
||||
NULL };
|
||||
int rc = run_victim (env);
|
||||
switch (rc)
|
||||
{
|
||||
/* Secure, trusted copy loaded via the normalized rpath: fixed. */
|
||||
case ORIGIN_SECURE_STATUS_SECURE:
|
||||
break;
|
||||
|
||||
/* Secure, attacker copy loaded: the raw rpath was opened. */
|
||||
case ORIGIN_SECURE_STATUS_SECURE | ORIGIN_SECURE_STATUS_ATTACKER:
|
||||
FAIL_EXIT1 ("secure-mode loader resolved the un-normalized rpath "
|
||||
"through the attacker symlink (bug 34360)");
|
||||
|
||||
/* Not secure, attacker copy: exactly what the control run produced, so
|
||||
the tunable did not engage and this run says nothing about the
|
||||
trusted-path handling. */
|
||||
case ORIGIN_SECURE_STATUS_ATTACKER:
|
||||
FAIL_UNSUPPORTED ("glibc.rtld.enable_secure=1 did not enable "
|
||||
"secure mode (victim status %d)", rc);
|
||||
|
||||
/* Not secure, yet the trusted copy was loaded, which is reachable only
|
||||
through the normalized rpath, and only a secure loader normalizes it.
|
||||
Fail rather than report UNSUPPORTED. */
|
||||
case ORIGIN_SECURE_STATUS_NONE:
|
||||
FAIL_EXIT1 ("secure run loaded the trusted copy but the victim "
|
||||
"reports not being secure: __libc_enable_secure is no "
|
||||
"longer a valid proxy for secure mode");
|
||||
|
||||
/* Neither copy loaded: since the trusted copy is reachable only through
|
||||
the normalized rpath, this means the rpath entry was not honored at
|
||||
all. */
|
||||
default:
|
||||
FAIL_EXIT1 ("secure run did not load the module via the normalized "
|
||||
"rpath (victim status %d)", rc);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -1,41 +0,0 @@
|
||||
/* Definitions shared by the tst-origin-secure test, its victim and modules.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _TST_ORIGIN_SECURE_H
|
||||
#define _TST_ORIGIN_SECURE_H 1
|
||||
|
||||
enum
|
||||
{
|
||||
ORIGIN_SECURE_ID_TRUSTED = 1, /* The copy installed in the trusted
|
||||
SLIBDIR. */
|
||||
ORIGIN_SECURE_ID_ATTACKER = 2, /* The copy reachable only by resolving the
|
||||
"sub" symlink. */
|
||||
};
|
||||
|
||||
extern int origin_secure_id (void);
|
||||
|
||||
enum
|
||||
{
|
||||
ORIGIN_SECURE_STATUS_NONE = 0,
|
||||
ORIGIN_SECURE_STATUS_ATTACKER = 1 << 0, /* The victim loaded attacker
|
||||
rather than the trusted. */
|
||||
ORIGIN_SECURE_STATUS_SECURE = 1 << 1, /* The loader ran the victim in
|
||||
secure mode. */
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
/* Check if RPATH/RUNPATH is allowed for static-pie.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
int foo (void) { return 42; }
|
||||
@@ -1,38 +0,0 @@
|
||||
/* Check if RPATH/RUNPATH is allowed for static-pie.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/xdlfcn.h>
|
||||
|
||||
/* The module is placed in the directory named by the RUNPATH of this
|
||||
program (tst-pie-rpath-static.root/tst-pie-rpath-static.script), so
|
||||
dlopen can only find it if the RUNPATH is honoured. */
|
||||
#define LIBNAME "tst-pie-rpath-mod.so"
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
void *h = xdlopen (LIBNAME, RTLD_NOW);
|
||||
int (*foo)(void) = xdlsym (h, "foo");
|
||||
TEST_COMPARE (foo (), 42);
|
||||
xdlclose (h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -1,2 +0,0 @@
|
||||
mkdirp 0755 $B/elf/tst-pie-rpath-static-subdir
|
||||
cp $B/elf/tst-pie-rpath-mod.so $B/elf/tst-pie-rpath-static-subdir/tst-pie-rpath-mod.so
|
||||
@@ -74,7 +74,7 @@ if [ $fail -ne 0 ]; then
|
||||
echo "Test FAILED"
|
||||
cat "${debug_output}"
|
||||
rm -f "${debug_output}"
|
||||
exit $fail
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Test PASSED"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
#include "tst-tunables-seal.c"
|
||||
@@ -1,75 +0,0 @@
|
||||
/* Verify that string tunables are sealed after early startup.
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This generic test is parameterized by TST_SEAL_TUNABLE_NAME, the name of
|
||||
a glibc.cpu string tunable for the target ABI. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
|
||||
#ifdef TST_SEAL_TUNABLE_NAME
|
||||
|
||||
# include <string.h>
|
||||
# include <unistd.h>
|
||||
# include <support/capture_subprocess.h>
|
||||
|
||||
# define TUNABLE_NAMESPACE cpu
|
||||
# include <elf/dl-tunables.h>
|
||||
|
||||
# define STRINGIFY(x) STRINGIFY1 (x)
|
||||
# define STRINGIFY1(x) #x
|
||||
|
||||
/* The full internal name of the tunable, e.g. "glibc.cpu.hwcaps", as
|
||||
embedded in the fatal error message. */
|
||||
# define TST_SEAL_TUNABLE_FULLNAME \
|
||||
STRINGIFY (TOP_NAMESPACE) "." STRINGIFY (TUNABLE_NAMESPACE) "." \
|
||||
STRINGIFY (TST_SEAL_TUNABLE_NAME)
|
||||
|
||||
static void
|
||||
read_sealed_tunable (void *closure)
|
||||
{
|
||||
TUNABLE_GET (TST_SEAL_TUNABLE_NAME, struct tunable_str_t *, NULL);
|
||||
/* Not reached: the read above is a fatal error. Exit successfully so
|
||||
that a missing diagnostic is caught as an unexpected exit status. */
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#endif /* TST_SEAL_TUNABLE_NAME */
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
#ifndef TST_SEAL_TUNABLE_NAME
|
||||
FAIL_UNSUPPORTED ("the target ABI has no glibc.cpu string tunable");
|
||||
#else
|
||||
struct support_capture_subprocess result
|
||||
= support_capture_subprocess (read_sealed_tunable, NULL);
|
||||
|
||||
support_capture_subprocess_check (&result, "tst-tunables-seal", 127,
|
||||
sc_allow_stderr);
|
||||
TEST_VERIFY (strstr (result.err.buffer,
|
||||
"Fatal glibc error: " TST_SEAL_TUNABLE_FULLNAME
|
||||
": string tunable read after process initialization")
|
||||
!= NULL);
|
||||
|
||||
support_capture_subprocess_free (&result);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -1,81 +0,0 @@
|
||||
/* 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
|
||||
#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);
|
||||
int32_t perturb = TUNABLE_GET_FULL (glibc, malloc, perturb, int32_t, NULL);
|
||||
size_t mmap_threshold = TUNABLE_GET_FULL (glibc, malloc, mmap_threshold, size_t, NULL);
|
||||
size_t trim_threshold = TUNABLE_GET_FULL (glibc, malloc, trim_threshold, size_t, NULL);
|
||||
|
||||
printf("tcache count is %zu (should be 5, from env)\n", tcache_count);
|
||||
TEST_COMPARE ((long)tcache_count, 5);
|
||||
printf("tcache max is %zu (should be 4, from /etc)\n", tcache_max);
|
||||
TEST_COMPARE ((long)tcache_max, 4);
|
||||
|
||||
/* This is set by the environment but blocked by the config. */
|
||||
printf("perturb is %" PRId32 " (should be 42, from /etc)\n",
|
||||
perturb);
|
||||
TEST_COMPARE (perturb, 42);
|
||||
|
||||
/* This is blocked by the general config, enabled by filter, set in env. */
|
||||
printf("mmap_threshold is %zu (should be 10002, from env)\n",
|
||||
mmap_threshold);
|
||||
TEST_COMPARE ((long)mmap_threshold, 10002);
|
||||
|
||||
/* This is allowed by the general config, blocked by filter, set in env. */
|
||||
printf("trim_threshold is %zu (should be 10001, from filter)\n",
|
||||
trim_threshold);
|
||||
TEST_COMPARE ((long)trim_threshold, 10001);
|
||||
|
||||
/* Interaction with legacy environment-variable aliases (MALLOC_*). */
|
||||
int32_t mmap_max = TUNABLE_GET_FULL (glibc, malloc, mmap_max, int32_t, NULL);
|
||||
size_t top_pad = TUNABLE_GET_FULL (glibc, malloc, top_pad, size_t, NULL);
|
||||
size_t arena_max = TUNABLE_GET_FULL (glibc, malloc, arena_max, size_t, NULL);
|
||||
|
||||
/* Overridable cache default (100); the MALLOC_MMAP_MAX_ alias overrides
|
||||
it, just like GLIBC_TUNABLES would. */
|
||||
printf("mmap_max is %" PRId32 " (should be 200, from MALLOC_MMAP_MAX_ alias)"
|
||||
"\n",
|
||||
mmap_max);
|
||||
TEST_COMPARE (mmap_max, 200);
|
||||
|
||||
/* Nonoverridable cache default (100); the MALLOC_TOP_PAD_ alias must not
|
||||
override it. */
|
||||
printf("top_pad is %zu (should be 100, from /etc nonoverridable)\n",
|
||||
top_pad);
|
||||
TEST_COMPARE ((long)top_pad, 100);
|
||||
|
||||
/* Set both by GLIBC_TUNABLES (300) and by the MALLOC_ARENA_MAX alias
|
||||
(400); the canonical GLIBC_TUNABLES form wins. */
|
||||
printf("arena_max is %zu (should be 300, from GLIBC_TUNABLES)\n", arena_max);
|
||||
TEST_COMPARE ((long)arena_max, 300);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -1,31 +0,0 @@
|
||||
# These test the parser for both the overridability characters as well as
|
||||
# tunables that either never exist, or only exist on some platforms.
|
||||
-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
|
||||
|
||||
-glibc.malloc.perturb=42
|
||||
-glibc.malloc.mmap_threshold=10000
|
||||
overridable glibc.malloc.trim_threshold=10000
|
||||
|
||||
# Interaction with legacy environment-variable aliases (MALLOC_*), checked
|
||||
# in the test case:
|
||||
# - mmap_max: overridable cache default, must be overridable by the
|
||||
# MALLOC_MMAP_MAX_ alias just like by GLIBC_TUNABLES.
|
||||
# - top_pad: nonoverridable cache default, must NOT be overridable by the
|
||||
# MALLOC_TOP_PAD_ alias.
|
||||
glibc.malloc.mmap_max=100
|
||||
-glibc.malloc.top_pad=100
|
||||
|
||||
[proc:/bin/ls]
|
||||
glibc.malloc.tcache_max=7
|
||||
|
||||
[proc:tst-tunconf1]
|
||||
glibc.malloc.tcache_max=4
|
||||
+glibc.malloc.mmap_threshold=10001
|
||||
nonoverridable glibc.malloc.trim_threshold=10001
|
||||
-440
@@ -1,440 +0,0 @@
|
||||
/* Manage /etc/tunables.*
|
||||
Copyright (C) 1999-2023 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <alloca.h>
|
||||
#include <argp.h>
|
||||
#include <assert.h>
|
||||
#include <error.h>
|
||||
#include <inttypes.h>
|
||||
#include <glob.h>
|
||||
#include <libgen.h>
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <programs/xmalloc.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio_ext.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define TUNABLES_INTERNAL
|
||||
#include <elf/dl-tunables.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ldconfig.h>
|
||||
#include <dl-cache.h>
|
||||
#include <version.h>
|
||||
#include <stringtable.h>
|
||||
#include <array_length.h>
|
||||
|
||||
#include "tunconf.h"
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef TUNABLES_CONF
|
||||
# define TUNABLES_CONF SYSCONFDIR "/tunables.conf"
|
||||
#endif
|
||||
|
||||
#ifndef TUNABLES_CACHE
|
||||
# define TUNABLES_CACHE SYSCONFDIR "/tunables.cache"
|
||||
#endif
|
||||
|
||||
/* Tunable Override Policies. */
|
||||
typedef enum {
|
||||
TOP_ALLOW = 0, /* let the environment variable override */
|
||||
TOP_DENY /* no override allowed */
|
||||
} TOP;
|
||||
|
||||
struct tunable_entry_int {
|
||||
struct stringtable_entry *name;
|
||||
struct stringtable_entry *value;
|
||||
struct stringtable_entry *filter;
|
||||
TOP top;
|
||||
bool exclude_secure:1;
|
||||
bool exclude_nonsecure:1;
|
||||
int tunable_id;
|
||||
unsigned int value_is_negative:1;
|
||||
unsigned int value_was_parsed:1;
|
||||
unsigned long long value_ull;
|
||||
signed long long value_sll;
|
||||
long filter_flags;
|
||||
|
||||
struct tunable_entry_int *next;
|
||||
};
|
||||
|
||||
struct tunable_entry_int *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)
|
||||
{
|
||||
error_at_line (0, 0, filename, lineno,
|
||||
"syntax error, filter line ignored: `%s' (missing ':')\n",
|
||||
line);
|
||||
return;
|
||||
}
|
||||
if (right_bracket == NULL)
|
||||
{
|
||||
error_at_line (0, 0, filename, lineno,
|
||||
"syntax error, filter line ignored: `%s' (missing ']')\n",
|
||||
line);
|
||||
return;
|
||||
}
|
||||
|
||||
if (filter_string != NULL)
|
||||
{
|
||||
clear_filter ();
|
||||
}
|
||||
|
||||
if (colon - line - 1 == 4 && memcmp ("proc", line + 1, 4) == 0)
|
||||
{
|
||||
/* Consider this example: [proc:foo] ..." */
|
||||
/* We allocate 4 bytes, [0] through [3]. */
|
||||
filter_string = (char *) xmalloc (right_bracket - colon);
|
||||
/* We copy "foo" for 3 bytes, [0] through [2]. */
|
||||
memcpy (filter_string, colon + 1, right_bracket - colon - 1);
|
||||
/* [3] = 0 so now "foo\0". */
|
||||
filter_string [right_bracket - colon - 1] = 0;
|
||||
filter_flags = TUNCONF_FILTER_PERPROC;
|
||||
}
|
||||
|
||||
else
|
||||
error_at_line (0, 0, filename, lineno,
|
||||
"unrecognized filter `%.*s', ignored\n",
|
||||
(int)(colon - line - 1), line + 1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_tunable (char *line, const char *filename, int lineno)
|
||||
{
|
||||
TOP top = TOP_ALLOW;
|
||||
char *name;
|
||||
char *value;
|
||||
char *eq;
|
||||
char *orig_line;
|
||||
struct tunable_entry_int *entry;
|
||||
int i, id;
|
||||
static struct tunable_entry_int **entry_list_next = &entry_list;
|
||||
bool exclude_secure = 1, exclude_nonsecure = 0;
|
||||
|
||||
/* Denotes file boundaries. */
|
||||
if (line == NULL)
|
||||
{
|
||||
clear_filter();
|
||||
return;
|
||||
}
|
||||
|
||||
orig_line = line;
|
||||
|
||||
/* Leading whitespace has already been stripped. */
|
||||
|
||||
/* Canonicalize the line. */
|
||||
for (i=0; line[i]; i++)
|
||||
{
|
||||
if (line[i] == '\t')
|
||||
line[i] = ' ';
|
||||
if (line[i] == '\n' || line[i] == '\r')
|
||||
{
|
||||
line[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse modifiers. */
|
||||
while (*line)
|
||||
{
|
||||
int prefix_len;
|
||||
|
||||
#define TUN_PREFIX(s) \
|
||||
prefix_len = sizeof(s) - 1, \
|
||||
strncmp (line, s " ", prefix_len + 1) == 0
|
||||
|
||||
if (TUN_PREFIX("overridable"))
|
||||
{
|
||||
top = TOP_ALLOW;
|
||||
/* The line++ below skips the space. */
|
||||
line += prefix_len;
|
||||
}
|
||||
else if (TUN_PREFIX ("nonoverridable"))
|
||||
{
|
||||
top = TOP_DENY;
|
||||
line += prefix_len;
|
||||
}
|
||||
else if (TUN_PREFIX ("onlysecure"))
|
||||
{
|
||||
exclude_nonsecure = 1;
|
||||
exclude_secure = 0;
|
||||
line += prefix_len;
|
||||
}
|
||||
else if (TUN_PREFIX ("nonsecure"))
|
||||
{
|
||||
exclude_secure = 1;
|
||||
exclude_nonsecure = 0;
|
||||
line += prefix_len;
|
||||
}
|
||||
else if (TUN_PREFIX ("anysecure"))
|
||||
{
|
||||
exclude_secure = 0;
|
||||
exclude_nonsecure = 0;
|
||||
line += prefix_len;
|
||||
}
|
||||
else switch (*line)
|
||||
{
|
||||
case '+':
|
||||
top = TOP_ALLOW;
|
||||
break;
|
||||
case '-':
|
||||
top = TOP_DENY;
|
||||
break;
|
||||
case '@':
|
||||
exclude_nonsecure = 1;
|
||||
exclude_secure = 0;
|
||||
break;
|
||||
case '$':
|
||||
exclude_nonsecure = 0;
|
||||
exclude_secure = 1;
|
||||
break;
|
||||
case '*':
|
||||
exclude_nonsecure = 0;
|
||||
exclude_secure = 0;
|
||||
break;
|
||||
case '[':
|
||||
parse_filter (line, filename, lineno);
|
||||
return;
|
||||
case ' ':
|
||||
break;
|
||||
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
line ++;
|
||||
}
|
||||
done:
|
||||
|
||||
/* NAME now points to the start of the tunable name. */
|
||||
name = line;
|
||||
|
||||
/* Look for the '=' separator. */
|
||||
eq = strchr (line, '=');
|
||||
if (eq == NULL)
|
||||
{
|
||||
error_at_line (0, 0, filename, lineno,
|
||||
"syntax error, line ignored: `%s' (missing '=')",
|
||||
orig_line);
|
||||
return;
|
||||
}
|
||||
|
||||
if (eq == name)
|
||||
{
|
||||
error_at_line (0, 0, filename, lineno,
|
||||
"syntax error, line ignored: `%s' (missing tunable name)",
|
||||
orig_line);
|
||||
return;
|
||||
}
|
||||
|
||||
/* At this point, EQ actually points to '='. */
|
||||
value = eq + 1;
|
||||
|
||||
while (*value && isspace(*value))
|
||||
value ++;
|
||||
|
||||
if (*value == 0)
|
||||
{
|
||||
error_at_line (0, 0, filename, lineno,
|
||||
"syntax error, line ignored: `%s' (missing value)",
|
||||
orig_line);
|
||||
return;
|
||||
}
|
||||
|
||||
/* VALUE now points to the start of the value. */
|
||||
|
||||
/* Split the string into name and value c-strings. */
|
||||
*eq = 0;
|
||||
/* Trim trailing whitespace off NAME. */
|
||||
while (*name && isspace (name[strlen(name)-1]))
|
||||
name[strlen(name)-1] = 0;
|
||||
/* Trim trailing whitespace off VALUE. */
|
||||
while (*value && isspace (value[strlen(value)-1]))
|
||||
value[strlen(value)-1] = 0;
|
||||
|
||||
id = -1;
|
||||
for (i = 0; i < array_length (tunable_list); i ++)
|
||||
if (strcmp (tunable_list[i].name, name) == 0)
|
||||
{
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
if (id == -1)
|
||||
printf ("%s:%d: Warning: tunable %s not recognized.\n",
|
||||
filename, lineno, name);
|
||||
|
||||
entry = (struct tunable_entry_int *) xcalloc (sizeof (struct tunable_entry_int), 1);
|
||||
entry->name = cache_store_string (name);
|
||||
entry->value = cache_store_string (value);
|
||||
entry->tunable_id = id;
|
||||
entry->top = top;
|
||||
entry->exclude_secure = exclude_secure;
|
||||
entry->exclude_nonsecure = exclude_nonsecure;
|
||||
|
||||
if (filter_flags)
|
||||
{
|
||||
entry->filter_flags = filter_flags;
|
||||
entry->filter = cache_store_string (filter_string);
|
||||
}
|
||||
|
||||
if (value[0] == '-')
|
||||
{
|
||||
entry->value_is_negative = 1;
|
||||
if (sscanf (value, "%lld", &entry->value_sll) == 1)
|
||||
entry->value_was_parsed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->value_is_negative = 0;
|
||||
if (sscanf (value, "%llu", &entry->value_ull) == 1)
|
||||
entry->value_was_parsed = 1;
|
||||
}
|
||||
|
||||
*entry_list_next = entry;
|
||||
entry_list_next = & (entry->next);
|
||||
}
|
||||
|
||||
void
|
||||
parse_tunconf (const char *filename, char *opt_chroot)
|
||||
{
|
||||
ldconfig_parse_config (filename, opt_chroot, add_tunable);
|
||||
}
|
||||
|
||||
struct tunable_header_cached *
|
||||
get_tunconf_ext (uint32_t string_table_offset)
|
||||
{
|
||||
struct tunable_entry_int *tei;
|
||||
struct tunable_header_cached *thc;
|
||||
size_t count;
|
||||
size_t size;
|
||||
|
||||
/* First, count the number of entries we have. */
|
||||
tei = entry_list;
|
||||
count = 0;
|
||||
while (tei != NULL)
|
||||
{
|
||||
++ count;
|
||||
tei = tei->next;
|
||||
}
|
||||
if (count == 0)
|
||||
return NULL;
|
||||
|
||||
/* Allocate enough space for the whole cached block. */
|
||||
size = sizeof (struct tunable_header_cached)
|
||||
+ sizeof (struct tunable_entry_cached) * count;
|
||||
thc = (struct tunable_header_cached *) xmalloc (size);
|
||||
|
||||
/* Now, fill in the structures. */
|
||||
|
||||
thc->signature = TUNCONF_SIGNATURE;
|
||||
thc->version = TUNCONF_VERSION;
|
||||
thc->num_tunables = count;
|
||||
thc->unused_1 = 0;
|
||||
|
||||
tei = entry_list;
|
||||
count = 0;
|
||||
while (tei != NULL)
|
||||
{
|
||||
struct tunable_entry_cached *tec;
|
||||
|
||||
tec = & ( thc->tunables[count] );
|
||||
|
||||
tec->flags = 0;
|
||||
if (tei->value_was_parsed)
|
||||
tec->flags |= TUNCONF_FLAG_PARSED;
|
||||
if (tei->value_is_negative)
|
||||
tec->flags |= TUNCONF_FLAG_NEGATIVE;
|
||||
switch (tei->top)
|
||||
{
|
||||
case TOP_ALLOW:
|
||||
tec->flags |= TUNCONF_OVERRIDE_ALLOW;
|
||||
break;
|
||||
case TOP_DENY:
|
||||
tec->flags |= TUNCONF_OVERRIDE_DENY;
|
||||
break;
|
||||
}
|
||||
if (tei->exclude_secure)
|
||||
tec->flags |= TUNCONF_EXCLUDE_SECURE;
|
||||
if (tei->exclude_nonsecure)
|
||||
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;
|
||||
|
||||
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;
|
||||
else
|
||||
tec->parsed_value = (uint64_t) tei->value_ull;
|
||||
|
||||
++ count;
|
||||
tei = tei->next;
|
||||
}
|
||||
|
||||
return thc;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#define TUNCONF_SIGNATURE 0x7c3ba94f
|
||||
#define TUNCONF_VERSION 0x01000000
|
||||
|
||||
#define TUNCONF_FLAG_PARSED 0x00000001
|
||||
#define TUNCONF_FLAG_NEGATIVE 0x00000002
|
||||
|
||||
#define TUNCONF_FLAG_OVERRIDABLE 0x0000000C
|
||||
#define TUNCONF_OVERRIDE_DENY 0x00000004
|
||||
#define TUNCONF_OVERRIDE_ALLOW 0x00000000
|
||||
|
||||
#define TUNCONF_EXCLUDE_SECURE 0x00000010
|
||||
#define TUNCONF_EXCLUDE_UNSECURE 0x00000020
|
||||
|
||||
#define TUNCONF_FLAG_FILTER 0x0000ff00
|
||||
#define TUNCONF_FILTER_NONE 0x00000000
|
||||
#define TUNCONF_FILTER_PERPROC 0x00000100
|
||||
|
||||
/* An array of [num_tunables] of these follows the below. */
|
||||
struct tunable_entry_cached {
|
||||
uint32_t flags;
|
||||
uint32_t tunable_id;
|
||||
uint32_t name_offset;
|
||||
uint32_t value_offset;
|
||||
uint32_t flag_offset;
|
||||
uint32_t unused_1; /* for alignment */
|
||||
uint64_t parsed_value;
|
||||
};
|
||||
|
||||
/* One of these is at the beginning of the tunable data block. */
|
||||
struct tunable_header_cached {
|
||||
uint32_t signature;
|
||||
uint32_t version;
|
||||
uint32_t num_tunables;
|
||||
uint32_t unused_1; /* for alignment */
|
||||
struct tunable_entry_cached tunables[0 /* num_tunables */];
|
||||
};
|
||||
|
||||
void parse_tunconf (const char *filename, char *opt_chroot);
|
||||
|
||||
struct tunable_header_cached * get_tunconf_ext (uint32_t str_offset);
|
||||
#define TUNCONF_SIZE(thc_p) (sizeof(struct tunable_header_cached) \
|
||||
+ thc_p->num_tunables * sizeof (struct tunable_entry_cached))
|
||||
|
||||
extern const struct tunable_header_cached *
|
||||
_dl_load_cache_tunables (const char **data);
|
||||
@@ -17,7 +17,6 @@
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libc-diag.h>
|
||||
|
||||
#define __no_type_class -1
|
||||
#define __void_type_class 0
|
||||
@@ -62,17 +61,12 @@ do_test (void)
|
||||
struct { int a; } __record_type;
|
||||
union { int a; int b; } __union_type;
|
||||
|
||||
/* clang warns that the variables are uninitializedd, but the builtin
|
||||
only inspects the type of its operand and never evaluates it. */
|
||||
DIAG_PUSH_NEEDS_COMMENT_CLANG;
|
||||
DIAG_IGNORE_NEEDS_COMMENT_CLANG (23, "-Wuninitialized");
|
||||
result |= TEST (integer);
|
||||
result |= TEST (pointer);
|
||||
result |= TEST (real);
|
||||
result |= TEST (complex);
|
||||
result |= TEST (record);
|
||||
result |= TEST (union);
|
||||
DIAG_POP_NEEDS_COMMENT_CLANG;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -257,10 +257,3 @@ $(addprefix $(objpfx),$(tests-static) $(xtests-static)): $(srcdir)/libpthread_sy
|
||||
else
|
||||
$(addprefix $(objpfx),$(tests) $(test-srcs)): $(srcdir)/libpthread_syms.a $(objpfx)libpthread.a
|
||||
endif
|
||||
|
||||
# Like rt, these tests prefer to be run serially.
|
||||
ifeq (yes-yes,$(run-built-tests)-$(serialize-tests))
|
||||
ifneq ($(filter %tests,$(MAKECMDGOALS)),)
|
||||
.NOTPARALLEL:
|
||||
endif
|
||||
endif
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ __file_name_lookup_at (int fd, int at_flags,
|
||||
file_t dir = result;
|
||||
|
||||
err = __dir_mkfile (dir, orig_flags & ~(O_TMPFILE | O_DIRECTORY),
|
||||
mode & ~_hurd_umask, &result);
|
||||
mode, &result);
|
||||
__mach_port_deallocate (__mach_task_self (), dir);
|
||||
if (err)
|
||||
{
|
||||
|
||||
+1
-4
@@ -76,8 +76,7 @@ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
|
||||
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
|
||||
bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
|
||||
bug-iconv13 bug-iconv14 bug-iconv15 \
|
||||
tst-iconv-iso-2022-cn-ext tst-bug33980 \
|
||||
tst-jisx0213-progress
|
||||
tst-iconv-iso-2022-cn-ext tst-bug33980
|
||||
ifeq ($(have-thread-library),yes)
|
||||
tests += bug-iconv3
|
||||
endif
|
||||
@@ -336,8 +335,6 @@ $(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules))
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)tst-bug33980.out: $(addprefix $(objpfx), $(gconv-modules)) \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)tst-jisx0213-progress.out: \
|
||||
$(addprefix $(objpfx), $(gconv-modules)) $(addprefix $(objpfx),$(modules.so))
|
||||
|
||||
$(objpfx)iconv-test.out: run-iconv-test.sh \
|
||||
$(addprefix $(objpfx), $(gconv-modules)) \
|
||||
|
||||
@@ -224,9 +224,6 @@
|
||||
STANDARD_FROM_LOOP_ERR_HANDLER (1); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
/* There was a pending character. Clear it. */ \
|
||||
*statep = 0; \
|
||||
\
|
||||
put32 (outptr, ch); \
|
||||
outptr += 4; \
|
||||
|
||||
@@ -226,9 +226,6 @@
|
||||
STANDARD_FROM_LOOP_ERR_HANDLER (1); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
/* There was a pending character. Clear it. */ \
|
||||
*statep = 0; \
|
||||
\
|
||||
put32 (outptr, ch); \
|
||||
outptr += 4; \
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/* Test JISX0213 combining character conversion progress (bug 34556, bug 34568).
|
||||
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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Certain JISX0213 byte sequences map to a combining sequence, for
|
||||
example U+304B (HIRAGANA LETTER KA) followed by U+309A (COMBINING
|
||||
SEMI-VOICED SOUND MARK). When converting to internal encoding
|
||||
(actually UTF-32) with a small output buffer, the first code point
|
||||
is emitted and the second is queued in the converter state. This
|
||||
test verifies that the queued code point is consumed exactly once
|
||||
on retry, so that the conversion makes progress and terminates. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
|
||||
static void
|
||||
test_one (const char *charset, const char *input, size_t outbufsize)
|
||||
{
|
||||
printf ("info: %s: testing output buffer size %zu\n", charset, outbufsize);
|
||||
|
||||
/* Expected UTF-32 output. */
|
||||
static const wchar_t expected[] = { 0x304b, 0x309a, 'A' };
|
||||
|
||||
/* Use WCHAR_T encoding to avoid the BOM. */
|
||||
iconv_t cd = iconv_open ("WCHAR_T", charset);
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
char result[64];
|
||||
size_t result_len = 0;
|
||||
|
||||
char *inptr = (char *) input;
|
||||
size_t inleft = strlen (input);
|
||||
|
||||
char outbuf[64];
|
||||
|
||||
int iterations = 0;
|
||||
while (inleft > 0)
|
||||
{
|
||||
char *outptr = outbuf;
|
||||
size_t outleft = outbufsize;
|
||||
size_t inleft_before = inleft;
|
||||
|
||||
size_t ret = iconv (cd, &inptr, &inleft, &outptr, &outleft);
|
||||
size_t produced = outptr - outbuf;
|
||||
|
||||
TEST_VERIFY_EXIT (result_len + produced <= sizeof (result));
|
||||
memcpy (result + result_len, outbuf, produced);
|
||||
result_len += produced;
|
||||
|
||||
if (ret == (size_t) -1 && errno == E2BIG)
|
||||
{
|
||||
if (produced == 0 && inleft == inleft_before)
|
||||
{
|
||||
/* Output buffer too small for a single code point. */
|
||||
TEST_VERIFY_EXIT (outbufsize < 4);
|
||||
break;
|
||||
}
|
||||
/* Bound iterations to detect non-progress bugs. */
|
||||
if (++iterations < 10)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
FAIL ("%s: no progress", charset);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (ret == (size_t) -1)
|
||||
FAIL_EXIT1 ("outbufsize %zu: iconv: %m", outbufsize);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Flush pending converter state. */
|
||||
{
|
||||
char *outptr = outbuf;
|
||||
size_t outleft = outbufsize;
|
||||
size_t ret = iconv (cd, NULL, NULL, &outptr, &outleft);
|
||||
TEST_VERIFY (ret == 0);
|
||||
size_t produced = outptr - outbuf;
|
||||
memcpy (result + result_len, outbuf, produced);
|
||||
result_len += produced;
|
||||
}
|
||||
|
||||
if (outbufsize >= 4)
|
||||
{
|
||||
TEST_COMPARE (inleft, 0);
|
||||
TEST_COMPARE_BLOB (result, result_len,
|
||||
expected, sizeof (expected));
|
||||
}
|
||||
|
||||
out:
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) == 0);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
for (size_t outbufsize = 1; outbufsize <= 16; outbufsize++)
|
||||
{
|
||||
test_one ("EUC-JISX0213", "\244\367A", outbufsize);
|
||||
test_one ("SHIFT_JISX0213", "\202\365A", outbufsize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+4
-2
@@ -20,9 +20,11 @@ extern int __fcntl (int __fd, int __cmd, ...);
|
||||
libc_hidden_proto (__fcntl)
|
||||
extern int __fcntl64 (int __fd, int __cmd, ...) attribute_hidden;
|
||||
libc_hidden_proto (__fcntl64)
|
||||
extern int __openat (int __fd, const char *__file, int __oflag, ...);
|
||||
extern int __openat (int __fd, const char *__file, int __oflag, ...)
|
||||
__nonnull ((2));
|
||||
libc_hidden_proto (__openat)
|
||||
extern int __openat64 (int __fd, const char *__file, int __oflag, ...);
|
||||
extern int __openat64 (int __fd, const char *__file, int __oflag, ...)
|
||||
__nonnull ((2));
|
||||
libc_hidden_proto (__openat64)
|
||||
|
||||
extern int __open_2 (const char *__path, int __oflag);
|
||||
|
||||
+1
-1
@@ -529,7 +529,7 @@
|
||||
/* Major and minor version number of the GNU C library package. Use
|
||||
these macros to test for features in specific releases. */
|
||||
#define __GLIBC__ 2
|
||||
#define __GLIBC_MINOR__ 44
|
||||
#define __GLIBC_MINOR__ 43
|
||||
|
||||
#define __GLIBC_PREREQ(maj, min) \
|
||||
((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
|
||||
|
||||
@@ -194,6 +194,9 @@ struct link_map
|
||||
the l_libname list. */
|
||||
unsigned int l_faked:1; /* Nonzero if this is a faked descriptor
|
||||
without associated file. */
|
||||
unsigned int l_need_tls_init:1; /* Nonzero if GL(dl_init_static_tls)
|
||||
should be called on this link map
|
||||
when relocation finishes. */
|
||||
unsigned int l_auditing:1; /* Nonzero if the DSO is used in auditing. */
|
||||
unsigned int l_audit_any_plt:1; /* Nonzero if at least one audit module
|
||||
is interested in the PLT interception.*/
|
||||
|
||||
@@ -65,9 +65,6 @@ extern int __xpg_sigpause (int sig);
|
||||
/* Allocate real-time signal with highest/lowest available priority. */
|
||||
extern int __libc_allocate_rtsig (int __high);
|
||||
|
||||
/* Similar to raise, but does not set errno. */
|
||||
extern int __raise_direct (int signo) attribute_hidden;
|
||||
|
||||
# if IS_IN (rtld)
|
||||
extern __typeof (__sigaction) __sigaction attribute_hidden;
|
||||
extern __typeof (__libc_sigaction) __libc_sigaction attribute_hidden;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
extern void __chk_fail (void) __attribute__ ((__noreturn__));
|
||||
libc_hidden_proto (__chk_fail)
|
||||
rtld_hidden_proto (__chk_fail)
|
||||
|
||||
/* If we are using redirects internally to support long double,
|
||||
we need to tweak some macros to ensure the PLT bypass tricks
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ extern int inet_pton (int __af, const char *__restrict __cp,
|
||||
|
||||
/* Convert a Internet address in binary network format for interface
|
||||
type AF in buffer starting at CP to presentation form and place
|
||||
result in buffer of length LEN starting at BUF. */
|
||||
result in buffer of length LEN astarting at BUF. */
|
||||
extern const char *inet_ntop (int __af, const void *__restrict __cp,
|
||||
char *__restrict __buf, socklen_t __len)
|
||||
__THROW;
|
||||
|
||||
@@ -91,8 +91,6 @@ enum
|
||||
#define IPPROTO_MPLS IPPROTO_MPLS
|
||||
IPPROTO_ETHERNET = 143, /* Ethernet-within-IPv6 Encapsulation. */
|
||||
#define IPPROTO_ETHERNET IPPROTO_ETHERNET
|
||||
IPPROTO_AGGFRAG = 144, /* AGGFRAG in ESP (RFC 9347). */
|
||||
#define IPPROTO_AGGFRAG IPPROTO_AGGFRAG
|
||||
IPPROTO_RAW = 255, /* Raw IP packets. */
|
||||
#define IPPROTO_RAW IPPROTO_RAW
|
||||
IPPROTO_SMC = 256, /* Shared Memory Communications. */
|
||||
|
||||
@@ -24,7 +24,7 @@ test_program_prefix=$2
|
||||
objpfx=$3
|
||||
|
||||
# Create the locale directories.
|
||||
mkdir -p ${objpfx}domaindir/existing-locale/LC_MESSAGES
|
||||
mkdir -p ${objpfx}localedir/existing-locale/LC_MESSAGES
|
||||
|
||||
msgfmt -o ${objpfx}domaindir/existing-locale/LC_MESSAGES/translit.mo \
|
||||
translit.po
|
||||
|
||||
+1
-1
@@ -309,7 +309,7 @@ tst-statvfs-ARGS = $(objpfx)tst-statvfs tst-statvfs.c /tmp
|
||||
|
||||
tst-open-tmpfile-ARGS = --test-dir=$(objpfx)
|
||||
|
||||
CFLAGS-ftwtest-time64.c += $(+time64-flags) -D_FILE_OFFSET_BITS=64
|
||||
CFLAGS-ftwtest-time64.c += -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
$(objpfx)ftwtest.out: ftwtest-sh $(objpfx)ftwtest
|
||||
|
||||
+8
-4
@@ -135,14 +135,18 @@ open64 (__fortify_clang_overload_arg (const char *, ,__path), int __oflag,
|
||||
|
||||
#ifdef __USE_ATFILE
|
||||
# ifndef __USE_FILE_OFFSET64
|
||||
extern int __openat_2 (int __fd, const char *__path, int __oflag);
|
||||
extern int __openat_2 (int __fd, const char *__path, int __oflag)
|
||||
__nonnull ((2));
|
||||
extern int __REDIRECT (__openat_alias, (int __fd, const char *__path,
|
||||
int __oflag, ...), openat);
|
||||
int __oflag, ...), openat)
|
||||
__nonnull ((2));
|
||||
# else
|
||||
extern int __REDIRECT (__openat_2, (int __fd, const char *__path,
|
||||
int __oflag), __openat64_2);
|
||||
int __oflag), __openat64_2)
|
||||
__nonnull ((2));
|
||||
extern int __REDIRECT (__openat_alias, (int __fd, const char *__path,
|
||||
int __oflag, ...), openat64);
|
||||
int __oflag, ...), openat64)
|
||||
__nonnull ((2));
|
||||
# endif
|
||||
|
||||
# ifdef __va_arg_pack_len
|
||||
|
||||
+5
-3
@@ -230,17 +230,19 @@ extern int open64 (const char *__file, int __oflag, ...) __nonnull ((1));
|
||||
This function is a cancellation point and therefore not marked with
|
||||
__THROW. */
|
||||
# ifndef __USE_FILE_OFFSET64
|
||||
extern int openat (int __fd, const char *__file, int __oflag, ...);
|
||||
extern int openat (int __fd, const char *__file, int __oflag, ...)
|
||||
__nonnull ((2));
|
||||
# else
|
||||
# ifdef __REDIRECT
|
||||
extern int __REDIRECT (openat, (int __fd, const char *__file, int __oflag,
|
||||
...), openat64);
|
||||
...), openat64) __nonnull ((2));
|
||||
# else
|
||||
# define openat openat64
|
||||
# endif
|
||||
# endif
|
||||
# ifdef __USE_LARGEFILE64
|
||||
extern int openat64 (int __fd, const char *__file, int __oflag, ...);
|
||||
extern int openat64 (int __fd, const char *__file, int __oflag, ...)
|
||||
__nonnull ((2));
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if !defined __OFF_T_MATCHES_OFF64_T \
|
||||
|| !defined __INO_T_MATCHES_INO64_T
|
||||
#ifndef __OFF_T_MATCHES_OFF64_T
|
||||
# include "io/fts-common.c"
|
||||
#endif
|
||||
|
||||
+1
-2
@@ -50,8 +50,7 @@ weak_alias (__fts64_read, fts64_read)
|
||||
weak_alias (__fts64_set, fts64_set)
|
||||
weak_alias (__fts64_children, fts64_children)
|
||||
|
||||
#if defined __OFF_T_MATCHES_OFF64_T \
|
||||
&& defined __INO_T_MATCHES_INO64_T
|
||||
#ifdef __OFF_T_MATCHES_OFF64_T
|
||||
weak_alias (__fts64_open, fts_open)
|
||||
weak_alias (__fts64_close, fts_close)
|
||||
weak_alias (__fts64_read, fts_read)
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <kernel_stat.h>
|
||||
|
||||
#if !XSTAT_IS_XSTAT64
|
||||
#ifndef __OFF_T_MATCHES_OFF64_T
|
||||
# include "ftw-common.c"
|
||||
|
||||
versioned_symbol (libc, __new_nftw, nftw, GLIBC_2_3_3);
|
||||
|
||||
+1
-4
@@ -31,9 +31,6 @@
|
||||
#define ftw __rename_ftw
|
||||
#define nftw __rename_nftw
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <kernel_stat.h>
|
||||
#include <shlib-compat.h>
|
||||
#include "ftw-common.c"
|
||||
|
||||
@@ -47,7 +44,7 @@ versioned_symbol (libc, __new_nftw64, nftw64, GLIBC_2_3_3);
|
||||
compat_symbol (libc, __old_nftw64, nftw64, GLIBC_2_1);
|
||||
#endif
|
||||
|
||||
#if XSTAT_IS_XSTAT64
|
||||
#ifdef __OFF_T_MATCHES_OFF64_T
|
||||
weak_alias (__ftw64, ftw)
|
||||
versioned_symbol (libc, __new_nftw64, nftw, GLIBC_2_3_3);
|
||||
# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_3_3)
|
||||
|
||||
+1
-1
@@ -370,7 +370,7 @@ extern int fchmod (int __fd, __mode_t __mode) __THROW;
|
||||
the directory FD is open on. */
|
||||
extern int fchmodat (int __fd, const char *__file, __mode_t __mode,
|
||||
int __flag)
|
||||
__THROW __wur;
|
||||
__THROW __nonnull ((2)) __wur;
|
||||
#endif /* Use ATFILE. */
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user