Compare commits

..
Author SHA1 Message Date
Florian Weimer e51a6bf18e malloc: Increase tcache fill count from 16 to 32
This avoids a regression in the omnetpp and xalancbmk benchmarks
of SPEC.  Apparently, these benchmarks are very sensitive to the
fill rate in malloc.

Suggested-by: Wilco Dijkstra <wilco.dijkstra@arm.com>
Tested-by: Wilco Dijkstra <wilco.dijkstra@arm.com>
2026-06-30 09:07:19 +02:00
Florian Weimer b50e24aea3 malloc: Only fill half of the tcache during batch allocation
This leaves room for subsequent frees.
2026-06-30 09:07:19 +02:00
Florian Weimer c0a1c6e06d malloc: Perform batched frees if tcache is full
Batched frees amortize the locking overhead once the tcache is full.
Previously, once the tcache slot was full, each free acquired the
arena lock.  With this change, neighboring tcache allocations in the
same arena re-use an arena lock that already exists.

Pass the tcache pointer to __libc_free_batch so that it is not
necessary to reload the tcache pointer after the _int_free_chunk
calls.
2026-06-30 09:07:19 +02:00
714 changed files with 29308 additions and 46522 deletions
File diff suppressed because it is too large Load Diff
+12 -8
View File
@@ -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
View File
@@ -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),)
+14 -198
View File
@@ -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.
+11 -79
View File
@@ -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)
+17 -172
View File
@@ -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
+14 -31
View File
@@ -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
View File
@@ -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
-19
View File
@@ -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
-18
View File
@@ -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
View File
@@ -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.
-5
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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)
+1 -2
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+4911 -3006
View File
File diff suppressed because it is too large Load Diff
+3446 -2004
View File
File diff suppressed because it is too large Load Diff
+3 -11
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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. */
-5
View File
@@ -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)
-5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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. */
+8
View File
@@ -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
View File
@@ -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
-118
View File
@@ -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 */
+4 -10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-1
View File
@@ -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. */
+5 -2
View File
@@ -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);
+2 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-43
View File
@@ -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);
}
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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}".*)
-142
View File
@@ -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>
-27
View File
@@ -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;
}
-40
View File
@@ -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")));
-137
View File
@@ -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
-125
View File
@@ -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
+3 -1
View File
@@ -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)
{
-28
View File
@@ -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;
}
-43
View File
@@ -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;
}
-203
View File
@@ -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>
-41
View File
@@ -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
-19
View File
@@ -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; }
-38
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -1 +0,0 @@
#include "tst-tunables-seal.c"
-75
View File
@@ -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>
-81
View File
@@ -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>
-31
View File
@@ -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
View File
View File
-440
View File
@@ -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;
}
-45
View File
@@ -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);
-6
View File
@@ -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;
}
-7
View File
@@ -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
View File
@@ -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
View File
@@ -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)) \
-3
View File
@@ -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; \
-3
View File
@@ -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; \
-124
View File
@@ -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
View File
@@ -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
View File
@@ -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))
+3
View File
@@ -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.*/
-3
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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;
-2
View File
@@ -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. */
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -2
View File
@@ -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
View File
@@ -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)
+1 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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