summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile358
-rw-r--r--elf/Versions26
-rw-r--r--elf/cache.c18
-rw-r--r--elf/chroot_canon.c2
-rw-r--r--elf/dl-addr-obj.c74
-rw-r--r--elf/dl-addr.c25
-rw-r--r--elf/dl-cache.c11
-rw-r--r--elf/dl-caller.c86
-rw-r--r--elf/dl-close.c38
-rw-r--r--elf/dl-conflict.c2
-rw-r--r--elf/dl-debug.c3
-rw-r--r--elf/dl-deps.c134
-rw-r--r--elf/dl-dst.h15
-rw-r--r--elf/dl-environ.c3
-rw-r--r--elf/dl-error-minimal.c23
-rw-r--r--elf/dl-error-skeleton.c239
-rw-r--r--elf/dl-error.c212
-rw-r--r--elf/dl-exception.c202
-rw-r--r--elf/dl-execstack.c3
-rw-r--r--elf/dl-fini.c109
-rw-r--r--elf/dl-fptr.c2
-rw-r--r--elf/dl-hwcaps.c38
-rw-r--r--elf/dl-hwcaps.h30
-rw-r--r--elf/dl-init.c3
-rw-r--r--elf/dl-iteratephdr.c3
-rw-r--r--elf/dl-libc.c86
-rw-r--r--elf/dl-load.c602
-rw-r--r--elf/dl-load.h2
-rw-r--r--elf/dl-lookup.c69
-rw-r--r--elf/dl-machine-reject-phdr.h2
-rw-r--r--elf/dl-map-segments.h22
-rw-r--r--elf/dl-minimal.c117
-rw-r--r--elf/dl-misc.c98
-rw-r--r--elf/dl-object.c4
-rw-r--r--elf/dl-open.c136
-rw-r--r--elf/dl-origin.c2
-rw-r--r--elf/dl-profile.c22
-rw-r--r--elf/dl-profstub.c2
-rw-r--r--elf/dl-reloc-static-pie.c68
-rw-r--r--elf/dl-reloc.c14
-rw-r--r--elf/dl-runtime.c16
-rw-r--r--elf/dl-scope.c2
-rw-r--r--elf/dl-sort-maps.c122
-rw-r--r--elf/dl-support.c26
-rw-r--r--elf/dl-sym.c31
-rw-r--r--elf/dl-symaddr.c4
-rw-r--r--elf/dl-sysdep-open.h2
-rw-r--r--elf/dl-sysdep.c10
-rw-r--r--elf/dl-tls.c213
-rw-r--r--elf/dl-tsd.c53
-rw-r--r--elf/dl-tunable-types.h62
-rw-r--r--elf/dl-tunables.c403
-rw-r--r--elf/dl-tunables.h132
-rw-r--r--elf/dl-tunables.list124
-rw-r--r--elf/dl-unmap-segments.h2
-rw-r--r--elf/dl-version.c70
-rw-r--r--elf/dl-writev.h2
-rw-r--r--elf/do-rel.h2
-rw-r--r--elf/dynamic-link.h7
-rw-r--r--elf/elf.h544
-rw-r--r--elf/enbl-secure.c2
-rw-r--r--elf/get-dynamic-info.h16
-rw-r--r--elf/ifuncdep2.c3
-rw-r--r--elf/ifuncmain6pie.c1
-rw-r--r--elf/ifuncmain7.c1
-rw-r--r--elf/ifuncmod1.c3
-rw-r--r--elf/ifuncmod5.c3
-rw-r--r--elf/interp.c2
-rw-r--r--elf/ldconfig.c32
-rw-r--r--elf/ldd.bash.in18
-rw-r--r--elf/link.h2
-rw-r--r--elf/loadtest.c16
-rw-r--r--elf/next.c3
-rw-r--r--elf/nodelete.c3
-rw-r--r--elf/order2.c3
-rw-r--r--elf/pldd-xx.c2
-rw-r--r--elf/pldd.c4
-rw-r--r--elf/readelflib.c21
-rw-r--r--elf/readlib.c2
-rw-r--r--elf/rtld-Rules12
-rw-r--r--elf/rtld.c262
-rw-r--r--elf/setup-vdso.h2
-rw-r--r--elf/sln.c21
-rw-r--r--elf/soinit.c1
-rw-r--r--elf/sotruss-lib.c6
-rwxr-xr-xelf/sotruss.sh4
-rw-r--r--elf/sprof.c4
-rw-r--r--elf/static-stubs.c2
-rw-r--r--elf/testobj6.c3
-rw-r--r--elf/tlsdeschtab.h5
-rw-r--r--elf/tst-_dl_addr_inside_object.c221
-rw-r--r--elf/tst-absolute-sym-lib.c25
-rw-r--r--elf/tst-absolute-sym-lib.lds19
-rw-r--r--elf/tst-absolute-sym.c38
-rw-r--r--elf/tst-absolute-zero-lib.c25
-rw-r--r--elf/tst-absolute-zero-lib.lds1
-rw-r--r--elf/tst-absolute-zero.c38
-rw-r--r--elf/tst-addr1.c3
-rw-r--r--elf/tst-align.c5
-rw-r--r--elf/tst-align2.c5
-rw-r--r--elf/tst-alignmod.c2
-rw-r--r--elf/tst-alignmod2.c2
-rw-r--r--elf/tst-audit11.c5
-rw-r--r--elf/tst-audit11mod1.c2
-rw-r--r--elf/tst-audit11mod2.c2
-rw-r--r--elf/tst-audit11mod2.map2
-rw-r--r--elf/tst-audit12.c5
-rw-r--r--elf/tst-audit12mod1.c2
-rw-r--r--elf/tst-audit12mod2.c2
-rw-r--r--elf/tst-audit12mod2.map2
-rw-r--r--elf/tst-audit12mod3.c2
-rw-r--r--elf/tst-audit2.c3
-rw-r--r--elf/tst-audit9.c3
-rw-r--r--elf/tst-auditmod1.c2
-rw-r--r--elf/tst-auditmod11.c2
-rw-r--r--elf/tst-auditmod12.c2
-rw-r--r--elf/tst-auxv.c5
-rw-r--r--elf/tst-big-note-lib.S26
-rw-r--r--elf/tst-big-note.c26
-rw-r--r--elf/tst-debug1.c34
-rw-r--r--elf/tst-deep1.c3
-rw-r--r--elf/tst-dl-iter-static.c5
-rw-r--r--elf/tst-dlmodcount.c5
-rw-r--r--elf/tst-dlmopen1.c3
-rw-r--r--elf/tst-dlmopen2.c3
-rw-r--r--elf/tst-dlmopen3.c3
-rw-r--r--elf/tst-dlopen-aout.c6
-rw-r--r--elf/tst-dlopenrpath.c5
-rw-r--r--elf/tst-dlopenrpathmod.c2
-rw-r--r--elf/tst-dlsym-error.c113
-rw-r--r--elf/tst-env-setuid-tunables.c75
-rw-r--r--elf/tst-env-setuid.c296
-rw-r--r--elf/tst-execstack-needed.c4
-rw-r--r--elf/tst-execstack-prog.c4
-rw-r--r--elf/tst-execstack.c3
-rw-r--r--elf/tst-global1.c3
-rw-r--r--elf/tst-gnu2-tls1.c51
-rw-r--r--elf/tst-gnu2-tls1mod.c56
-rw-r--r--elf/tst-latepthread.c104
-rw-r--r--elf/tst-latepthreadmod.c33
-rw-r--r--elf/tst-ldconfig-X.sh62
-rw-r--r--elf/tst-leaks1.c24
-rw-r--r--elf/tst-libc_dlvsym-dso.c25
-rw-r--r--elf/tst-libc_dlvsym-static.c32
-rw-r--r--elf/tst-libc_dlvsym.c34
-rw-r--r--elf/tst-libc_dlvsym.h125
-rw-r--r--elf/tst-linkall-static.c54
-rw-r--r--elf/tst-main1.c19
-rw-r--r--elf/tst-main1mod.c25
-rw-r--r--elf/tst-nodelete-dlclose-dso.c90
-rw-r--r--elf/tst-nodelete-dlclose-plugin.c40
-rw-r--r--elf/tst-nodelete-dlclose.c35
-rw-r--r--elf/tst-nodelete-opened-lib.c2
-rw-r--r--elf/tst-nodelete-opened.c5
-rw-r--r--elf/tst-nodelete.cc3
-rw-r--r--elf/tst-nodelete2.c3
-rw-r--r--elf/tst-noload.c72
-rw-r--r--elf/tst-null-argv-lib.c2
-rw-r--r--elf/tst-null-argv.c5
-rw-r--r--elf/tst-order-main.c3
-rw-r--r--elf/tst-pathopt.c3
-rwxr-xr-xelf/tst-pathopt.sh2
-rw-r--r--elf/tst-pie2.c5
-rw-r--r--elf/tst-piemod1.c3
-rw-r--r--elf/tst-prelink.c5
-rw-r--r--elf/tst-protected1a.c6
-rw-r--r--elf/tst-protected1b.c6
-rw-r--r--elf/tst-protected1mod.h2
-rw-r--r--elf/tst-protected1moda.c2
-rw-r--r--elf/tst-protected1modb.c2
-rw-r--r--elf/tst-ptrguard1.c35
-rw-r--r--elf/tst-relsort1.c3
-rwxr-xr-xelf/tst-rtld-load-self.sh2
-rw-r--r--elf/tst-stackguard1.c29
-rw-r--r--elf/tst-thrlock.c3
-rw-r--r--elf/tst-tls-dlinfo.c3
-rw-r--r--elf/tst-tls-manydynamic.c151
-rw-r--r--elf/tst-tls-manydynamic.h44
-rw-r--r--elf/tst-tls-manydynamicmod.c36
-rw-r--r--elf/tst-tls1-static-non-pie.c1
-rw-r--r--elf/tst-tls1.c3
-rw-r--r--elf/tst-tls10.c3
-rw-r--r--elf/tst-tls11.c3
-rw-r--r--elf/tst-tls12.c3
-rw-r--r--elf/tst-tls13.c4
-rw-r--r--elf/tst-tls14.c3
-rw-r--r--elf/tst-tls15.c4
-rw-r--r--elf/tst-tls16.c4
-rw-r--r--elf/tst-tls17.c4
-rw-r--r--elf/tst-tls18.c4
-rw-r--r--elf/tst-tls19.c3
-rw-r--r--elf/tst-tls2.c3
-rw-r--r--elf/tst-tls3.c3
-rw-r--r--elf/tst-tls4.c3
-rw-r--r--elf/tst-tls5.c3
-rw-r--r--elf/tst-tls6.c3
-rw-r--r--elf/tst-tls7.c3
-rw-r--r--elf/tst-tls8.c4
-rw-r--r--elf/tst-tls9.c3
-rw-r--r--elf/tst-tlsalign-extern.c5
-rw-r--r--elf/tst-tlsalign.c5
-rw-r--r--elf/tst-unique1.c3
-rw-r--r--elf/tst-unique2.c3
-rw-r--r--elf/vismain.c5
-rw-r--r--elf/vismod1.c2
-rw-r--r--elf/vismod2.c2
-rw-r--r--elf/vismod3.c2
207 files changed, 5605 insertions, 1967 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 63a535502c..cd0771307f 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1995-2016 Free Software Foundation, Inc.
+# Copyright (C) 1995-2018 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
@@ -23,32 +23,59 @@ include ../Makeconfig
headers = elf.h bits/elfclass.h link.h bits/link.h
routines = $(all-dl-routines) dl-support dl-iteratephdr \
- dl-addr enbl-secure dl-profstub \
- dl-origin dl-libc dl-sym dl-tsd dl-sysdep
+ dl-addr dl-addr-obj enbl-secure dl-profstub \
+ dl-origin dl-libc dl-sym dl-sysdep dl-error \
+ dl-reloc-static-pie
# The core dynamic linking functions are in libc for the static and
# profiled libraries.
dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \
- runtime error init fini debug misc \
- version profile conflict tls origin scope \
- execstack caller open close trampoline)
+ runtime init fini debug misc \
+ version profile tls origin scope \
+ execstack open close trampoline \
+ exception sort-maps)
ifeq (yes,$(use-ldconfig))
dl-routines += dl-cache
endif
+
+ifneq (no,$(have-tunables))
+dl-routines += dl-tunables
+tunables-type = $(addprefix TUNABLES_FRONTEND_,$(have-tunables))
+CPPFLAGS-dl-tunables.c += -DTUNABLES_FRONTEND=$(tunables-type)
+
+# Make sure that the compiler does not insert any library calls in tunables
+# code paths.
+ifeq (yes,$(have-loop-to-function))
+CFLAGS-dl-tunables.c += -fno-tree-loop-distribute-patterns
+endif
+endif
+
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
# But they are absent from the shared libc, because that code is in ld.so.
elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
- dl-sysdep
-shared-only-routines += dl-caller
+ dl-sysdep dl-exception dl-reloc-static-pie
# ld.so uses those routines, plus some special stuff for being the program
# interpreter and operating independent of libc.
-rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal
+rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \
+ dl-error-minimal dl-conflict
all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines)
-CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
-CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
-CFLAGS-dl-iterate-phdr.c = $(uses-callbacks)
+CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-dl-lookup.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-dl-iterate-phdr.c += $(uses-callbacks)
+
+# Compile rtld itself without stack protection.
+# Also compile all routines in the static library that are elided from
+# the shared libc because they are in libc.a in the same way.
+
+define elide-stack-protector
+$(if $(filter $(@F),$(patsubst %,%$(1),$(2))), $(no-stack-protector))
+endef
+
+CFLAGS-.o += $(call elide-stack-protector,.o,$(elide-routines.os))
+CFLAGS-.op += $(call elide-stack-protector,.op,$(elide-routines.os))
+CFLAGS-.os += $(call elide-stack-protector,.os,$(all-rtld-routines))
ifeq ($(unwind-find-fde),yes)
routines += unwind-dw2-fde-glibc
@@ -85,6 +112,7 @@ install-rootsbin += ldconfig
ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs
extra-objs += $(ldconfig-modules:=.o)
+others-extras = $(ldconfig-modules)
endif
endif
@@ -105,7 +133,7 @@ $(objpfx)sotruss-lib.so: $(common-objpfx)libc.so $(objpfx)ld.so \
$(objpfx)sotruss: sotruss.sh $(common-objpfx)config.make
sed -e 's%@BASH@%$(BASH)%g' \
-e 's%@VERSION@%$(version)%g' \
- -e 's%@TEXTDOMAINDIR@%$(msgcatdir)%g' \
+ -e 's%@TEXTDOMAINDIR@%$(localedir)%g' \
-e 's%@PREFIX@%$(prefix)%g' \
-e 's|@PKGVERSION@|$(PKGVERSION)|g' \
-e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|g' \
@@ -116,44 +144,57 @@ $(inst_auditdir)/sotruss-lib.so: $(objpfx)sotruss-lib.so $(+force)
$(do-install-program)
endif
-tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1 \
+tests-static-normal := tst-leaks1-static tst-array1-static tst-array5-static \
+ tst-dl-iter-static \
+ tst-tlsalign-static tst-tlsalign-extern-static \
+ tst-linkall-static tst-env-setuid tst-env-setuid-tunables
+tests-static-internal := tst-tls1-static tst-tls2-static \
+ tst-ptrguard1-static tst-stackguard1-static \
+ tst-tls1-static-non-pie tst-libc_dlvsym-static
+
+CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o
+tst-tls1-static-non-pie-no-pie = yes
+
+tests := tst-tls9 tst-leaks1 \
tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
tst-auxv
-tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static \
- tst-leaks1-static tst-array1-static tst-array5-static \
- tst-ptrguard1-static tst-dl-iter-static \
- tst-tlsalign-static tst-tlsalign-extern-static
+tests-internal := tst-tls1 tst-tls2 $(tests-static-internal)
+tests-static := $(tests-static-normal) $(tests-static-internal)
+
ifeq (yes,$(build-shared))
tests-static += tst-tls9-static
tst-tls9-static-ENV = \
LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
-endif
-tests += $(tests-static)
-ifeq (yes,$(build-shared))
-tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
- constload1 order noload filter unload \
+
+tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ constload1 order noload filter \
reldep reldep2 reldep3 reldep4 nodelete nodelete2 \
- nodlopen nodlopen2 neededtest neededtest2 \
- neededtest3 neededtest4 unload2 lateglobal initfirst global \
+ nodlopen nodlopen2 lateglobal initfirst global \
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
- circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
+ tst-tls4 tst-tls5 \
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \
- tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
+ tst-align tst-align2 \
tst-dlmodcount tst-dlopenrpath tst-deep1 \
- tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
+ tst-dlmopen1 tst-dlmopen3 \
unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
- tst-stackguard1 tst-addr1 tst-thrlock \
+ tst-addr1 tst-thrlock \
tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \
tst-nodelete) \
tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
- tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
- tst-nodelete2 tst-audit11 tst-audit12
+ tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
+ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
+ tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
+ tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note
# reldep9
+tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+ tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
+ tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym
ifeq ($(build-hardcoded-path-in-tests),yes)
tests += tst-dlopen-aout
-LDFLAGS-tst-dlopen-aout = $(no-pie-ldflag)
+tst-dlopen-aout-no-pie = yes
endif
test-srcs = tst-pathopt
selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
@@ -161,16 +202,23 @@ ifneq ($(selinux-enabled),1)
tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
endif
endif
+tests += $(tests-execstack-$(have-z-execstack))
ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-leaks1-mem.out \
- $(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out
+ $(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
+ $(objpfx)tst-ldconfig-X.out
endif
tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
tlsmod17a-modules = $(addprefix tst-tlsmod17a, $(tlsmod17a-suffixes))
tlsmod18a-modules = $(addprefix tst-tlsmod18a, $(tlsmod17a-suffixes))
-extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os)
-test-extras += tst-tlsmod17a tst-tlsmod18a
+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)
+extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \
+ tst-tlsalign-vars.o
+test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars
modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
testobj1_1 failobj constload2 constload3 unloadmod \
dep1 dep2 dep3 dep4 vismod1 vismod2 vismod3 \
@@ -221,7 +269,19 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-array5dep tst-null-argv-lib \
tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \
tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \
- tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12
+ tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
+ tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
+ tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
+ tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
+ tst-absolute-zero-lib tst-big-note-lib
+
+ifeq (yes,$(have-mtls-dialect-gnu2))
+tests += tst-gnu2-tls1
+modules-names += tst-gnu2-tls1mod
+$(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
+tst-gnu2-tls1mod.so-no-z-defs = yes
+CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
+endif
ifeq (yes,$(have-protected-data))
modules-names += tst-protected1moda tst-protected1modb
tests += tst-protected1a tst-protected1b
@@ -240,27 +300,31 @@ ifeq (yesyes,$(have-fpie)$(build-shared))
modules-names += tst-piemod1
tests += tst-pie1 tst-pie2
tests-pie += tst-pie1 tst-pie2
+ifeq (yes,$(have-protected-data))
tests += vismain
tests-pie += vismain
-CFLAGS-vismain.c = $(PIE-ccflag)
+CFLAGS-vismain.c += $(PIE-ccflag)
+endif
endif
modules-execstack-yes = tst-execstack-mod
extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
-# We need this variable to be sure the test modules get the right CPPFLAGS.
-test-extras += $(modules-names)
# filtmod1.so has a special rule
modules-names-nobuild := filtmod1
+tests += $(tests-static)
+
ifneq (no,$(multi-arch))
-tests-static += ifuncmain1static ifuncmain1picstatic \
+tests-ifuncstatic := ifuncmain1static ifuncmain1picstatic \
ifuncmain2static ifuncmain2picstatic \
ifuncmain4static ifuncmain4picstatic \
ifuncmain5static ifuncmain5picstatic \
ifuncmain7static ifuncmain7picstatic
-
+tests-static += $(tests-ifuncstatic)
+tests-internal += $(tests-ifuncstatic)
ifeq (yes,$(build-shared))
-tests += ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
+tests-internal += \
+ ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
ifuncmain1staticpic \
ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \
ifuncmain5 ifuncmain5pic ifuncmain5staticpic \
@@ -268,11 +332,11 @@ tests += ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
ifunc-test-modules = ifuncdep1 ifuncdep1pic ifuncdep2 ifuncdep2pic \
ifuncdep5 ifuncdep5pic
extra-test-objs += $(ifunc-test-modules:=.o)
-test-extras += $(ifunc-test-modules)
+test-internal-extras += $(ifunc-test-modules)
ifeq (yes,$(have-fpie))
ifunc-pie-tests = ifuncmain1pie ifuncmain1vispie ifuncmain1staticpie \
ifuncmain5pie ifuncmain6pie ifuncmain7pie
-tests += $(ifunc-pie-tests)
+tests-internal += $(ifunc-pie-tests)
tests-pie += $(ifunc-pie-tests)
endif
modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6
@@ -284,7 +348,7 @@ ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out
endif
tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
- $(objpfx)check-localplt.out
+ $(objpfx)check-localplt.out $(objpfx)check-initfini.out
endif
ifeq ($(run-built-tests),yes)
@@ -305,11 +369,41 @@ update-all-abi: update-all-abi-ld
ifeq ($(have-glob-dat-reloc),yes)
tests += tst-prelink
+# Don't compile tst-prelink.c with PIE for GLOB_DAT relocation.
+CFLAGS-tst-prelink.c += -fno-pie
+tst-prelink-no-pie = yes
ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-prelink-cmp.out
endif
endif
+# The test requires shared _and_ PIE because the executable
+# unit test driver must be able to link with the shared object
+# that is going to eventually go into an installed DSO.
+ifeq (yesyes,$(have-fpie)$(build-shared))
+tests-internal += tst-_dl_addr_inside_object
+tests-pie += tst-_dl_addr_inside_object
+$(objpfx)tst-_dl_addr_inside_object: $(objpfx)dl-addr-obj.os
+CFLAGS-tst-_dl_addr_inside_object.c += $(PIE-ccflag)
+endif
+
+# We can only test static libcrypt use if libcrypt has been built,
+# and either NSS crypto is not in use, or static NSS libraries are
+# available.
+ifeq ($(build-crypt),no)
+CFLAGS-tst-linkall-static.c += -DUSE_CRYPT=0
+else
+ifeq ($(nss-crypt),no)
+CFLAGS-tst-linkall-static.c += -DUSE_CRYPT=1
+else
+ifeq ($(static-nss-crypt),no)
+CFLAGS-tst-linkall-static.c += -DUSE_CRYPT=0
+else
+CFLAGS-tst-linkall-static.c += -DUSE_CRYPT=1
+endif
+endif
+endif
+
include ../Rules
ifeq (yes,$(build-shared))
@@ -336,9 +430,22 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os)
# are compiled with special flags, and puts these modules into rtld-libc.a
# for us. Then we do the real link using rtld-libc.a instead of libc_pic.a.
+# If the compiler can do SSP, build the mapfile with dummy __stack_chk_fail
+# and __stack_chk_fail_local symbols defined, to prevent the real things
+# being dragged into rtld even though rtld is never built with stack-
+# protection.
+
+ifeq ($(have-ssp),yes)
+dummy-stack-chk-fail := -Wl,--defsym='__stack_chk_fail=0' \
+ -Wl,--defsym='__stack_chk_fail_local=0'
+else
+dummy-stack-chk-fail :=
+endif
+
$(objpfx)librtld.map: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a
@-rm -f $@T
- $(reloc-link) -o $@.o '-Wl,-(' $^ -lgcc '-Wl,-)' -Wl,-Map,$@T
+ $(reloc-link) -o $@.o $(dummy-stack-chk-fail) \
+ '-Wl,-(' $^ -lgcc '-Wl,-)' -Wl,-Map,$@T
rm -f $@.o
mv -f $@T $@
@@ -412,7 +519,7 @@ $(objpfx)trusted-dirs.st: Makefile $(..)Makeconfig
echo '#define DL_DST_LIB "$(notdir $(slibdir))"' >> ${@:st=T}
$(move-if-change) ${@:st=T} ${@:st=h}
touch $@
-CPPFLAGS-dl-load.c = -I$(objpfx). -I$(csu-objpfx).
+CPPFLAGS-dl-load.c += -I$(objpfx). -I$(csu-objpfx).
ifeq (yes,$(build-shared))
$(inst_slibdir)/$(rtld-version-installed-name): $(objpfx)ld.so $(+force)
@@ -436,7 +543,7 @@ ldd-rewrite = -e 's%@RTLD@%$(rtlddir)/$(rtld-installed-name)%g' \
-e 's|@PKGVERSION@|$(PKGVERSION)|g' \
-e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|g' \
-e 's%@BASH@%$(BASH)%g' \
- -e 's%@TEXTDOMAINDIR@%$(msgcatdir)%g'
+ -e 's%@TEXTDOMAINDIR@%$(localedir)%g'
ifeq ($(ldd-rewrite-script),no)
define gen-ldd
@@ -462,16 +569,16 @@ $(objpfx)sln: $(sln-modules:%=$(objpfx)%.o)
$(objpfx)ldconfig: $(ldconfig-modules:%=$(objpfx)%.o)
SYSCONF-FLAGS := -D'SYSCONFDIR="$(sysconfdir)"'
-CFLAGS-ldconfig.c = $(SYSCONF-FLAGS) -D'LIBDIR="$(libdir)"' \
+CFLAGS-ldconfig.c += $(SYSCONF-FLAGS) -D'LIBDIR="$(libdir)"' \
-D'SLIBDIR="$(slibdir)"'
libof-ldconfig = ldconfig
-CFLAGS-dl-cache.c = $(SYSCONF-FLAGS)
-CFLAGS-cache.c = $(SYSCONF-FLAGS)
-CFLAGS-rtld.c = $(SYSCONF-FLAGS)
+CFLAGS-dl-cache.c += $(SYSCONF-FLAGS)
+CFLAGS-cache.c += $(SYSCONF-FLAGS)
+CFLAGS-rtld.c += $(SYSCONF-FLAGS)
cpp-srcs-left := $(all-rtld-routines:=.os)
lib := rtld
-include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left))
+include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(strip $(modules-names))))
generated += $(addsuffix .so,$(strip $(modules-names)))
@@ -545,6 +652,7 @@ $(objpfx)tst-null-argv: $(objpfx)tst-null-argv-lib.so
$(objpfx)tst-tlsalign: $(objpfx)tst-tlsalign-lib.so
$(objpfx)tst-nodelete-opened.out: $(objpfx)tst-nodelete-opened-lib.so
$(objpfx)tst-nodelete-opened: $(libdl)
+$(objpfx)tst-noload: $(libdl)
$(objpfx)tst-tlsalign-extern: $(objpfx)tst-tlsalign-vars.o
$(objpfx)tst-tlsalign-extern-static: $(objpfx)tst-tlsalign-vars.o
@@ -661,7 +769,7 @@ $(objpfx)loadfail.out: $(objpfx)failobj.so
$(objpfx)multiload: $(libdl)
LDFLAGS-multiload = -rdynamic
-CFLAGS-multiload.c = -DOBJDIR=\"$(elf-objpfx)\"
+CFLAGS-multiload.c += -DOBJDIR=\"$(elf-objpfx)\"
$(objpfx)multiload.out: $(objpfx)testobj1.so
@@ -728,6 +836,9 @@ $(objpfx)filtmod1.so: $(objpfx)filtmod1.os $(objpfx)filtmod2.so
$< -Wl,-F,$(objpfx)filtmod2.so
$(objpfx)filter: $(objpfx)filtmod1.so
+# This does not link against libc.
+CFLAGS-filtmod1.c += $(no-stack-protector)
+
$(objpfx)unload: $(libdl)
$(objpfx)unload.out: $(objpfx)unloadmod.so
@@ -756,7 +867,7 @@ $(objpfx)tst-pathopt: $(libdl)
$(objpfx)tst-pathopt.out: tst-pathopt.sh $(objpfx)tst-pathopt \
$(objpfx)pathoptobj.so
$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' \
- '$(run-program-env)'; \
+ '$(run-program-env)' > $@; \
$(evaluate-test)
$(objpfx)tst-rtld-load-self.out: tst-rtld-load-self.sh $(objpfx)ld.so
@@ -853,10 +964,10 @@ $(patsubst %,$(objpfx)%.so,$(tlsmod18a-modules)): $(objpfx)tst-tlsmod18a%.so: $(
$(objpfx)tst-tls19: $(libdl)
$(objpfx)tst-tls19.out: $(objpfx)tst-tls19mod1.so
-CFLAGS-tst-align.c = $(stack-align-test-flags)
-CFLAGS-tst-align2.c = $(stack-align-test-flags)
-CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
-CFLAGS-tst-alignmod2.c = $(stack-align-test-flags)
+CFLAGS-tst-align.c += $(stack-align-test-flags)
+CFLAGS-tst-align2.c += $(stack-align-test-flags)
+CFLAGS-tst-alignmod.c += $(stack-align-test-flags)
+CFLAGS-tst-alignmod2.c += $(stack-align-test-flags)
$(objpfx)tst-align: $(libdl)
$(objpfx)tst-align.out: $(objpfx)tst-alignmod.so
$(objpfx)tst-align2: $(objpfx)tst-alignmod2.so
@@ -891,7 +1002,7 @@ endif
ifeq ($(have-z-execstack),yes)
$(objpfx)tst-execstack: $(libdl)
$(objpfx)tst-execstack.out: $(objpfx)tst-execstack-mod.so
-CPPFLAGS-tst-execstack.c = -DUSE_PTHREADS=0
+CPPFLAGS-tst-execstack.c += -DUSE_PTHREADS=0
LDFLAGS-tst-execstack = -Wl,-z,noexecstack
LDFLAGS-tst-execstack-mod = -Wl,-z,execstack
@@ -943,9 +1054,12 @@ $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
CFLAGS-tst-pie1.c += $(pie-ccflag)
CFLAGS-tst-pie2.c += $(pie-ccflag)
+$(objpfx)tst-piemod1.so: $(libsupport)
$(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
ifeq (yes,$(build-shared))
+# NB: Please keep cet-built-dso in sysdeps/x86/Makefile in sync with
+# all-built-dso here.
all-built-dso := $(common-objpfx)elf/ld.so $(common-objpfx)libc.so \
$(filter-out $(common-objpfx)linkobj/libc.so, \
$(sort $(wildcard $(addprefix $(common-objpfx), \
@@ -989,7 +1103,7 @@ common-generated += $(all-built-dso:$(common-objpfx)%=%.phdr)
$(objpfx)check-execstack.out: $(..)scripts/check-execstack.awk \
$(objpfx)execstack-default \
$(all-built-dso:=.phdr)
- LC_ALL=C $(AWK) -f $^ > $@; \
+ LC_ALL=C $(AWK) -v "xfail=$(check-execstack-xfail)" -f $^ > $@; \
$(evaluate-test)
generated += check-execstack.out
@@ -1010,7 +1124,6 @@ localplt-built-dso := $(addprefix $(common-objpfx),\
rt/librt.so \
dlfcn/libdl.so \
resolv/libresolv.so \
- crypt/libcrypt.so \
)
ifeq ($(build-mathvec),yes)
localplt-built-dso += $(addprefix $(common-objpfx), mathvec/libmvec.so)
@@ -1018,6 +1131,9 @@ endif
ifeq ($(have-thread-library),yes)
localplt-built-dso += $(filter-out %_nonshared.a, $(shared-thread-library))
endif
+ifeq ($(build-crypt),yes)
+localplt-built-dso += $(addprefix $(common-objpfx), crypt/libcrypt.so)
+endif
vpath localplt.data $(+sysdep_dirs)
@@ -1031,6 +1147,19 @@ $(objpfx)check-localplt.out: $(..)scripts/check-localplt.awk \
$(evaluate-test)
endif
+$(all-built-dso:=.dynsym): %.dynsym: %
+ @rm -f $@T
+ LC_ALL=C $(READELF) -W --dyn-syms $< > $@T
+ test -s $@T
+ mv -f $@T $@
+common-generated += $(all-built-dso:$(common-objpfx)%=%.dynsym)
+
+$(objpfx)check-initfini.out: $(..)scripts/check-initfini.awk \
+ $(all-built-dso:=.dynsym)
+ LC_ALL=C $(AWK) -f $^ > $@; \
+ $(evaluate-test)
+generated += check-initfini.out
+
$(objpfx)tst-dlopenrpathmod.so: $(libdl)
$(objpfx)tst-dlopenrpath: $(objpfx)tst-dlopenrpathmod.so $(libdl)
CFLAGS-tst-dlopenrpath.c += -DPFX=\"$(objpfx)\"
@@ -1091,7 +1220,7 @@ tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child
tst-ptrguard1-ARGS = --command "$(host-test-program-cmd) --child"
# When built statically, the pointer guard interface uses
# __pointer_chk_guard_local.
-CFLAGS-tst-ptrguard1-static.c = -DPTRGUARD_LOCAL
+CFLAGS-tst-ptrguard1-static.c += -DPTRGUARD_LOCAL
tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child"
$(objpfx)tst-leaks1: $(libdl)
@@ -1243,6 +1372,26 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so
$(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so
LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map
+# Override -z defs, so that we can reference an undefined symbol.
+# Force lazy binding for the same reason.
+LDFLAGS-tst-latepthreadmod.so = \
+ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
+# Do not optimize sibling calls as the test relies on a JMP_SLOT relocation for
+# function this_function_is_not_defined.
+CFLAGS-tst-latepthreadmod.c += -fno-optimize-sibling-calls
+$(objpfx)tst-latepthreadmod.so: $(shared-thread-library)
+$(objpfx)tst-latepthread: $(libdl)
+$(objpfx)tst-latepthread.out: $(objpfx)tst-latepthreadmod.so
+
+# The test modules are parameterized by preprocessor macros.
+$(patsubst %,$(objpfx)%.os,$(tst-tls-many-dynamic-modules)): \
+ $(objpfx)tst-tls-manydynamic%mod.os : tst-tls-manydynamicmod.c
+ $(compile-command.c) \
+ -DNAME=tls_global_$* -DSETTER=set_value_$* -DGETTER=get_value_$*
+$(objpfx)tst-tls-manydynamic: $(libdl) $(shared-thread-library)
+$(objpfx)tst-tls-manydynamic.out: \
+ $(patsubst %,$(objpfx)%.so,$(tst-tls-many-dynamic-modules))
+
tst-prelink-ENV = LD_TRACE_PRELINKING=1
$(objpfx)tst-prelink-conflict.out: $(objpfx)tst-prelink.out
@@ -1252,3 +1401,86 @@ $(objpfx)tst-prelink-cmp.out: tst-prelink.exp \
$(objpfx)tst-prelink-conflict.out
cmp $^ > $@; \
$(evaluate-test)
+
+$(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig
+ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' \
+ '$(run-program-env)' > $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-dlsym-error: $(libdl)
+
+# Test static linking of all the libraries we can possibly link
+# together. Note that in some configurations this may be less than the
+# complete list of libraries we build but we try to maxmimize this list.
+$(objpfx)tst-linkall-static: \
+ $(common-objpfx)math/libm.a \
+ $(common-objpfx)resolv/libresolv.a \
+ $(common-objpfx)dlfcn/libdl.a \
+ $(common-objpfx)login/libutil.a \
+ $(common-objpfx)rt/librt.a \
+ $(common-objpfx)resolv/libanl.a \
+ $(static-thread-library)
+
+ifeq ($(build-crypt),yes)
+# If we are using NSS crypto and we have the ability to link statically
+# then we include libcrypt.a, otherwise we leave out libcrypt.a and
+# link as much as we can into the tst-linkall-static test. This assumes
+# that linking with libcrypt.a does everything required to include the
+# static NSS crypto library.
+ifeq (yesyes,$(nss-crypt)$(static-nss-crypt))
+$(objpfx)tst-linkall-static: \
+ $(common-objpfx)crypt/libcrypt.a
+endif
+# If we are not using NSS crypto then we always have the ability to link
+# with libcrypt.a.
+ifeq (no,$(nss-crypt))
+$(objpfx)tst-linkall-static: \
+ $(common-objpfx)crypt/libcrypt.a
+endif
+endif
+
+# The application depends on the DSO, and the DSO loads the plugin.
+# The plugin also depends on the DSO. This creates the circular
+# dependency via dlopen that we're testing to make sure works.
+$(objpfx)tst-nodelete-dlclose-dso.so: $(libdl)
+$(objpfx)tst-nodelete-dlclose-plugin.so: $(objpfx)tst-nodelete-dlclose-dso.so
+$(objpfx)tst-nodelete-dlclose: $(objpfx)tst-nodelete-dlclose-dso.so
+$(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \
+ $(objpfx)tst-nodelete-dlclose-plugin.so
+
+tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
+ LD_HWCAP_MASK=0x1
+tst-env-setuid-tunables-ENV = \
+ GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
+
+$(objpfx)tst-debug1: $(libdl)
+$(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so
+
+$(objpfx)tst-debug1mod1.so: $(objpfx)testobj1.so
+ $(OBJCOPY) --only-keep-debug $< $@
+
+$(objpfx)tst-main1: $(objpfx)tst-main1mod.so
+CRT-tst-main1 := $(csu-objpfx)crt1.o
+tst-main1-no-pie = yes
+LDLIBS-tst-main1 = $(libsupport)
+tst-main1mod.so-no-z-defs = yes
+
+LDLIBS-tst-absolute-sym-lib.so = tst-absolute-sym-lib.lds
+$(objpfx)tst-absolute-sym-lib.so: $(LDLIBS-tst-absolute-sym-lib.so)
+$(objpfx)tst-absolute-sym: $(objpfx)tst-absolute-sym-lib.so
+
+LDLIBS-tst-absolute-zero-lib.so = tst-absolute-zero-lib.lds
+$(objpfx)tst-absolute-zero-lib.so: $(LDLIBS-tst-absolute-zero-lib.so)
+$(objpfx)tst-absolute-zero: $(objpfx)tst-absolute-zero-lib.so
+
+# Both the main program and the DSO for tst-libc_dlvsym need to link
+# against libdl.
+$(objpfx)tst-libc_dlvsym: $(libdl)
+$(objpfx)tst-libc_dlvsym-dso.so: $(libsupport) $(libdl)
+$(objpfx)tst-libc_dlvsym.out: $(objpfx)tst-libc_dlvsym-dso.so
+$(objpfx)tst-libc_dlvsym-static: $(common-objpfx)dlfcn/libdl.a
+tst-libc_dlvsym-static-ENV = \
+ LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
+$(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so
+
+$(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so
diff --git a/elf/Versions b/elf/Versions
index 23deda984f..3b09901f6c 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -23,16 +23,20 @@ libc {
GLIBC_PRIVATE {
# functions used in other libraries
_dl_addr;
- _dl_open_hook;
+ _dl_open_hook; _dl_open_hook2;
_dl_sym; _dl_vsym;
- __libc_dlclose; __libc_dlopen_mode; __libc_dlsym;
+ __libc_dlclose; __libc_dlopen_mode; __libc_dlsym; __libc_dlvsym;
+
+ # Internal error handling support. Interposes the functions in ld.so.
+ _dl_signal_exception; _dl_catch_exception;
+ _dl_signal_error; _dl_catch_error;
}
}
ld {
GLIBC_2.0 {
- # Function from libc.so which must be shared with libc.
- __libc_memalign; calloc; free; malloc; realloc;
+ # Functions which are interposed from libc.so.
+ calloc; free; malloc; realloc;
_r_debug;
}
@@ -55,8 +59,8 @@ ld {
__libc_enable_secure;
_dl_allocate_tls; _dl_allocate_tls_init;
_dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info;
- _dl_deallocate_tls; _dl_make_stack_executable; _dl_out_of_memory;
- _dl_rtld_di_serinfo; _dl_starting_up; _dl_tls_setup;
+ _dl_deallocate_tls; _dl_make_stack_executable;
+ _dl_rtld_di_serinfo; _dl_starting_up;
_rtld_global; _rtld_global_ro;
# Only here for gdb while a better method is developed.
@@ -64,5 +68,15 @@ ld {
# Pointer protection.
__pointer_chk_guard;
+
+ # Internal error handling support.
+ _dl_exception_create; _dl_exception_create_format; _dl_exception_free;
+
+ # Internal error handling support. Interposed by libc.so.
+ _dl_signal_exception; _dl_catch_exception;
+ _dl_signal_error; _dl_catch_error;
+
+ # Set value of a tunable.
+ __tunable_get_val;
}
}
diff --git a/elf/cache.c b/elf/cache.c
index fbee172012..e63979da7d 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999.
@@ -114,6 +114,12 @@ print_entry (const char *lib, int flag, unsigned int osversion,
case FLAG_MIPS64_LIBN64_NAN2008:
fputs (",64bit,nan2008", stdout);
break;
+ case FLAG_RISCV_FLOAT_ABI_SOFT:
+ fputs (",soft-float", stdout);
+ break;
+ case FLAG_RISCV_FLOAT_ABI_DOUBLE:
+ fputs (",double-float", stdout);
+ break;
case 0:
break;
default:
@@ -448,8 +454,7 @@ save_cache (const char *cache_name)
error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
}
- if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
- || close (fd))
+ if (write (fd, strings, total_strlen) != (ssize_t) total_strlen)
error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
/* Make sure user can always read cache file */
@@ -458,6 +463,10 @@ save_cache (const char *cache_name)
_("Changing access rights of %s to %#o failed"), temp_name,
S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
+ /* Make sure that data is written to disk. */
+ if (fsync (fd) != 0 || close (fd) != 0)
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+
/* Move temporary to its final location. */
if (rename (temp_name, cache_name))
error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
@@ -812,7 +821,8 @@ save_aux_cache (const char *aux_cache_name)
if (write (fd, file_entries, file_entries_size + total_strlen)
!= (ssize_t) (file_entries_size + total_strlen)
- || close (fd))
+ || fdatasync (fd) != 0
+ || close (fd) != 0)
{
unlink (temp_name);
goto out_fail;
diff --git a/elf/chroot_canon.c b/elf/chroot_canon.c
index d1c4d01013..ecc41ae48c 100644
--- a/elf/chroot_canon.c
+++ b/elf/chroot_canon.c
@@ -1,5 +1,5 @@
/* Return the canonical absolute name of a given file inside chroot.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
diff --git a/elf/dl-addr-obj.c b/elf/dl-addr-obj.c
new file mode 100644
index 0000000000..db84415a69
--- /dev/null
+++ b/elf/dl-addr-obj.c
@@ -0,0 +1,74 @@
+/* Determine if address is inside object load segments.
+ Copyright (C) 1996-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <elf.h>
+
+/* Return non-zero if ADDR lies within one of L's loadable segments.
+ We have three cases we care about.
+
+ Case 1: addr is above a segment.
+ +==================+<- l_map_end
+ | |<- addr
+ |------------------|<- l_addr + p_vaddr + p_memsz
+ | |
+ | |
+ |------------------|<- l_addr + p_vaddr
+ |------------------|<- l_addr
+ | |
+ +==================+<- l_map_start
+
+ Case 2: addr is within a segments.
+ +==================+<- l_map_end
+ | |
+ |------------------|<- l_addr + p_vaddr + p_memsz
+ | |<- addr
+ | |
+ |------------------|<- l_addr + p_vaddr
+ |------------------|<- l_addr
+ | |
+ +==================+<- l_map_start
+
+ Case 3: addr is below a segments.
+ +==================+<- l_map_end
+ | |
+ |------------------|<- l_addr + p_vaddr + p_memsz
+ | |
+ | |
+ |------------------|<- l_addr + p_vaddr
+ |------------------|<- l_addr
+ | |<- addr
+ +==================+<- l_map_start
+
+ All the arithmetic is unsigned and we shift all the values down by
+ l_addr + p_vaddr and then compare the normalized addr to the range
+ of interest i.e. 0 <= addr < p_memsz.
+
+*/
+int
+_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
+{
+ int n = l->l_phnum;
+ const ElfW(Addr) reladdr = addr - l->l_addr;
+
+ while (--n >= 0)
+ if (l->l_phdr[n].p_type == PT_LOAD
+ && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
+ return 1;
+ return 0;
+}
diff --git a/elf/dl-addr.c b/elf/dl-addr.c
index 291ff55816..e6c7d02094 100644
--- a/elf/dl-addr.c
+++ b/elf/dl-addr.c
@@ -1,5 +1,5 @@
/* Locate the shared object symbol nearest a given address.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
@@ -42,8 +42,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
const ElfW(Sym) *matchsym = NULL;
- if (match->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
- + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] != NULL)
+ if (match->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)
{
/* We look at all symbol table entries referenced by the hash
table. */
@@ -60,6 +59,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
we can omit that test here. */
if ((symtab[symndx].st_shndx != SHN_UNDEF
|| symtab[symndx].st_value != 0)
+ && symtab[symndx].st_shndx != SHN_ABS
&& ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS
&& DL_ADDR_SYM_MATCH (match, &symtab[symndx],
matchsym, addr)
@@ -88,9 +88,11 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
for (; (void *) symtab < (void *) symtabend; ++symtab)
if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
|| ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
+ && __glibc_likely (!dl_symbol_visibility_binds_local_p (symtab))
&& ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
&& (symtab->st_shndx != SHN_UNDEF
|| symtab->st_value != 0)
+ && symtab->st_shndx != SHN_ABS
&& DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr)
&& symtab->st_name < strtabsize)
matchsym = (ElfW(Sym) *) symtab;
@@ -120,7 +122,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
int
-internal_function
_dl_addr (const void *address, Dl_info *info,
struct link_map **mapp, const ElfW(Sym) **symbolp)
{
@@ -143,19 +144,3 @@ _dl_addr (const void *address, Dl_info *info,
return result;
}
libc_hidden_def (_dl_addr)
-
-/* Return non-zero if ADDR lies within one of L's segments. */
-int
-internal_function
-_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
-{
- int n = l->l_phnum;
- const ElfW(Addr) reladdr = addr - l->l_addr;
-
- while (--n >= 0)
- if (l->l_phdr[n].p_type == PT_LOAD
- && reladdr - l->l_phdr[n].p_vaddr >= 0
- && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
- return 1;
- return 0;
-}
diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index cfa335eb32..6ee5153ff9 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -1,5 +1,5 @@
/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
@@ -24,6 +24,7 @@
#include <dl-procinfo.h>
#include <stdint.h>
#include <_itoa.h>
+#include <dl-hwcaps.h>
#ifndef _DL_PLATFORMS_COUNT
# define _DL_PLATFORMS_COUNT 0
@@ -133,7 +134,6 @@ while (0)
int
-internal_function
_dl_cache_libcmp (const char *p1, const char *p2)
{
while (*p1 != '\0')
@@ -180,7 +180,6 @@ _dl_cache_libcmp (const char *p1, const char *p2)
this function must take care that it does not return references to
any data in the mapping. */
char *
-internal_function
_dl_load_cache_lookup (const char *name)
{
int left, right, middle;
@@ -258,8 +257,10 @@ _dl_load_cache_lookup (const char *name)
if (platform != (uint64_t) -1)
platform = 1ULL << platform;
+ uint64_t hwcap_mask = GET_HWCAP_MASK();
+
#define _DL_HWCAP_TLS_MASK (1LL << 63)
- uint64_t hwcap_exclude = ~((GLRO(dl_hwcap) & GLRO(dl_hwcap_mask))
+ uint64_t hwcap_exclude = ~((GLRO(dl_hwcap) & hwcap_mask)
| _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK);
/* Only accept hwcap if it's for the right platform. */
@@ -302,7 +303,7 @@ _dl_load_cache_lookup (const char *name)
char *temp;
temp = alloca (strlen (best) + 1);
strcpy (temp, best);
- return strdup (temp);
+ return __strdup (temp);
}
#ifndef MAP_COPY
diff --git a/elf/dl-caller.c b/elf/dl-caller.c
deleted file mode 100644
index 4526da085e..0000000000
--- a/elf/dl-caller.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* Check whether caller comes from the right place.
- Copyright (C) 2004-2016 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
- <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <ldsodefs.h>
-#include <stddef.h>
-#include <caller.h>
-#include <gnu/lib-names.h>
-
-
-int
-attribute_hidden
-_dl_check_caller (const void *caller, enum allowmask mask)
-{
- static const char expected1[] = LIBC_SO;
- static const char expected2[] = LIBDL_SO;
-#ifdef LIBPTHREAD_SO
- static const char expected3[] = LIBPTHREAD_SO;
-#endif
- static const char expected4[] = LD_SO;
-
- for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
- for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
- l = l->l_next)
- if (caller >= (const void *) l->l_map_start
- && caller < (const void *) l->l_text_end)
- {
- /* The address falls into this DSO's address range. Check the
- name. */
- if ((mask & allow_libc) && strcmp (expected1, l->l_name) == 0)
- return 0;
- if ((mask & allow_libdl) && strcmp (expected2, l->l_name) == 0)
- return 0;
-#ifdef LIBPTHREAD_SO
- if ((mask & allow_libpthread) && strcmp (expected3, l->l_name) == 0)
- return 0;
-#endif
- if ((mask & allow_ldso) && strcmp (expected4, l->l_name) == 0)
- return 0;
-
- struct libname_list *runp = l->l_libname;
-
- while (runp != NULL)
- {
- if ((mask & allow_libc) && strcmp (expected1, runp->name) == 0)
- return 0;
- if ((mask & allow_libdl) && strcmp (expected2, runp->name) == 0)
- return 0;
-#ifdef LIBPTHREAD_SO
- if ((mask & allow_libpthread)
- && strcmp (expected3, runp->name) == 0)
- return 0;
-#endif
- if ((mask & allow_ldso) && strcmp (expected4, runp->name) == 0)
- return 0;
-
- runp = runp->next;
- }
-
- break;
- }
-
- /* Maybe the dynamic linker is not yet on the list. */
- if ((mask & allow_ldso) != 0
- && caller >= (const void *) GL(dl_rtld_map).l_map_start
- && caller < (const void *) GL(dl_rtld_map).l_text_end)
- return 0;
-
- /* No valid caller. */
- return 1;
-}
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 687d7de874..ecd6729704 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -1,5 +1,5 @@
/* Close a shared object opened by `_dl_open'.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
@@ -241,8 +241,10 @@ _dl_close_worker (struct link_map *map, bool force)
}
}
- /* Sort the entries. */
- _dl_sort_fini (maps, nloaded, used, nsid);
+ /* Sort the entries. We can skip looking for the binary itself which is
+ at the front of the search list for the main namespace. */
+ _dl_sort_maps (maps + (nsid == LM_ID_BASE), nloaded - (nsid == LM_ID_BASE),
+ used + (nsid == LM_ID_BASE), true);
/* Call all termination functions at once. */
#ifdef SHARED
@@ -805,19 +807,37 @@ _dl_close (void *_map)
{
struct link_map *map = _map;
- /* First see whether we can remove the object at all. */
+ /* We must take the lock to examine the contents of map and avoid
+ concurrent dlopens. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ /* At this point we are guaranteed nobody else is touching the list of
+ loaded maps, but a concurrent dlclose might have freed our map
+ before we took the lock. There is no way to detect this (see below)
+ so we proceed assuming this isn't the case. First see whether we
+ can remove the object at all. */
if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE))
{
- assert (map->l_init_called);
/* Nope. Do nothing. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
return;
}
+ /* At present this is an unreliable check except in the case where the
+ caller has recursively called dlclose and we are sure the link map
+ has not been freed. In a non-recursive dlclose the map itself
+ might have been freed and this access is potentially a data race
+ with whatever other use this memory might have now, or worse we
+ might silently corrupt memory if it looks enough like a link map.
+ POSIX has language in dlclose that appears to guarantee that this
+ should be a detectable case and given that dlclose should be threadsafe
+ we need this to be a reliable detection.
+ This is bug 20990. */
if (__builtin_expect (map->l_direct_opencount, 1) == 0)
- GLRO(dl_signal_error) (0, map->l_name, NULL, N_("shared object not open"));
-
- /* Acquire the lock. */
- __rtld_lock_lock_recursive (GL(dl_load_lock));
+ {
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ _dl_signal_error (0, map->l_name, NULL, N_("shared object not open"));
+ }
_dl_close_worker (map, false);
diff --git a/elf/dl-conflict.c b/elf/dl-conflict.c
index d9ed24d884..70f14b04cd 100644
--- a/elf/dl-conflict.c
+++ b/elf/dl-conflict.c
@@ -1,5 +1,5 @@
/* Resolve conflicts against already prelinked libraries.
- Copyright (C) 2001-2016 Free Software Foundation, Inc.
+ Copyright (C) 2001-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index 30eee97981..14d1125fe6 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -1,5 +1,5 @@
/* Communicate dynamic linker state to the debugger at runtime.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
@@ -42,7 +42,6 @@ struct r_debug _r_debug;
_r_debug.r_ldbase. Returns the address of _r_debug. */
struct r_debug *
-internal_function
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
{
struct r_debug *r;
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 6a82987799..9d9b1ba7f2 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -1,5 +1,5 @@
/* Load the dependencies of a mapped object.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <sys/param.h>
#include <ldsodefs.h>
+#include <scratch_buffer.h>
#include <dl-dst.h>
@@ -68,7 +69,6 @@ openaux (void *a)
}
static ptrdiff_t
-internal_function
_dl_build_local_scope (struct link_map **list, struct link_map *map)
{
struct link_map **p = list;
@@ -101,7 +101,7 @@ struct list
({ \
const char *__str = (str); \
const char *__result = __str; \
- size_t __dst_cnt = DL_DST_COUNT (__str, 0); \
+ size_t __dst_cnt = _dl_dst_count (__str); \
\
if (__dst_cnt != 0) \
{ \
@@ -115,7 +115,7 @@ DST not allowed in SUID/SGID programs")); \
__newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \
__dst_cnt)); \
\
- __result = _dl_dst_substitute (l, __str, __newp, 0); \
+ __result = _dl_dst_substitute (l, __str, __newp); \
\
if (*__result == '\0') \
{ \
@@ -153,7 +153,6 @@ preload (struct list *known, unsigned int *nlist, struct link_map *map)
}
void
-internal_function
_dl_map_object_deps (struct link_map *map,
struct link_map **preloads, unsigned int npreloads,
int trace_mode, int open_mode)
@@ -165,8 +164,7 @@ _dl_map_object_deps (struct link_map *map,
const char *name;
int errno_saved;
int errno_reason;
- const char *errstring;
- const char *objname;
+ struct dl_exception exception;
/* No loaded object so far. */
nlist = 0;
@@ -184,9 +182,8 @@ _dl_map_object_deps (struct link_map *map,
/* Pointer to last unique object. */
tail = &known[nlist - 1];
- /* No alloca'd space yet. */
- struct link_map **needed_space = NULL;
- size_t needed_space_bytes = 0;
+ struct scratch_buffer needed_space;
+ scratch_buffer_init (&needed_space);
/* Process each element of the search list, loading each of its
auxiliary objects and immediate dependencies. Auxiliary objects
@@ -200,7 +197,6 @@ _dl_map_object_deps (struct link_map *map,
alloca means we cannot use recursive function calls. */
errno_saved = errno;
errno_reason = 0;
- errstring = NULL;
errno = 0;
name = NULL;
for (runp = known; runp; )
@@ -217,13 +213,12 @@ _dl_map_object_deps (struct link_map *map,
if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
&& l != map && l->l_ldnum > 0)
{
- size_t new_size = l->l_ldnum * sizeof (struct link_map *);
-
- if (new_size > needed_space_bytes)
- needed_space
- = extend_alloca (needed_space, needed_space_bytes, new_size);
-
- needed = needed_space;
+ /* l->l_ldnum includes space for the terminating NULL. */
+ if (!scratch_buffer_set_array_size
+ (&needed_space, l->l_ldnum, sizeof (struct link_map *)))
+ _dl_signal_error (ENOMEM, map->l_name, NULL,
+ N_("cannot allocate dependency buffer"));
+ needed = needed_space.data;
}
if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
@@ -250,17 +245,9 @@ _dl_map_object_deps (struct link_map *map,
/* Store the tag in the argument structure. */
args.name = name;
- bool malloced;
- int err = _dl_catch_error (&objname, &errstring, &malloced,
- openaux, &args);
- if (__glibc_unlikely (errstring != NULL))
+ int err = _dl_catch_exception (&exception, openaux, &args);
+ if (__glibc_unlikely (exception.errstring != NULL))
{
- char *new_errstring = strdupa (errstring);
- objname = strdupa (objname);
- if (malloced)
- free ((char *) errstring);
- errstring = new_errstring;
-
if (err)
errno_reason = err;
else
@@ -313,31 +300,18 @@ _dl_map_object_deps (struct link_map *map,
/* We must be prepared that the addressed shared
object is not available. For filter objects the dependency
must be available. */
- bool malloced;
- int err = _dl_catch_error (&objname, &errstring, &malloced,
- openaux, &args);
-
- if (__glibc_unlikely (errstring != NULL))
+ int err = _dl_catch_exception (&exception, openaux, &args);
+ if (__glibc_unlikely (exception.errstring != NULL))
{
if (d->d_tag == DT_AUXILIARY)
{
/* We are not interested in the error message. */
- assert (errstring != NULL);
- if (malloced)
- free ((char *) errstring);
-
+ _dl_exception_free (&exception);
/* Simply ignore this error and continue the work. */
continue;
}
else
{
-
- char *new_errstring = strdupa (errstring);
- objname = strdupa (objname);
- if (malloced)
- free ((char *) errstring);
- errstring = new_errstring;
-
if (err)
errno_reason = err;
else
@@ -463,8 +437,11 @@ _dl_map_object_deps (struct link_map *map,
struct link_map **l_initfini = (struct link_map **)
malloc ((2 * nneeded + 1) * sizeof needed[0]);
if (l_initfini == NULL)
- _dl_signal_error (ENOMEM, map->l_name, NULL,
- N_("cannot allocate dependency list"));
+ {
+ scratch_buffer_free (&needed_space);
+ _dl_signal_error (ENOMEM, map->l_name, NULL,
+ N_("cannot allocate dependency list"));
+ }
l_initfini[0] = l;
memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
memcpy (&l_initfini[nneeded + 1], l_initfini,
@@ -482,6 +459,8 @@ _dl_map_object_deps (struct link_map *map,
}
out:
+ scratch_buffer_free (&needed_space);
+
if (errno == 0 && errno_saved != 0)
__set_errno (errno_saved);
@@ -610,62 +589,9 @@ Filters not supported with LD_TRACE_PRELINKING"));
itself will always be initialize last. */
memcpy (l_initfini, map->l_searchlist.r_list,
nlist * sizeof (struct link_map *));
- if (__glibc_likely (nlist > 1))
- {
- /* We can skip looking for the binary itself which is at the front
- of the search list. */
- i = 1;
- uint16_t seen[nlist];
- memset (seen, 0, nlist * sizeof (seen[0]));
- while (1)
- {
- /* Keep track of which object we looked at this round. */
- ++seen[i];
- struct link_map *thisp = l_initfini[i];
-
- /* Find the last object in the list for which the current one is
- a dependency and move the current object behind the object
- with the dependency. */
- unsigned int k = nlist - 1;
- while (k > i)
- {
- struct link_map **runp = l_initfini[k]->l_initfini;
- if (runp != NULL)
- /* Look through the dependencies of the object. */
- while (*runp != NULL)
- if (__glibc_unlikely (*runp++ == thisp))
- {
- /* Move the current object to the back past the last
- object with it as the dependency. */
- memmove (&l_initfini[i], &l_initfini[i + 1],
- (k - i) * sizeof (l_initfini[0]));
- l_initfini[k] = thisp;
-
- if (seen[i + 1] > nlist - i)
- {
- ++i;
- goto next_clear;
- }
-
- uint16_t this_seen = seen[i];
- memmove (&seen[i], &seen[i + 1],
- (k - i) * sizeof (seen[0]));
- seen[k] = this_seen;
-
- goto next;
- }
-
- --k;
- }
-
- if (++i == nlist)
- break;
- next_clear:
- memset (&seen[i], 0, (nlist - i) * sizeof (seen[0]));
-
- next:;
- }
- }
+ /* We can skip looking for the binary itself which is at the front of
+ the search list. */
+ _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false);
/* Terminate the list of dependencies. */
l_initfini[nlist] = NULL;
@@ -683,6 +609,6 @@ Filters not supported with LD_TRACE_PRELINKING"));
_dl_scope_free (old_l_initfini);
if (errno_reason)
- _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, objname,
- NULL, errstring);
+ _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason,
+ &exception, NULL);
}
diff --git a/elf/dl-dst.h b/elf/dl-dst.h
index 26bfe65de9..859032be0d 100644
--- a/elf/dl-dst.h
+++ b/elf/dl-dst.h
@@ -1,5 +1,5 @@
/* Handling of dynamic sring tokens.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2018 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
@@ -18,19 +18,6 @@
#include "trusted-dirs.h"
-/* Determine the number of DST elements in the name. Only if IS_PATH is
- nonzero paths are recognized (i.e., multiple, ':' separated filenames). */
-#define DL_DST_COUNT(name, is_path) \
- ({ \
- size_t __cnt = 0; \
- const char *__sf = strchr (name, '$'); \
- \
- if (__glibc_unlikely (__sf != NULL)) \
- __cnt = _dl_dst_count (__sf, is_path); \
- \
- __cnt; })
-
-
#ifdef SHARED
# define IS_RTLD(l) (l) == &GL(dl_rtld_map)
#else
diff --git a/elf/dl-environ.c b/elf/dl-environ.c
index 5240e9de40..b20045b870 100644
--- a/elf/dl-environ.c
+++ b/elf/dl-environ.c
@@ -1,5 +1,5 @@
/* Environment handling for dynamic loader.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -24,7 +24,6 @@
/* Walk through the environment of the process and return all entries
starting with `LD_'. */
char *
-internal_function
_dl_next_ld_env_entry (char ***position)
{
char **current = *position;
diff --git a/elf/dl-error-minimal.c b/elf/dl-error-minimal.c
new file mode 100644
index 0000000000..583f2f574a
--- /dev/null
+++ b/elf/dl-error-minimal.c
@@ -0,0 +1,23 @@
+/* Error handling for runtime dynamic linker, minimal version.
+ Copyright (C) 1995-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This version does lives in ld.so, does not use thread-local data
+ and supports _dl_signal_cerror and _dl_receive_error. */
+
+#define DL_ERROR_BOOTSTRAP 1
+#include "dl-error-skeleton.c"
diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c
new file mode 100644
index 0000000000..d5f418ab18
--- /dev/null
+++ b/elf/dl-error-skeleton.c
@@ -0,0 +1,239 @@
+/* Template for error handling for runtime dynamic linker.
+ Copyright (C) 1995-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* The following macro needs to be defined before including this
+ skeleton file:
+
+ DL_ERROR_BOOTSTRAP
+
+ If 1, do not use TLS and implement _dl_signal_cerror and
+ _dl_receive_error. If 0, TLS is used, and the variants with
+ error callbacks are not provided. */
+
+
+#include <libintl.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <stdio.h>
+
+/* This structure communicates state between _dl_catch_error and
+ _dl_signal_error. */
+struct catch
+ {
+ struct dl_exception *exception; /* The exception data is stored there. */
+ volatile int *errcode; /* Return value of _dl_signal_error. */
+ jmp_buf env; /* longjmp here on error. */
+ };
+
+/* Multiple threads at once can use the `_dl_catch_error' function. The
+ calls can come from `_dl_map_object_deps', `_dlerror_run', or from
+ any of the libc functionality which loads dynamic objects (NSS, iconv).
+ Therefore we have to be prepared to save the state in thread-local
+ memory. */
+#if !DL_ERROR_BOOTSTRAP
+static __thread struct catch *catch_hook attribute_tls_model_ie;
+#else
+/* The version of this code in ld.so cannot use thread-local variables
+ and is used during bootstrap only. */
+static struct catch *catch_hook;
+#endif
+
+#if DL_ERROR_BOOTSTRAP
+/* This points to a function which is called when an continuable error is
+ received. Unlike the handling of `catch' this function may return.
+ The arguments will be the `errstring' and `objname'.
+
+ Since this functionality is not used in normal programs (only in ld.so)
+ we do not care about multi-threaded programs here. We keep this as a
+ global variable. */
+static receiver_fct receiver;
+#endif /* DL_ERROR_BOOTSTRAP */
+
+/* Lossage while resolving the program's own symbols is always fatal. */
+static void
+__attribute__ ((noreturn))
+fatal_error (int errcode, const char *objname, const char *occasion,
+ const char *errstring)
+{
+ char buffer[1024];
+ _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
+ RTLD_PROGNAME,
+ occasion ?: N_("error while loading shared libraries"),
+ objname, *objname ? ": " : "",
+ errstring, errcode ? ": " : "",
+ (errcode
+ ? __strerror_r (errcode, buffer, sizeof buffer)
+ : ""));
+}
+
+void
+_dl_signal_exception (int errcode, struct dl_exception *exception,
+ const char *occasion)
+{
+ struct catch *lcatch = catch_hook;
+ if (lcatch != NULL)
+ {
+ *lcatch->exception = *exception;
+ *lcatch->errcode = errcode;
+
+ /* We do not restore the signal mask because none was saved. */
+ __longjmp (lcatch->env[0].__jmpbuf, 1);
+ }
+ else
+ fatal_error (errcode, exception->objname, occasion, exception->errstring);
+}
+libc_hidden_def (_dl_signal_exception)
+
+void
+_dl_signal_error (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+{
+ struct catch *lcatch = catch_hook;
+
+ if (! errstring)
+ errstring = N_("DYNAMIC LINKER BUG!!!");
+
+ if (lcatch != NULL)
+ {
+ _dl_exception_create (lcatch->exception, objname, errstring);
+ *lcatch->errcode = errcode;
+
+ /* We do not restore the signal mask because none was saved. */
+ __longjmp (lcatch->env[0].__jmpbuf, 1);
+ }
+ else
+ fatal_error (errcode, objname, occation, errstring);
+}
+libc_hidden_def (_dl_signal_error)
+
+
+#if DL_ERROR_BOOTSTRAP
+void
+_dl_signal_cexception (int errcode, struct dl_exception *exception,
+ const char *occasion)
+{
+ if (__builtin_expect (GLRO(dl_debug_mask)
+ & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
+ _dl_debug_printf ("%s: error: %s: %s (%s)\n",
+ exception->objname, occasion,
+ exception->errstring, receiver ? "continued" : "fatal");
+
+ if (receiver)
+ {
+ /* We are inside _dl_receive_error. Call the user supplied
+ handler and resume the work. The receiver will still be
+ installed. */
+ (*receiver) (errcode, exception->objname, exception->errstring);
+ }
+ else
+ _dl_signal_exception (errcode, exception, occasion);
+}
+
+void
+_dl_signal_cerror (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+{
+ if (__builtin_expect (GLRO(dl_debug_mask)
+ & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
+ _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
+ errstring, receiver ? "continued" : "fatal");
+
+ if (receiver)
+ {
+ /* We are inside _dl_receive_error. Call the user supplied
+ handler and resume the work. The receiver will still be
+ installed. */
+ (*receiver) (errcode, objname, errstring);
+ }
+ else
+ _dl_signal_error (errcode, objname, occation, errstring);
+}
+#endif /* DL_ERROR_BOOTSTRAP */
+
+int
+_dl_catch_exception (struct dl_exception *exception,
+ void (*operate) (void *), void *args)
+{
+ /* We need not handle `receiver' since setting a `catch' is handled
+ before it. */
+
+ /* Only this needs to be marked volatile, because it is the only local
+ variable that gets changed between the setjmp invocation and the
+ longjmp call. All others are just set here (before setjmp) and read
+ in _dl_signal_error (before longjmp). */
+ volatile int errcode;
+
+ struct catch c;
+ /* Don't use an initializer since we don't need to clear C.env. */
+ c.exception = exception;
+ c.errcode = &errcode;
+
+ struct catch *const old = catch_hook;
+ catch_hook = &c;
+
+ /* Do not save the signal mask. */
+ if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0)
+ {
+ (*operate) (args);
+ catch_hook = old;
+ *exception = (struct dl_exception) { NULL };
+ return 0;
+ }
+
+ /* We get here only if we longjmp'd out of OPERATE.
+ _dl_signal_exception has already stored values into
+ *EXCEPTION. */
+ catch_hook = old;
+ return errcode;
+}
+libc_hidden_def (_dl_catch_exception)
+
+int
+_dl_catch_error (const char **objname, const char **errstring,
+ bool *mallocedp, void (*operate) (void *), void *args)
+{
+ struct dl_exception exception;
+ int errorcode = _dl_catch_exception (&exception, operate, args);
+ *objname = exception.objname;
+ *errstring = exception.errstring;
+ *mallocedp = exception.message_buffer == exception.errstring;
+ return errorcode;
+}
+libc_hidden_def (_dl_catch_error)
+
+#if DL_ERROR_BOOTSTRAP
+void
+_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
+{
+ struct catch *old_catch = catch_hook;
+ receiver_fct old_receiver = receiver;
+
+ /* Set the new values. */
+ catch_hook = NULL;
+ receiver = fct;
+
+ (*operate) (args);
+
+ catch_hook = old_catch;
+ receiver = old_receiver;
+}
+#endif /* DL_ERROR_BOOTSTRAP */
diff --git a/elf/dl-error.c b/elf/dl-error.c
index bd22ec6cf0..272bee762b 100644
--- a/elf/dl-error.c
+++ b/elf/dl-error.c
@@ -1,5 +1,5 @@
-/* Error handling for runtime dynamic linker.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+/* Error handling for runtime dynamic linker, full version.
+ Copyright (C) 1995-2018 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
@@ -16,206 +16,12 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <libintl.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <ldsodefs.h>
+/* This implementation lives in libc.so because it uses thread-local
+ data, which is not available in ld.so. It interposes the version
+ in dl-error-minimal.c after ld.so bootstrap.
-/* This structure communicates state between _dl_catch_error and
- _dl_signal_error. */
-struct catch
- {
- const char **objname; /* Object/File name. */
- const char **errstring; /* Error detail filled in here. */
- bool *malloced; /* Nonzero if the string is malloced
- by the libc malloc. */
- volatile int *errcode; /* Return value of _dl_signal_error. */
- jmp_buf env; /* longjmp here on error. */
- };
+ The signal/catch mechanism is used by the audit framework, which
+ means that even in ld.so, not all errors are fatal. */
-/* Multiple threads at once can use the `_dl_catch_error' function. The
- calls can come from `_dl_map_object_deps', `_dlerror_run', or from
- any of the libc functionality which loads dynamic objects (NSS, iconv).
- Therefore we have to be prepared to save the state in thread-local
- memory. The _dl_error_catch_tsd function pointer is reset by the thread
- library so that it returns the address of a thread-local variable. */
-
-
-/* This message we return as a last resort. We define the string in a
- variable since we have to avoid freeing it and so have to enable
- a pointer comparison. See below and in dlfcn/dlerror.c. */
-static const char _dl_out_of_memory[] = "out of memory";
-
-
-/* This points to a function which is called when an continuable error is
- received. Unlike the handling of `catch' this function may return.
- The arguments will be the `errstring' and `objname'.
-
- Since this functionality is not used in normal programs (only in ld.so)
- we do not care about multi-threaded programs here. We keep this as a
- global variable. */
-static receiver_fct receiver;
-
-#ifdef _LIBC_REENTRANT
-# define CATCH_HOOK (*(struct catch **) (*GL(dl_error_catch_tsd)) ())
-#else
-static struct catch *catch_hook;
-# define CATCH_HOOK catch_hook
-#endif
-
-void
-internal_function
-_dl_signal_error (int errcode, const char *objname, const char *occation,
- const char *errstring)
-{
- struct catch *lcatch;
-
- if (! errstring)
- errstring = N_("DYNAMIC LINKER BUG!!!");
-
- lcatch = CATCH_HOOK;
- if (objname == NULL)
- objname = "";
- if (lcatch != NULL)
- {
- /* We are inside _dl_catch_error. Return to it. We have to
- duplicate the error string since it might be allocated on the
- stack. The object name is always a string constant. */
- size_t len_objname = strlen (objname) + 1;
- size_t len_errstring = strlen (errstring) + 1;
-
- char *errstring_copy = malloc (len_objname + len_errstring);
- if (errstring_copy != NULL)
- {
- /* Make a copy of the object file name and the error string. */
- *lcatch->objname = memcpy (__mempcpy (errstring_copy,
- errstring, len_errstring),
- objname, len_objname);
- *lcatch->errstring = errstring_copy;
-
- /* If the main executable is relocated it means the libc's malloc
- is used. */
- bool malloced = true;
-#ifdef SHARED
- malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
- && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
-#endif
- *lcatch->malloced = malloced;
- }
- else
- {
- /* This is better than nothing. */
- *lcatch->objname = "";
- *lcatch->errstring = _dl_out_of_memory;
- *lcatch->malloced = false;
- }
-
- *lcatch->errcode = errcode;
-
- /* We do not restore the signal mask because none was saved. */
- __longjmp (lcatch->env[0].__jmpbuf, 1);
- }
- else
- {
- /* Lossage while resolving the program's own symbols is always fatal. */
- char buffer[1024];
- _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
- RTLD_PROGNAME,
- occation ?: N_("error while loading shared libraries"),
- objname, *objname ? ": " : "",
- errstring, errcode ? ": " : "",
- (errcode
- ? __strerror_r (errcode, buffer, sizeof buffer)
- : ""));
- }
-}
-
-
-void
-internal_function
-_dl_signal_cerror (int errcode, const char *objname, const char *occation,
- const char *errstring)
-{
- if (__builtin_expect (GLRO(dl_debug_mask)
- & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
- _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
- errstring, receiver ? "continued" : "fatal");
-
- if (receiver)
- {
- /* We are inside _dl_receive_error. Call the user supplied
- handler and resume the work. The receiver will still be
- installed. */
- (*receiver) (errcode, objname, errstring);
- }
- else
- _dl_signal_error (errcode, objname, occation, errstring);
-}
-
-
-int
-internal_function
-_dl_catch_error (const char **objname, const char **errstring,
- bool *mallocedp, void (*operate) (void *), void *args)
-{
- /* We need not handle `receiver' since setting a `catch' is handled
- before it. */
-
- /* Only this needs to be marked volatile, because it is the only local
- variable that gets changed between the setjmp invocation and the
- longjmp call. All others are just set here (before setjmp) and read
- in _dl_signal_error (before longjmp). */
- volatile int errcode;
-
- struct catch c;
- /* Don't use an initializer since we don't need to clear C.env. */
- c.objname = objname;
- c.errstring = errstring;
- c.malloced = mallocedp;
- c.errcode = &errcode;
-
- struct catch **const catchp = &CATCH_HOOK;
- struct catch *const old = *catchp;
- *catchp = &c;
-
- /* Do not save the signal mask. */
- if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0)
- {
- (*operate) (args);
- *catchp = old;
- *objname = NULL;
- *errstring = NULL;
- *mallocedp = false;
- return 0;
- }
-
- /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has
- already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */
- *catchp = old;
- return errcode;
-}
-
-
-void
-internal_function
-_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
-{
- struct catch **const catchp = &CATCH_HOOK;
- struct catch *old_catch;
- receiver_fct old_receiver;
-
- old_catch = *catchp;
- old_receiver = receiver;
-
- /* Set the new values. */
- *catchp = NULL;
- receiver = fct;
-
- (*operate) (args);
-
- *catchp = old_catch;
- receiver = old_receiver;
-}
+#define DL_ERROR_BOOTSTRAP 0
+#include "dl-error-skeleton.c"
diff --git a/elf/dl-exception.c b/elf/dl-exception.c
new file mode 100644
index 0000000000..1c63e4a3a6
--- /dev/null
+++ b/elf/dl-exception.c
@@ -0,0 +1,202 @@
+/* ld.so error exception allocation and deallocation.
+ Copyright (C) 1995-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+/* This message we return as a last resort. We define the string in a
+ variable since we have to avoid freeing it and so have to enable
+ a pointer comparison. See below and in dlfcn/dlerror.c. */
+static const char _dl_out_of_memory[] = "out of memory";
+
+/* Dummy allocation object used if allocating the message buffer
+ fails. */
+static void
+oom_exception (struct dl_exception *exception)
+{
+ exception->objname = "";
+ exception->errstring = _dl_out_of_memory;
+ exception->message_buffer = NULL;
+}
+
+static void
+__attribute__ ((noreturn))
+length_mismatch (void)
+{
+ _dl_fatal_printf ("Fatal error: "
+ "length accounting in _dl_exception_create_format\n");
+}
+
+/* Adjust the message buffer to indicate whether it is possible to
+ free it. EXCEPTION->errstring must be a potentially deallocatable
+ pointer. */
+static void
+adjust_message_buffer (struct dl_exception *exception)
+{
+ /* If the main executable is relocated it means the libc's malloc
+ is used. */
+ bool malloced = true;
+#ifdef SHARED
+ malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
+ && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
+#endif
+ if (malloced)
+ exception->message_buffer = (char *) exception->errstring;
+ else
+ exception->message_buffer = NULL;
+}
+
+void
+_dl_exception_create (struct dl_exception *exception, const char *objname,
+ const char *errstring)
+{
+ if (objname == NULL)
+ objname = "";
+ size_t len_objname = strlen (objname) + 1;
+ size_t len_errstring = strlen (errstring) + 1;
+ char *errstring_copy = malloc (len_objname + len_errstring);
+ if (errstring_copy != NULL)
+ {
+ /* Make a copy of the object file name and the error string. */
+ exception->objname = memcpy (__mempcpy (errstring_copy,
+ errstring, len_errstring),
+ objname, len_objname);
+ exception->errstring = errstring_copy;
+ adjust_message_buffer (exception);
+ }
+ else
+ oom_exception (exception);
+}
+rtld_hidden_def (_dl_exception_create)
+
+void
+_dl_exception_create_format (struct dl_exception *exception, const char *objname,
+ const char *fmt, ...)
+{
+ if (objname == NULL)
+ objname = "";
+ size_t len_objname = strlen (objname) + 1;
+ /* Compute the length of the result. Include room for two NUL
+ bytes. */
+ size_t length = len_objname + 1;
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ for (const char *p = fmt; *p != '\0'; ++p)
+ if (*p == '%')
+ {
+ ++p;
+ switch (*p)
+ {
+ case 's':
+ length += strlen (va_arg (ap, const char *));
+ break;
+ default:
+ /* Assumed to be '%'. */
+ ++length;
+ break;
+ }
+ }
+ else
+ ++length;
+ va_end (ap);
+ }
+
+ if (length > PTRDIFF_MAX)
+ {
+ oom_exception (exception);
+ return;
+ }
+ char *errstring = malloc (length);
+ if (errstring == NULL)
+ {
+ oom_exception (exception);
+ return;
+ }
+ exception->errstring = errstring;
+ adjust_message_buffer (exception);
+
+ /* Copy the error message to errstring. */
+ {
+ /* Next byte to be written in errstring. */
+ char *wptr = errstring;
+ /* End of the allocated string. */
+ char *const end = errstring + length;
+
+ va_list ap;
+ va_start (ap, fmt);
+
+ for (const char *p = fmt; *p != '\0'; ++p)
+ if (*p == '%')
+ {
+ ++p;
+ switch (*p)
+ {
+ case 's':
+ {
+ const char *ptr = va_arg (ap, const char *);
+ size_t len_ptr = strlen (ptr);
+ if (len_ptr > end - wptr)
+ length_mismatch ();
+ wptr = __mempcpy (wptr, ptr, len_ptr);
+ }
+ break;
+ case '%':
+ if (wptr == end)
+ length_mismatch ();
+ *wptr = '%';
+ ++wptr;
+ break;
+ default:
+ _dl_fatal_printf ("Fatal error:"
+ " invalid format in exception string\n");
+ }
+ }
+ else
+ {
+ if (wptr == end)
+ length_mismatch ();
+ *wptr = *p;
+ ++wptr;
+ }
+
+ if (wptr == end)
+ length_mismatch ();
+ *wptr = '\0';
+ ++wptr;
+ if (len_objname != end - wptr)
+ length_mismatch ();
+ exception->objname = memcpy (wptr, objname, len_objname);
+ }
+}
+rtld_hidden_def (_dl_exception_create_format)
+
+void
+_dl_exception_free (struct dl_exception *exception)
+{
+ free (exception->message_buffer);
+ exception->objname = NULL;
+ exception->errstring = NULL;
+ exception->message_buffer = NULL;
+}
+rtld_hidden_def (_dl_exception_free)
diff --git a/elf/dl-execstack.c b/elf/dl-execstack.c
index 69c966e8e2..baea092904 100644
--- a/elf/dl-execstack.c
+++ b/elf/dl-execstack.c
@@ -1,5 +1,5 @@
/* Stack executability handling for GNU dynamic linker. Stub version.
- Copyright (C) 2003-2016 Free Software Foundation, Inc.
+ Copyright (C) 2003-2018 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
@@ -23,7 +23,6 @@
so as to mprotect it. */
int
-internal_function
_dl_make_stack_executable (void **stack_endp)
{
return ENOSYS;
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 5864b8e066..3cfc262400 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -1,5 +1,5 @@
/* Call the termination functions of loaded shared objects.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -26,106 +26,6 @@ typedef void (*fini_t) (void);
void
-internal_function
-_dl_sort_fini (struct link_map **maps, size_t nmaps, char *used, Lmid_t ns)
-{
- /* A list of one element need not be sorted. */
- if (nmaps == 1)
- return;
-
- /* We can skip looking for the binary itself which is at the front
- of the search list for the main namespace. */
- unsigned int i = ns == LM_ID_BASE;
- uint16_t seen[nmaps];
- memset (seen, 0, nmaps * sizeof (seen[0]));
- while (1)
- {
- /* Keep track of which object we looked at this round. */
- ++seen[i];
- struct link_map *thisp = maps[i];
-
- /* Do not handle ld.so in secondary namespaces and object which
- are not removed. */
- if (thisp != thisp->l_real || thisp->l_idx == -1)
- goto skip;
-
- /* Find the last object in the list for which the current one is
- a dependency and move the current object behind the object
- with the dependency. */
- unsigned int k = nmaps - 1;
- while (k > i)
- {
- struct link_map **runp = maps[k]->l_initfini;
- if (runp != NULL)
- /* Look through the dependencies of the object. */
- while (*runp != NULL)
- if (__glibc_unlikely (*runp++ == thisp))
- {
- move:
- /* Move the current object to the back past the last
- object with it as the dependency. */
- memmove (&maps[i], &maps[i + 1],
- (k - i) * sizeof (maps[0]));
- maps[k] = thisp;
-
- if (used != NULL)
- {
- char here_used = used[i];
- memmove (&used[i], &used[i + 1],
- (k - i) * sizeof (used[0]));
- used[k] = here_used;
- }
-
- if (seen[i + 1] > nmaps - i)
- {
- ++i;
- goto next_clear;
- }
-
- uint16_t this_seen = seen[i];
- memmove (&seen[i], &seen[i + 1], (k - i) * sizeof (seen[0]));
- seen[k] = this_seen;
-
- goto next;
- }
-
- if (__glibc_unlikely (maps[k]->l_reldeps != NULL))
- {
- unsigned int m = maps[k]->l_reldeps->act;
- struct link_map **relmaps = &maps[k]->l_reldeps->list[0];
-
- /* Look through the relocation dependencies of the object. */
- while (m-- > 0)
- if (__glibc_unlikely (relmaps[m] == thisp))
- {
- /* If a cycle exists with a link time dependency,
- preserve the latter. */
- struct link_map **runp = thisp->l_initfini;
- if (runp != NULL)
- while (*runp != NULL)
- if (__glibc_unlikely (*runp++ == maps[k]))
- goto ignore;
- goto move;
- }
- ignore:;
- }
-
- --k;
- }
-
- skip:
- if (++i == nmaps)
- break;
- next_clear:
- memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0]));
-
- next:;
- }
-}
-
-
-void
-internal_function
_dl_fini (void)
{
/* Lots of fun ahead. We have to call the destructors for all still
@@ -188,8 +88,11 @@ _dl_fini (void)
assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
unsigned int nmaps = i;
- /* Now we have to do the sorting. */
- _dl_sort_fini (maps, nmaps, NULL, ns);
+ /* Now we have to do the sorting. We can skip looking for the
+ binary itself which is at the front of the search list for
+ the main namespace. */
+ _dl_sort_maps (maps + (ns == LM_ID_BASE), nmaps - (ns == LM_ID_BASE),
+ NULL, true);
/* We do not rely on the linked list of loaded object anymore
from this point on. We have our own list here (maps). The
diff --git a/elf/dl-fptr.c b/elf/dl-fptr.c
index 1eb360faad..027c5029eb 100644
--- a/elf/dl-fptr.c
+++ b/elf/dl-fptr.c
@@ -1,5 +1,5 @@
/* Manage function descriptors. Generic version.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2018 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
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index 6004ff264d..23482a88a1 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -1,5 +1,5 @@
/* Hardware capability support for run-time dynamic loader.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2018 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
@@ -24,6 +24,7 @@
#include <ldsodefs.h>
#include <dl-procinfo.h>
+#include <dl-hwcaps.h>
#ifdef _DL_FIRST_PLATFORM
# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
@@ -33,12 +34,12 @@
/* Return an array of useful/necessary hardware capability names. */
const struct r_strlenpair *
-internal_function
_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
size_t *max_capstrlen)
{
+ uint64_t hwcap_mask = GET_HWCAP_MASK();
/* Determine how many important bits are set. */
- uint64_t masked = GLRO(dl_hwcap) & GLRO(dl_hwcap_mask);
+ uint64_t masked = GLRO(dl_hwcap) & hwcap_mask;
size_t cnt = platform != NULL;
size_t n, m;
size_t total;
@@ -66,6 +67,18 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
{
const ElfW(Addr) start = (phdr[i].p_vaddr
+ GLRO(dl_sysinfo_map)->l_addr);
+ /* NB: Some PT_NOTE segment may have alignment value of 0
+ or 1. gABI specifies that PT_NOTE segments should be
+ aligned to 4 bytes in 32-bit objects and to 8 bytes in
+ 64-bit objects. As a Linux extension, we also support
+ 4 byte alignment in 64-bit objects. If p_align is less
+ than 4, we treate alignment as 4 bytes since some note
+ segments have 0 or 1 byte alignment. */
+ ElfW(Addr) align = phdr[i].p_align;
+ if (align < 4)
+ align = 4;
+ else if (align != 4 && align != 8)
+ continue;
/* The standard ELF note layout is exactly as the anonymous struct.
The next element is a variable length vendor name of length
VENDORLEN (with a real length rounded to ElfW(Word)), followed
@@ -79,7 +92,6 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
} *note = (const void *) start;
while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
{
-#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
/* The layout of the type 2, vendor "GNU" note is as follows:
.long <Number of capabilities enabled by this note>
.long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
@@ -90,17 +102,18 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
&& !memcmp ((note + 1), "GNU", sizeof "GNU")
&& note->datalen > 2 * sizeof (ElfW(Word)) + 2)
{
- const ElfW(Word) *p = ((const void *) (note + 1)
- + ROUND (sizeof "GNU"));
+ const ElfW(Word) *p
+ = ((const void *) note
+ + ELF_NOTE_DESC_OFFSET (sizeof "GNU", align));
cnt += *p++;
++p; /* Skip mask word. */
dsocaps = (const char *) p; /* Pseudo-string "<b>name" */
dsocapslen = note->datalen - sizeof *p * 2;
break;
}
- note = ((const void *) (note + 1)
- + ROUND (note->vendorlen) + ROUND (note->datalen));
-#undef ROUND
+ note = ((const void *) note
+ + ELF_NOTE_NEXT_OFFSET (note->vendorlen,
+ note->datalen, align));
}
if (dsocaps != NULL)
break;
@@ -125,7 +138,12 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT).
So there is no way to request ignoring an OS-supplied dsocap
string and bit like you can ignore an OS-supplied HWCAP bit. */
- GLRO(dl_hwcap_mask) |= (uint64_t) mask << _DL_FIRST_EXTRA;
+ hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA;
+#if HAVE_TUNABLES
+ TUNABLE_SET (glibc, tune, hwcap_mask, uint64_t, hwcap_mask);
+#else
+ GLRO(dl_hwcap_mask) = hwcap_mask;
+#endif
size_t len;
for (const char *p = dsocaps; p < dsocaps + dsocapslen; p += len + 1)
{
diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h
new file mode 100644
index 0000000000..17f0da4c73
--- /dev/null
+++ b/elf/dl-hwcaps.h
@@ -0,0 +1,30 @@
+/* Hardware capability support for run-time dynamic loader.
+ Copyright (C) 2017-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <elf/dl-tunables.h>
+
+#if HAVE_TUNABLES
+# define GET_HWCAP_MASK() TUNABLE_GET (glibc, tune, hwcap_mask, uint64_t, NULL)
+#else
+# ifdef SHARED
+# define GET_HWCAP_MASK() GLRO(dl_hwcap_mask)
+# else
+/* HWCAP_MASK is ignored in static binaries when built without tunables. */
+# define GET_HWCAP_MASK() (0)
+# endif
+#endif
diff --git a/elf/dl-init.c b/elf/dl-init.c
index 818c3aa37c..3e72fa3013 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -1,5 +1,5 @@
/* Run initializers for newly loaded objects.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -75,7 +75,6 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
void
-internal_function
_dl_init (struct link_map *main_map, int argc, char **argv, char **env)
{
ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAY];
diff --git a/elf/dl-iteratephdr.c b/elf/dl-iteratephdr.c
index 1cb6e26233..48d3649053 100644
--- a/elf/dl-iteratephdr.c
+++ b/elf/dl-iteratephdr.c
@@ -1,5 +1,5 @@
/* Get loaded objects program headers.
- Copyright (C) 2001-2016 Free Software Foundation, Inc.
+ Copyright (C) 2001-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
@@ -28,7 +28,6 @@ cancel_handler (void *arg __attribute__((unused)))
__rtld_lock_unlock_recursive (GL(dl_load_write_lock));
}
-hidden_proto (__dl_iterate_phdr)
int
__dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
size_t size, void *data), void *data)
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index d56de1a57a..fc01f5514d 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -1,5 +1,5 @@
/* Handle loading and unloading shared objects for internal libc purposes.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Zack Weinberg <zack@rabi.columbia.edu>, 1999.
@@ -20,6 +20,7 @@
#include <dlfcn.h>
#include <stdlib.h>
#include <ldsodefs.h>
+#include <dl-hash.h>
extern int __libc_argc attribute_hidden;
extern char **__libc_argv attribute_hidden;
@@ -36,15 +37,14 @@ extern char **__environ;
Much of this code came from gconv_dl.c with slight modifications. */
static int
-internal_function
dlerror_run (void (*operate) (void *), void *args)
{
const char *objname;
const char *last_errstring = NULL;
bool malloced;
- int result = (GLRO(dl_catch_error) (&objname, &last_errstring, &malloced,
- operate, args)
+ int result = (_dl_catch_error (&objname, &last_errstring, &malloced,
+ operate, args)
?: last_errstring != NULL);
if (result && malloced)
@@ -79,6 +79,15 @@ struct do_dlsym_args
const ElfW(Sym) *ref;
};
+struct do_dlvsym_args
+{
+ /* dlvsym is like dlsym. */
+ struct do_dlsym_args dlsym;
+
+ /* But dlvsym needs a version as well. */
+ struct r_found_version version;
+};
+
static void
do_dlopen (void *ptr)
{
@@ -100,6 +109,18 @@ do_dlsym (void *ptr)
}
static void
+do_dlvsym (void *ptr)
+{
+ struct do_dlvsym_args *args = ptr;
+ args->dlsym.ref = NULL;
+ args->dlsym.loadbase
+ = GLRO(dl_lookup_symbol_x) (args->dlsym.name, args->dlsym.map,
+ &args->dlsym.ref,
+ args->dlsym.map->l_local_scope,
+ &args->version, 0, 0, NULL);
+}
+
+static void
do_dlclose (void *ptr)
{
GLRO(dl_close) ((struct link_map *) ptr);
@@ -113,6 +134,7 @@ struct dl_open_hook
void *(*dlopen_mode) (const char *name, int mode);
void *(*dlsym) (void *map, const char *name);
int (*dlclose) (void *map);
+ void *(*dlvsym) (void *map, const char *name, const char *version);
};
#ifdef SHARED
@@ -120,6 +142,15 @@ extern struct dl_open_hook *_dl_open_hook;
libc_hidden_proto (_dl_open_hook);
struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
libc_hidden_data_def (_dl_open_hook);
+
+/* The dlvsym member was added retroactively to struct dl_open_hook.
+ Static applications which have it will set _dl_open_hook2 in
+ addition to _dl_open_hook. */
+extern struct dl_open_hook *_dl_open_hook2;
+libc_hidden_proto (_dl_open_hook2);
+struct dl_open_hook *_dl_open_hook2 __attribute__ ((nocommon));
+libc_hidden_data_def (_dl_open_hook2);
+
#else
static void
do_dlsym_private (void *ptr)
@@ -143,7 +174,8 @@ static struct dl_open_hook _dl_open_hook =
{
.dlopen_mode = __libc_dlopen_mode,
.dlsym = __libc_dlsym,
- .dlclose = __libc_dlclose
+ .dlclose = __libc_dlclose,
+ .dlvsym = __libc_dlvsym,
};
#endif
@@ -158,7 +190,7 @@ __libc_dlopen_mode (const char *name, int mode)
args.caller_dlopen = RETURN_ADDRESS (0);
#ifdef SHARED
- if (__glibc_unlikely (_dl_open_hook != NULL))
+ if (!rtld_active ())
return _dl_open_hook->dlopen_mode (name, mode);
return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map);
#else
@@ -193,6 +225,11 @@ __libc_register_dl_open_hook (struct link_map *map)
hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook");
if (hook != NULL)
*hook = &_dl_open_hook;
+
+ /* For dlvsym support. */
+ hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook2");
+ if (hook != NULL)
+ *hook = &_dl_open_hook;
}
#endif
@@ -204,7 +241,7 @@ __libc_dlsym (void *map, const char *name)
args.name = name;
#ifdef SHARED
- if (__glibc_unlikely (_dl_open_hook != NULL))
+ if (!rtld_active ())
return _dl_open_hook->dlsym (map, name);
#endif
return (dlerror_run (do_dlsym, &args) ? NULL
@@ -212,11 +249,44 @@ __libc_dlsym (void *map, const char *name)
}
libc_hidden_def (__libc_dlsym)
+/* Replacement for dlvsym. MAP must be a real map. This function
+ returns NULL without setting the dlerror value in case of static
+ dlopen from an old binary. */
+void *
+__libc_dlvsym (void *map, const char *name, const char *version)
+{
+#ifdef SHARED
+ if (!rtld_active ())
+ {
+ /* The static application is too old and does not provide the
+ dlvsym hook. */
+ if (_dl_open_hook2 == NULL)
+ return NULL;
+ return _dl_open_hook2->dlvsym (map, name, version);
+ }
+#endif
+
+ struct do_dlvsym_args args;
+ args.dlsym.map = map;
+ args.dlsym.name = name;
+
+ /* See _dl_vsym in dl-sym.c. */
+ args.version.name = version;
+ args.version.hidden = 1;
+ args.version.hash = _dl_elf_hash (version);
+ args.version.filename = NULL;
+
+ return (dlerror_run (do_dlvsym, &args) ? NULL
+ : (void *) (DL_SYMBOL_ADDRESS (args.dlsym.loadbase,
+ args.dlsym.ref)));
+}
+libc_hidden_def (__libc_dlvsym)
+
int
__libc_dlclose (void *map)
{
#ifdef SHARED
- if (__glibc_unlikely (_dl_open_hook != NULL))
+ if (!rtld_active ())
return _dl_open_hook->dlclose (map);
#endif
return dlerror_run (do_dlclose, map);
diff --git a/elf/dl-load.c b/elf/dl-load.c
index c0d6249373..c51e4b3718 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1,5 +1,5 @@
/* Map in a shared object's segments from the file.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -30,13 +30,39 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
+
+/* Type for the buffer we put the ELF header and hopefully the program
+ header. This buffer does not really have to be too large. In most
+ cases the program header follows the ELF header directly. If this
+ is not the case all bets are off and we can make the header
+ arbitrarily large and still won't get it read. This means the only
+ question is how large are the ELF and program header combined. The
+ ELF header 32-bit files is 52 bytes long and in 64-bit files is 64
+ bytes long. Each program header entry is again 32 and 56 bytes
+ long respectively. I.e., even with a file which has 10 program
+ header entries we only have to read 372B/624B respectively. Add to
+ this a bit of margin for program notes and reading 512B and 832B
+ for 32-bit and 64-bit files respecitvely is enough. If this
+ heuristic should really fail for some file the code in
+ `_dl_map_object_from_fd' knows how to recover. */
+struct filebuf
+{
+ ssize_t len;
+#if __WORDSIZE == 32
+# define FILEBUF_SIZE 512
+#else
+# define FILEBUF_SIZE 832
+#endif
+ char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
+};
+
#include "dynamic-link.h"
#include <abi-tag.h>
#include <stackinfo.h>
-#include <caller.h>
#include <sysdep.h>
#include <stap-probe.h>
-#include <libc-internal.h>
+#include <libc-pointer-arith.h>
+#include <array_length.h>
#include <dl-dst.h>
#include <dl-load.h>
@@ -44,7 +70,8 @@
#include <dl-unmap-segments.h>
#include <dl-machine-reject-phdr.h>
#include <dl-sysdep-open.h>
-
+#include <dl-prop.h>
+#include <not-cancel.h>
#include <endian.h>
#if BYTE_ORDER == BIG_ENDIAN
@@ -69,31 +96,6 @@ int __stack_prot attribute_hidden attribute_relro
#endif
-/* Type for the buffer we put the ELF header and hopefully the program
- header. This buffer does not really have to be too large. In most
- cases the program header follows the ELF header directly. If this
- is not the case all bets are off and we can make the header
- arbitrarily large and still won't get it read. This means the only
- question is how large are the ELF and program header combined. The
- ELF header 32-bit files is 52 bytes long and in 64-bit files is 64
- bytes long. Each program header entry is again 32 and 56 bytes
- long respectively. I.e., even with a file which has 10 program
- header entries we only have to read 372B/624B respectively. Add to
- this a bit of margin for program notes and reading 512B and 832B
- for 32-bit and 64-bit files respecitvely is enough. If this
- heuristic should really fail for some file the code in
- `_dl_map_object_from_fd' knows how to recover. */
-struct filebuf
-{
- ssize_t len;
-#if __WORDSIZE == 32
-# define FILEBUF_SIZE 512
-#else
-# define FILEBUF_SIZE 832
-#endif
- char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
-};
-
/* This is the decomposed LD_LIBRARY_PATH search path. */
static struct r_search_path_struct env_path_list attribute_relro;
@@ -103,7 +105,9 @@ static size_t ncapstr attribute_relro;
static size_t max_capstrlen attribute_relro;
-/* Get the generated information about the trusted directories. */
+/* Get the generated information about the trusted directories. Use
+ an array of concatenated strings to avoid relocations. See
+ gen-trusted-dirs.awk. */
#include "trusted-dirs.h"
static const char system_dirs[] = SYSTEM_DIRS;
@@ -111,27 +115,7 @@ static const size_t system_dirs_len[] =
{
SYSTEM_DIRS_LEN
};
-#define nsystem_dirs_len \
- (sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
-
-
-static bool
-is_trusted_path (const char *path, size_t len)
-{
- const char *trun = system_dirs;
-
- for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
- {
- if (len == system_dirs_len[idx] && memcmp (trun, path, len) == 0)
- /* Found it. */
- return true;
-
- trun += system_dirs_len[idx] + 1;
- }
-
- return false;
-}
-
+#define nsystem_dirs_len array_length (system_dirs_len)
static bool
is_trusted_path_normalize (const char *path, size_t len)
@@ -139,12 +123,6 @@ is_trusted_path_normalize (const char *path, size_t len)
if (len == 0)
return false;
- if (*path == ':')
- {
- ++path;
- --len;
- }
-
char *npath = (char *) alloca (len + 2);
char *wnp = npath;
while (*path != '\0')
@@ -195,126 +173,167 @@ is_trusted_path_normalize (const char *path, size_t len)
return false;
}
+/* Given a substring starting at INPUT, just after the DST '$' start
+ token, determine if INPUT contains DST token REF, following the
+ ELF gABI rules for DSTs:
+
+ * Longest possible sequence using the rules (greedy).
+
+ * Must start with a $ (enforced by caller).
+
+ * Must follow $ with one underscore or ASCII [A-Za-z] (caller
+ follows these rules for REF) or '{' (start curly quoted name).
+
+ * Must follow first two characters with zero or more [A-Za-z0-9_]
+ (enforced by caller) or '}' (end curly quoted name).
+ If the sequence is a DST matching REF then the length of the DST
+ (excluding the $ sign but including curly braces, if any) is
+ returned, otherwise 0. */
static size_t
-is_dst (const char *start, const char *name, const char *str,
- int is_path, int secure)
+is_dst (const char *input, const char *ref)
{
- size_t len;
bool is_curly = false;
- if (name[0] == '{')
+ /* Is a ${...} input sequence? */
+ if (input[0] == '{')
{
is_curly = true;
- ++name;
+ ++input;
}
- len = 0;
- while (name[len] == str[len] && name[len] != '\0')
- ++len;
-
- if (is_curly)
- {
- if (name[len] != '}')
- return 0;
-
- /* Point again at the beginning of the name. */
- --name;
- /* Skip over closing curly brace and adjust for the --name. */
- len += 2;
- }
- else if (name[len] != '\0' && name[len] != '/'
- && (!is_path || name[len] != ':'))
+ /* Check for matching name, following closing curly brace (if
+ required), or trailing characters which are part of an
+ identifier. */
+ size_t rlen = strlen (ref);
+ if (strncmp (input, ref, rlen) != 0
+ || (is_curly && input[rlen] != '}')
+ || ((input[rlen] >= 'A' && input[rlen] <= 'Z')
+ || (input[rlen] >= 'a' && input[rlen] <= 'z')
+ || (input[rlen] >= '0' && input[rlen] <= '9')
+ || (input[rlen] == '_')))
return 0;
- if (__glibc_unlikely (secure)
- && ((name[len] != '\0' && name[len] != '/'
- && (!is_path || name[len] != ':'))
- || (name != start + 1 && (!is_path || name[-2] != ':'))))
- return 0;
-
- return len;
+ if (is_curly)
+ /* Count the two curly braces. */
+ return rlen + 2;
+ else
+ return rlen;
}
-
+/* INPUT should be the start of a path e.g DT_RPATH or name e.g.
+ DT_NEEDED. The return value is the number of known DSTs found. We
+ count all known DSTs regardless of __libc_enable_secure; the caller
+ is responsible for enforcing the security of the substitution rules
+ (usually _dl_dst_substitute). */
size_t
-_dl_dst_count (const char *name, int is_path)
+_dl_dst_count (const char *input)
{
- const char *const start = name;
size_t cnt = 0;
+ input = strchr (input, '$');
+
+ /* Most likely there is no DST. */
+ if (__glibc_likely (input == NULL))
+ return 0;
+
do
{
size_t len;
- /* $ORIGIN is not expanded for SUID/GUID programs (except if it
- is $ORIGIN alone) and it must always appear first in path. */
- ++name;
- if ((len = is_dst (start, name, "ORIGIN", is_path,
- __libc_enable_secure)) != 0
- || (len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0
- || (len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+ ++input;
+ /* All DSTs must follow ELF gABI rules, see is_dst (). */
+ if ((len = is_dst (input, "ORIGIN")) != 0
+ || (len = is_dst (input, "PLATFORM")) != 0
+ || (len = is_dst (input, "LIB")) != 0)
++cnt;
- name = strchr (name + len, '$');
+ /* There may be more than one DST in the input. */
+ input = strchr (input + len, '$');
}
- while (name != NULL);
+ while (input != NULL);
return cnt;
}
-
+/* Process INPUT for DSTs and store in RESULT using the information
+ from link map L to resolve the DSTs. This function only handles one
+ path at a time and does not handle colon-separated path lists (see
+ fillin_rpath ()). Lastly the size of result in bytes should be at
+ least equal to the value returned by DL_DST_REQUIRED. Note that it
+ is possible for a DT_NEEDED, DT_AUXILIARY, and DT_FILTER entries to
+ have colons, but we treat those as literal colons here, not as path
+ list delimeters. */
char *
-_dl_dst_substitute (struct link_map *l, const char *name, char *result,
- int is_path)
+_dl_dst_substitute (struct link_map *l, const char *input, char *result)
{
- const char *const start = name;
-
- /* Now fill the result path. While copying over the string we keep
- track of the start of the last path element. When we come across
- a DST we copy over the value or (if the value is not available)
- leave the entire path element out. */
+ /* Copy character-by-character from input into the working pointer
+ looking for any DSTs. We track the start of input and if we are
+ going to check for trusted paths, all of which are part of $ORIGIN
+ handling in SUID/SGID cases (see below). In some cases, like when
+ a DST cannot be replaced, we may set result to an empty string and
+ return. */
char *wp = result;
- char *last_elem = result;
+ const char *start = input;
bool check_for_trusted = false;
do
{
- if (__glibc_unlikely (*name == '$'))
+ if (__glibc_unlikely (*input == '$'))
{
const char *repl = NULL;
size_t len;
- ++name;
- if ((len = is_dst (start, name, "ORIGIN", is_path,
- __libc_enable_secure)) != 0)
+ ++input;
+ if ((len = is_dst (input, "ORIGIN")) != 0)
{
- repl = l->l_origin;
+ /* For SUID/GUID programs we normally ignore the path with
+ $ORIGIN in DT_RUNPATH, or DT_RPATH. However, there is
+ one exception to this rule, and it is:
+
+ * $ORIGIN appears as the first path element, and is
+ the only string in the path or is immediately
+ followed by a path separator and the rest of the
+ path,
+
+ and ...
+
+ * The path is rooted in a trusted directory.
+
+ This exception allows such programs to reference
+ shared libraries in subdirectories of trusted
+ directories. The use case is one of general
+ organization and deployment flexibility.
+ Trusted directories are usually such paths as "/lib64"
+ or "/usr/lib64", and the usual RPATHs take the form of
+ [$ORIGIN/../$LIB/somedir]. */
+ if (__glibc_unlikely (__libc_enable_secure)
+ && !(input == start + 1
+ && (input[len] == '\0' || input[len] == '/')))
+ repl = (const char *) -1;
+ else
+ repl = l->l_origin;
+
check_for_trusted = (__libc_enable_secure
&& l->l_type == lt_executable);
}
- else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
+ else if ((len = is_dst (input, "PLATFORM")) != 0)
repl = GLRO(dl_platform);
- else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+ else if ((len = is_dst (input, "LIB")) != 0)
repl = DL_DST_LIB;
if (repl != NULL && repl != (const char *) -1)
{
wp = __stpcpy (wp, repl);
- name += len;
+ input += len;
}
- else if (len > 1)
+ else if (len != 0)
{
- /* We cannot use this path element, the value of the
- replacement is unknown. */
- wp = last_elem;
- name += len;
- while (*name != '\0' && (!is_path || *name != ':'))
- ++name;
- /* Also skip following colon if this is the first rpath
- element, but keep an empty element at the end. */
- if (wp == result && is_path && *name == ':' && name[1] != '\0')
- ++name;
+ /* We found a valid DST that we know about, but we could
+ not find a replacement value for it, therefore we
+ cannot use this path and discard it. */
+ *result = '\0';
+ return result;
}
else
/* No DST we recognize. */
@@ -322,29 +341,26 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
}
else
{
- *wp++ = *name++;
- if (is_path && *name == ':')
- {
- /* In SUID/SGID programs, after $ORIGIN expansion the
- normalized path must be rooted in one of the trusted
- directories. */
- if (__glibc_unlikely (check_for_trusted)
- && !is_trusted_path_normalize (last_elem, wp - last_elem))
- wp = last_elem;
- else
- last_elem = wp;
-
- check_for_trusted = false;
- }
+ *wp++ = *input++;
}
}
- while (*name != '\0');
+ while (*input != '\0');
/* In SUID/SGID programs, after $ORIGIN expansion the normalized
- path must be rooted in one of the trusted directories. */
+ path must be rooted in one of the trusted directories. The $LIB
+ and $PLATFORM DST cannot in any way be manipulated by the caller
+ because they are fixed values that are set by the dynamic loader
+ and therefore any paths using just $LIB or $PLATFORM need not be
+ 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. */
if (__glibc_unlikely (check_for_trusted)
- && !is_trusted_path_normalize (last_elem, wp - last_elem))
- wp = last_elem;
+ && !is_trusted_path_normalize (result, wp - result))
+ {
+ *result = '\0';
+ return result;
+ }
*wp = '\0';
@@ -352,13 +368,13 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
}
-/* Return copy of argument with all recognized dynamic string tokens
- ($ORIGIN and $PLATFORM for now) replaced. On some platforms it
- might not be possible to determine the path from which the object
- belonging to the map is loaded. In this case the path element
- containing $ORIGIN is left out. */
+/* Return a malloc allocated copy of INPUT with all recognized DSTs
+ replaced. On some platforms it might not be possible to determine the
+ path from which the object belonging to the map is loaded. In this
+ case the path containing the DST is left out. On error NULL
+ is returned. */
static char *
-expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
+expand_dynamic_string_token (struct link_map *l, const char *input)
{
/* We make two runs over the string. First we determine how large the
resulting string is and then we copy it over. Since this is no
@@ -368,22 +384,22 @@ expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
size_t total;
char *result;
- /* Determine the number of DST elements. */
- cnt = DL_DST_COUNT (s, is_path);
+ /* Determine the number of DSTs. */
+ cnt = _dl_dst_count (input);
/* If we do not have to replace anything simply copy the string. */
if (__glibc_likely (cnt == 0))
- return __strdup (s);
+ return __strdup (input);
/* Determine the length of the substituted string. */
- total = DL_DST_REQUIRED (l, s, strlen (s), cnt);
+ total = DL_DST_REQUIRED (l, input, strlen (input), cnt);
/* Allocate the necessary memory. */
result = (char *) malloc (total + 1);
if (result == NULL)
return NULL;
- return _dl_dst_substitute (l, s, result, is_path);
+ return _dl_dst_substitute (l, input, result);
}
@@ -392,7 +408,6 @@ expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
be freed if the shared object already has this name.
Returns false if the object already had this name. */
static void
-internal_function
add_name_to_object (struct link_map *l, const char *name)
{
struct libname_list *lnp, *lastp;
@@ -428,42 +443,43 @@ static size_t max_dirnamelen;
static struct r_search_path_elem **
fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
- int check_trusted, const char *what, const char *where,
- struct link_map *l)
+ const char *what, const char *where, struct link_map *l)
{
char *cp;
size_t nelems = 0;
- char *to_free;
while ((cp = __strsep (&rpath, sep)) != NULL)
{
struct r_search_path_elem *dirp;
+ char *to_free = NULL;
+ size_t len = 0;
- to_free = cp = expand_dynamic_string_token (l, cp, 1);
-
- size_t len = strlen (cp);
-
- /* `strsep' can pass an empty string. This has to be
- interpreted as `use the current directory'. */
- if (len == 0)
+ /* `strsep' can pass an empty string. */
+ if (*cp != '\0')
{
- static const char curwd[] = "./";
- cp = (char *) curwd;
- }
+ to_free = cp = expand_dynamic_string_token (l, cp);
- /* Remove trailing slashes (except for "/"). */
- while (len > 1 && cp[len - 1] == '/')
- --len;
+ /* expand_dynamic_string_token can return NULL in case of empty
+ path or memory allocation failure. */
+ if (cp == NULL)
+ continue;
- /* Now add one if there is none so far. */
- if (len > 0 && cp[len - 1] != '/')
- cp[len++] = '/';
+ /* Compute the length after dynamic string token expansion and
+ ignore empty paths. */
+ len = strlen (cp);
+ if (len == 0)
+ {
+ free (to_free);
+ continue;
+ }
- /* Make sure we don't use untrusted directories if we run SUID. */
- if (__glibc_unlikely (check_trusted) && !is_trusted_path (cp, len))
- {
- free (to_free);
- continue;
+ /* Remove trailing slashes (except for "/"). */
+ while (len > 1 && cp[len - 1] == '/')
+ --len;
+
+ /* Now add one if there is none so far. */
+ if (len > 0 && cp[len - 1] != '/')
+ cp[len++] = '/';
}
/* See if this directory is already known. */
@@ -536,13 +552,11 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
static bool
-internal_function
decompose_rpath (struct r_search_path_struct *sps,
const char *rpath, struct link_map *l, const char *what)
{
/* Make a copy we can work with. */
const char *where = l->l_name;
- char *copy;
char *cp;
struct r_search_path_elem **result;
size_t nelems;
@@ -581,22 +595,21 @@ decompose_rpath (struct r_search_path_struct *sps,
while (*inhp != '\0');
}
+ /* Ignore empty rpaths. */
+ if (*rpath == '\0')
+ {
+ sps->dirs = (struct r_search_path_elem **) -1;
+ return false;
+ }
+
/* Make a writable copy. */
- copy = __strdup (rpath);
+ char *copy = __strdup (rpath);
if (copy == NULL)
{
errstring = N_("cannot create RUNPATH/RPATH copy");
goto signal_error;
}
- /* Ignore empty rpaths. */
- if (*copy == 0)
- {
- free (copy);
- sps->dirs = (struct r_search_path_elem **) -1;
- return false;
- }
-
/* Count the number of necessary elements in the result array. */
nelems = 0;
for (cp = copy; *cp != '\0'; ++cp)
@@ -615,12 +628,20 @@ decompose_rpath (struct r_search_path_struct *sps,
_dl_signal_error (ENOMEM, NULL, NULL, errstring);
}
- fillin_rpath (copy, result, ":", 0, what, where, l);
+ fillin_rpath (copy, result, ":", what, where, l);
/* Free the copied RPATH string. `fillin_rpath' make own copies if
necessary. */
free (copy);
+ /* There is no path after expansion. */
+ if (result[0] == NULL)
+ {
+ free (result);
+ sps->dirs = (struct r_search_path_elem **) -1;
+ return false;
+ }
+
sps->dirs = result;
/* The caller will change this value if we haven't used a real malloc. */
sps->malloced = 1;
@@ -656,7 +677,6 @@ cache_rpath (struct link_map *l,
void
-internal_function
_dl_init_paths (const char *llp)
{
size_t idx;
@@ -688,9 +708,8 @@ _dl_init_paths (const char *llp)
+ ncapstr * sizeof (enum r_dir_status))
/ sizeof (struct r_search_path_elem));
- rtld_search_dirs.dirs[0] = (struct r_search_path_elem *)
- malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]))
- * round_size * sizeof (struct r_search_path_elem));
+ rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size
+ * sizeof (*rtld_search_dirs.dirs[0]));
if (rtld_search_dirs.dirs[0] == NULL)
{
errstring = N_("cannot create cache for search path");
@@ -776,37 +795,14 @@ _dl_init_paths (const char *llp)
if (llp != NULL && *llp != '\0')
{
- size_t nllp;
- const char *cp = llp;
- char *llp_tmp;
-
-#ifdef SHARED
- /* Expand DSTs. */
- size_t cnt = DL_DST_COUNT (llp, 1);
- if (__glibc_likely (cnt == 0))
- llp_tmp = strdupa (llp);
- else
- {
- /* Determine the length of the substituted string. */
- size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt);
-
- /* Allocate the necessary memory. */
- llp_tmp = (char *) alloca (total + 1);
- llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1);
- }
-#else
- llp_tmp = strdupa (llp);
-#endif
+ char *llp_tmp = strdupa (llp);
/* Decompose the LD_LIBRARY_PATH contents. First determine how many
elements it has. */
- nllp = 1;
- while (*cp)
- {
- if (*cp == ':' || *cp == ';')
- ++nllp;
- ++cp;
- }
+ size_t nllp = 1;
+ for (const char *cp = llp_tmp; *cp != '\0'; ++cp)
+ if (*cp == ':' || *cp == ';')
+ ++nllp;
env_path_list.dirs = (struct r_search_path_elem **)
malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
@@ -817,8 +813,7 @@ _dl_init_paths (const char *llp)
}
(void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
- __libc_enable_secure, "LD_LIBRARY_PATH",
- NULL, l);
+ "LD_LIBRARY_PATH", NULL, l);
if (env_path_list.dirs[0] == NULL)
{
@@ -840,7 +835,7 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
{
/* The file might already be closed. */
if (fd != -1)
- (void) __close (fd);
+ (void) __close_nocancel (fd);
if (l != NULL && l->l_origin != (char *) -1l)
free ((char *) l->l_origin);
free (l);
@@ -899,7 +894,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
{
/* The object is already loaded.
Just bump its reference count and return it. */
- __close (fd);
+ __close_nocancel (fd);
/* If the name is not in the list of names for this object add
it. */
@@ -927,7 +922,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
/* No need to bump the refcount of the real object, ld.so will
never be unloaded. */
- __close (fd);
+ __close_nocancel (fd);
/* Add the map for the mirrored object to the object list. */
_dl_add_to_namespace_list (l, nsid);
@@ -941,7 +936,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
/* We are not supposed to load the object unless it is already
loaded. So return now. */
free (realname);
- __close (fd);
+ __close_nocancel (fd);
return NULL;
}
@@ -960,7 +955,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
if (_dl_zerofd == -1)
{
free (realname);
- __close (fd);
+ __close_nocancel (fd);
_dl_signal_error (errno, NULL, NULL,
N_("cannot open zero fill device"));
}
@@ -1026,7 +1021,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
{
phdr = alloca (maplength);
__lseek (fd, header->e_phoff, SEEK_SET);
- if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength)
+ if ((size_t) __read_nocancel (fd, (void *) phdr, maplength) != maplength)
{
errstring = N_("cannot read file data");
goto call_lose_errno;
@@ -1055,8 +1050,14 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
segments are mapped in. We record the addresses it says
verbatim, and later correct for the run-time load address. */
case PT_DYNAMIC:
- l->l_ld = (void *) ph->p_vaddr;
- l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+ if (ph->p_filesz)
+ {
+ /* Debuginfo only files from "objcopy --only-keep-debug"
+ contain a PT_DYNAMIC segment with p_filesz == 0. Skip
+ such a segment to avoid a crash later. */
+ l->l_ld = (void *) ph->p_vaddr;
+ l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+ }
break;
case PT_PHDR:
@@ -1135,54 +1136,14 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
}
#ifdef SHARED
- if (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0)
- /* We are loading the executable itself when the dynamic linker
- was executed directly. The setup will happen later. */
- break;
-
-# ifdef _LIBC_REENTRANT
- /* In a static binary there is no way to tell if we dynamically
- loaded libpthread. */
- if (GL(dl_error_catch_tsd) == &_dl_initial_error_catch_tsd)
-# endif
+ /* We are loading the executable itself when the dynamic
+ linker was executed directly. The setup will happen
+ later. Otherwise, the TLS data structures are already
+ initialized, and we assigned a TLS modid above. */
+ assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
+#else
+ assert (false && "TLS not initialized in static application");
#endif
- {
- /* We have not yet loaded libpthread.
- We can do the TLS setup right now! */
-
- void *tcb;
-
- /* The first call allocates TLS bookkeeping data structures.
- Then we allocate the TCB for the initial thread. */
- if (__glibc_unlikely (_dl_tls_setup ())
- || __glibc_unlikely ((tcb = _dl_allocate_tls (NULL)) == NULL))
- {
- errval = ENOMEM;
- errstring = N_("\
-cannot allocate TLS data structures for initial thread");
- goto call_lose;
- }
-
- /* Now we install the TCB in the thread register. */
- errstring = TLS_INIT_TP (tcb);
- if (__glibc_likely (errstring == NULL))
- {
- /* Now we are all good. */
- l->l_tls_modid = ++GL(dl_tls_max_dtv_idx);
- break;
- }
-
- /* The kernel is too old or somesuch. */
- errval = 0;
- _dl_deallocate_tls (tcb, 1);
- goto call_lose;
- }
-
- /* Uh-oh, the binary expects TLS support but we cannot
- provide it. */
- errval = 0;
- errstring = N_("cannot handle TLS data");
- goto call_lose;
break;
case PT_GNU_STACK:
@@ -1193,6 +1154,14 @@ cannot allocate TLS data structures for initial thread");
l->l_relro_addr = ph->p_vaddr;
l->l_relro_size = ph->p_memsz;
break;
+
+ case PT_NOTE:
+ if (_dl_process_pt_note (l, ph, fd, fbp))
+ {
+ errstring = N_("cannot process note segment");
+ goto call_lose;
+ }
+ break;
}
if (__glibc_unlikely (nloadcmds == 0))
@@ -1280,12 +1249,6 @@ cannot allocate TLS data structures for initial thread");
if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
{
- if (__glibc_unlikely (__check_caller (RETURN_ADDRESS (0), allow_ldso) != 0))
- {
- errstring = N_("invalid caller");
- goto call_lose;
- }
-
/* The stack is presently not executable, but this module
requires that it be executable. We must change the
protection of the variable which contains the flags used in
@@ -1336,7 +1299,7 @@ cannot enable executable stack as shared object requires");
l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
/* We are done mapping in the file. We no longer need the descriptor. */
- if (__glibc_unlikely (__close (fd) != 0))
+ if (__glibc_unlikely (__close_nocancel (fd) != 0))
{
errstring = N_("cannot close file descriptor");
goto call_lose_errno;
@@ -1551,7 +1514,7 @@ open_verify (const char *name, int fd,
{
/* An audit library changed what we're supposed to open,
so FD no longer matches it. */
- __close (fd);
+ __close_nocancel (fd);
fd = -1;
}
}
@@ -1559,13 +1522,14 @@ open_verify (const char *name, int fd,
if (fd == -1)
/* Open the file. We always open files read-only. */
- fd = __open (name, O_RDONLY | O_CLOEXEC);
+ fd = __open64_nocancel (name, O_RDONLY | O_CLOEXEC);
if (fd != -1)
{
ElfW(Ehdr) *ehdr;
ElfW(Phdr) *phdr, *ph;
ElfW(Word) *abi_note;
+ ElfW(Word) *abi_note_malloced = NULL;
unsigned int osversion;
size_t maplength;
@@ -1577,8 +1541,8 @@ open_verify (const char *name, int fd,
/* Read in the header. */
do
{
- ssize_t retlen = __libc_read (fd, fbp->buf + fbp->len,
- sizeof (fbp->buf) - fbp->len);
+ ssize_t retlen = __read_nocancel (fd, fbp->buf + fbp->len,
+ sizeof (fbp->buf) - fbp->len);
if (retlen <= 0)
break;
fbp->len += retlen;
@@ -1701,7 +1665,8 @@ open_verify (const char *name, int fd,
{
phdr = alloca (maplength);
__lseek (fd, ehdr->e_phoff, SEEK_SET);
- if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength)
+ if ((size_t) __read_nocancel (fd, (void *) phdr, maplength)
+ != maplength)
{
read_error:
errval = errno;
@@ -1720,23 +1685,49 @@ open_verify (const char *name, int fd,
if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
{
ElfW(Addr) size = ph->p_filesz;
+ /* NB: Some PT_NOTE segment may have alignment value of 0
+ or 1. gABI specifies that PT_NOTE segments should be
+ aligned to 4 bytes in 32-bit objects and to 8 bytes in
+ 64-bit objects. As a Linux extension, we also support
+ 4 byte alignment in 64-bit objects. If p_align is less
+ than 4, we treate alignment as 4 bytes since some note
+ segments have 0 or 1 byte alignment. */
+ ElfW(Addr) align = ph->p_align;
+ if (align < 4)
+ align = 4;
+ else if (align != 4 && align != 8)
+ continue;
if (ph->p_offset + size <= (size_t) fbp->len)
abi_note = (void *) (fbp->buf + ph->p_offset);
else
{
- abi_note = alloca (size);
+ /* Note: __libc_use_alloca is not usable here, because
+ thread info may not have been set up yet. */
+ if (size < __MAX_ALLOCA_CUTOFF)
+ abi_note = alloca (size);
+ else
+ {
+ /* There could be multiple PT_NOTEs. */
+ abi_note_malloced = realloc (abi_note_malloced, size);
+ if (abi_note_malloced == NULL)
+ goto read_error;
+
+ abi_note = abi_note_malloced;
+ }
__lseek (fd, ph->p_offset, SEEK_SET);
- if (__libc_read (fd, (void *) abi_note, size) != size)
- goto read_error;
+ if (__read_nocancel (fd, (void *) abi_note, size) != size)
+ {
+ free (abi_note_malloced);
+ goto read_error;
+ }
}
while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
{
-#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
- ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
- + ROUND (abi_note[0])
- + ROUND (abi_note[1]);
+ ElfW(Addr) note_size
+ = ELF_NOTE_NEXT_OFFSET (abi_note[0], abi_note[1],
+ align);
if (size - 32 < note_size)
{
@@ -1757,13 +1748,14 @@ open_verify (const char *name, int fd,
|| (GLRO(dl_osversion) && GLRO(dl_osversion) < osversion))
{
close_and_out:
- __close (fd);
+ __close_nocancel (fd);
__set_errno (ENOENT);
fd = -1;
}
break;
}
+ free (abi_note_malloced);
}
return fd;
@@ -1873,7 +1865,7 @@ open_path (const char *name, size_t namelen, int mode,
/* The shared object cannot be tested for being SUID
or this bit is not set. In this case we must not
use this object. */
- __close (fd);
+ __close_nocancel (fd);
fd = -1;
/* We simply ignore the file, signal this by setting
the error value which would have been set by `open'. */
@@ -1894,7 +1886,7 @@ open_path (const char *name, size_t namelen, int mode,
{
/* No memory for the name, we certainly won't be able
to load and link it. */
- __close (fd);
+ __close_nocancel (fd);
return -1;
}
}
@@ -1927,7 +1919,6 @@ open_path (const char *name, size_t namelen, int mode,
/* Map in the shared object file NAME. */
struct link_map *
-internal_function
_dl_map_object (struct link_map *loader, const char *name,
int type, int trace_mode, int mode, Lmid_t nsid)
{
@@ -2168,7 +2159,7 @@ _dl_map_object (struct link_map *loader, const char *name,
{
/* The path may contain dynamic string tokens. */
realname = (loader
- ? expand_dynamic_string_token (loader, name, 0)
+ ? expand_dynamic_string_token (loader, name)
: __strdup (name));
if (realname == NULL)
fd = -1;
@@ -2281,7 +2272,6 @@ add_path (struct add_path_state *p, const struct r_search_path_struct *sps,
}
void
-internal_function
_dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
{
if (counting)
diff --git a/elf/dl-load.h b/elf/dl-load.h
index 9fe7118cc7..66ea2e9237 100644
--- a/elf/dl-load.h
+++ b/elf/dl-load.h
@@ -1,5 +1,5 @@
/* Map in a shared object's segments from the file.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index f577759a9d..68ecc6179f 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -1,5 +1,5 @@
/* Look up a symbol in the loaded objects.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -47,23 +47,6 @@ struct sym_val
};
-#define make_string(string, rest...) \
- ({ \
- const char *all[] = { string, ## rest }; \
- size_t len, cnt; \
- char *result, *cp; \
- \
- len = 1; \
- for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- len += strlen (all[cnt]); \
- \
- cp = result = alloca (len); \
- for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- cp = __stpcpy (cp, all[cnt]); \
- \
- result; \
- })
-
/* Statistics function. */
#ifdef SHARED
# define bump_num_relocations() ++GL(dl_num_relocations)
@@ -93,6 +76,7 @@ check_match (const char *const undef_name,
unsigned int stt = ELFW(ST_TYPE) (sym->st_info);
assert (ELF_RTYPE_CLASS_PLT == 1);
if (__glibc_unlikely ((sym->st_value == 0 /* No value. */
+ && sym->st_shndx != SHN_ABS
&& stt != STT_TLS)
|| ELF_MACHINE_SYM_NO_MATCH (sym)
|| (type_class & (sym->st_shndx == SHN_UNDEF))))
@@ -516,6 +500,10 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
#endif
}
+ /* Hidden and internal symbols are local, ignore them. */
+ if (__glibc_unlikely (dl_symbol_visibility_binds_local_p (sym)))
+ goto skip;
+
switch (ELFW(ST_BIND) (sym->st_info))
{
case STB_WEAK:
@@ -573,7 +561,6 @@ dl_new_hash (const char *s)
/* Add extra dependency on MAP to UNDEF_MAP. */
static int
-internal_function
add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
{
struct link_map *runp;
@@ -783,7 +770,6 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
}
static void
-internal_function
_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
const ElfW(Sym) **ref, struct sym_val *value,
const struct r_found_version *version, int type_class,
@@ -797,7 +783,6 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
or in any function which gets called. If this would happen the audit
code might create a thread which can throw off all the scope locking. */
lookup_t
-internal_function
_dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
const ElfW(Sym) **ref,
struct r_scope_elem *symbol_scope[],
@@ -839,17 +824,16 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
for unversioned lookups. */
assert (version != NULL);
const char *reference_name = undef_map ? undef_map->l_name : "";
-
+ struct dl_exception exception;
/* XXX We cannot translate the message. */
- _dl_signal_cerror (0, DSO_FILENAME (reference_name),
- N_("relocation error"),
- make_string ("symbol ", undef_name, ", version ",
- version->name,
- " not defined in file ",
- version->filename,
- " with link time reference",
- res == -2
- ? " (no version symbols)" : ""));
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (reference_name),
+ "symbol %s version %s not defined in file %s"
+ " with link time reference%s",
+ undef_name, version->name, version->filename,
+ res == -2 ? " (no version symbols)" : "");
+ _dl_signal_cexception (0, &exception, N_("relocation error"));
+ _dl_exception_free (&exception);
*ref = NULL;
return 0;
}
@@ -858,7 +842,6 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
if (__glibc_unlikely (current_value.s == NULL))
{
if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
- && skip_map == NULL
&& !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
{
/* We could find no value for a strong reference. */
@@ -866,12 +849,14 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
const char *versionstr = version ? ", version " : "";
const char *versionname = (version && version->name
? version->name : "");
-
+ struct dl_exception exception;
/* XXX We cannot translate the message. */
- _dl_signal_cerror (0, DSO_FILENAME (reference_name),
- N_("symbol lookup error"),
- make_string ("undefined symbol: ", undef_name,
- versionstr, versionname));
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (reference_name),
+ "undefined symbol: %s%s%s",
+ undef_name, versionstr, versionname);
+ _dl_signal_cexception (0, &exception, N_("symbol lookup error"));
+ _dl_exception_free (&exception);
}
*ref = NULL;
return 0;
@@ -948,19 +933,14 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
/* Cache the location of MAP's hash table. */
void
-internal_function
_dl_setup_hash (struct link_map *map)
{
Elf_Symndx *hash;
- if (__glibc_likely (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
- + DT_THISPROCNUM + DT_VERSIONTAGNUM
- + DT_EXTRANUM + DT_VALNUM] != NULL))
+ if (__glibc_likely (map->l_info[ADDRIDX (DT_GNU_HASH)] != NULL))
{
Elf32_Word *hash32
- = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
- + DT_THISPROCNUM + DT_VERSIONTAGNUM
- + DT_EXTRANUM + DT_VALNUM]);
+ = (void *) D_PTR (map, l_info[ADDRIDX (DT_GNU_HASH)]);
map->l_nbuckets = *hash32++;
Elf32_Word symbias = *hash32++;
Elf32_Word bitmask_nwords = *hash32++;
@@ -992,7 +972,6 @@ _dl_setup_hash (struct link_map *map)
static void
-internal_function
_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
const ElfW(Sym) **ref, struct sym_val *value,
const struct r_found_version *version, int type_class,
diff --git a/elf/dl-machine-reject-phdr.h b/elf/dl-machine-reject-phdr.h
index bd36ee4e36..84d7f9d11b 100644
--- a/elf/dl-machine-reject-phdr.h
+++ b/elf/dl-machine-reject-phdr.h
@@ -1,5 +1,5 @@
/* Machine-dependent program header inspection for the ELF loader.
- Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Copyright (C) 2014-2018 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
diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h
index e583f64b3e..084076a283 100644
--- a/elf/dl-map-segments.h
+++ b/elf/dl-map-segments.h
@@ -1,5 +1,5 @@
/* Map in a shared object's segments. Generic version.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -64,14 +64,18 @@ _dl_map_segments (struct link_map *l, int fd,
l->l_addr = l->l_map_start - c->mapstart;
if (has_holes)
- /* Change protection on the excess portion to disallow all access;
- the portions we do not remap later will be inaccessible as if
- unallocated. Then jump into the normal segment-mapping loop to
- handle the portion of the segment past the end of the file
- mapping. */
- __mprotect ((caddr_t) (l->l_addr + c->mapend),
- loadcmds[nloadcmds - 1].mapstart - c->mapend,
- PROT_NONE);
+ {
+ /* Change protection on the excess portion to disallow all access;
+ the portions we do not remap later will be inaccessible as if
+ unallocated. Then jump into the normal segment-mapping loop to
+ handle the portion of the segment past the end of the file
+ mapping. */
+ if (__glibc_unlikely
+ (__mprotect ((caddr_t) (l->l_addr + c->mapend),
+ loadcmds[nloadcmds - 1].mapstart - c->mapend,
+ PROT_NONE) < 0))
+ return DL_MAP_SEGMENTS_ERROR_MPROTECT;
+ }
l->l_contiguous = 1;
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index 762e65b4d0..25ceded6fe 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -1,5 +1,5 @@
/* Minimal replacements for basic facilities used in the dynamic linker.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -27,28 +27,25 @@
#include <sys/types.h>
#include <ldsodefs.h>
#include <_itoa.h>
+#include <malloc/malloc-internal.h>
#include <assert.h>
-/* Minimal `malloc' allocator for use while loading shared libraries.
- No block is ever freed. */
+/* Minimal malloc allocator for used during initial link. After the
+ initial link, a full malloc implementation is interposed, either
+ the one in libc, or a different one supplied by the user through
+ interposition. */
static void *alloc_ptr, *alloc_end, *alloc_last_block;
/* Declarations of global functions. */
extern void weak_function free (void *ptr);
extern void * weak_function realloc (void *ptr, size_t n);
-extern unsigned long int weak_function __strtoul_internal (const char *nptr,
- char **endptr,
- int base,
- int group);
-extern unsigned long int weak_function strtoul (const char *nptr,
- char **endptr, int base);
/* Allocate an aligned memory block. */
void * weak_function
-__libc_memalign (size_t align, size_t n)
+malloc (size_t n)
{
if (alloc_end == 0)
{
@@ -61,20 +58,18 @@ __libc_memalign (size_t align, size_t n)
}
/* Make sure the allocation pointer is ideally aligned. */
- alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + align - 1)
- & ~(align - 1));
+ alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + MALLOC_ALIGNMENT - 1)
+ & ~(MALLOC_ALIGNMENT - 1));
if (alloc_ptr + n >= alloc_end || n >= -(uintptr_t) alloc_ptr)
{
- /* Insufficient space left; allocate another page. */
+ /* Insufficient space left; allocate another page plus one extra
+ page to reduce number of mmap calls. */
caddr_t page;
size_t nup = (n + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
- if (__glibc_unlikely (nup == 0))
- {
- if (n)
- return NULL;
- nup = GLRO(dl_pagesize);
- }
+ if (__glibc_unlikely (nup == 0 && n != 0))
+ return NULL;
+ nup += GLRO(dl_pagesize);
page = __mmap (0, nup, PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE, -1, 0);
if (page == MAP_FAILED)
@@ -89,12 +84,6 @@ __libc_memalign (size_t align, size_t n)
return alloc_last_block;
}
-void * weak_function
-malloc (size_t n)
-{
- return __libc_memalign (sizeof (double), n);
-}
-
/* We use this function occasionally since the real implementation may
be optimized when it can assume the memory it returns already is
set to NUL. */
@@ -241,84 +230,6 @@ Inconsistency detected by ld.so: %s: %u: %s%sUnexpected error: %s.\n",
rtld_hidden_weak (__assert_perror_fail)
#endif
-unsigned long int weak_function
-__strtoul_internal (const char *nptr, char **endptr, int base, int group)
-{
- unsigned long int result = 0;
- long int sign = 1;
- unsigned max_digit;
-
- while (*nptr == ' ' || *nptr == '\t')
- ++nptr;
-
- if (*nptr == '-')
- {
- sign = -1;
- ++nptr;
- }
- else if (*nptr == '+')
- ++nptr;
-
- if (*nptr < '0' || *nptr > '9')
- {
- if (endptr != NULL)
- *endptr = (char *) nptr;
- return 0UL;
- }
-
- assert (base == 0);
- base = 10;
- max_digit = 9;
- if (*nptr == '0')
- {
- if (nptr[1] == 'x' || nptr[1] == 'X')
- {
- base = 16;
- nptr += 2;
- }
- else
- {
- base = 8;
- max_digit = 7;
- }
- }
-
- while (1)
- {
- unsigned long int digval;
- if (*nptr >= '0' && *nptr <= '0' + max_digit)
- digval = *nptr - '0';
- else if (base == 16)
- {
- if (*nptr >= 'a' && *nptr <= 'f')
- digval = *nptr - 'a' + 10;
- else if (*nptr >= 'A' && *nptr <= 'F')
- digval = *nptr - 'A' + 10;
- else
- break;
- }
- else
- break;
-
- if (result > ULONG_MAX / base
- || (result == ULONG_MAX / base && digval > ULONG_MAX % base))
- {
- errno = ERANGE;
- if (endptr != NULL)
- *endptr = (char *) nptr;
- return ULONG_MAX;
- }
- result *= base;
- result += digval;
- ++nptr;
- }
-
- if (endptr != NULL)
- *endptr = (char *) nptr;
- return result * sign;
-}
-
-
#undef _itoa
/* We always use _itoa instead of _itoa_word in ld.so since the former
also has to be present and it is never about speed when these
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index c724e042a8..2eb81eeb02 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -1,5 +1,5 @@
/* Miscellaneous support functions for dynamic linker
- Copyright (C) 1997-2016 Free Software Foundation, Inc.
+ Copyright (C) 1997-2018 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
@@ -33,23 +33,18 @@
#include <sysdep.h>
#include <_itoa.h>
#include <dl-writev.h>
-
+#include <not-cancel.h>
/* Read the whole contents of FILE into new mmap'd space with given
protections. *SIZEP gets the size of the file. On error MAP_FAILED
is returned. */
void *
-internal_function
_dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
{
void *result = MAP_FAILED;
struct stat64 st;
- int flags = O_RDONLY;
-#ifdef O_CLOEXEC
- flags |= O_CLOEXEC;
-#endif
- int fd = __open (file, flags);
+ int fd = __open64_nocancel (file, O_RDONLY | O_CLOEXEC);
if (fd >= 0)
{
if (__fxstat64 (_STAT_VER, fd, &st) >= 0)
@@ -70,7 +65,7 @@ _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
#endif
, fd, 0);
}
- __close (fd);
+ __close_nocancel (fd);
}
return result;
}
@@ -283,7 +278,6 @@ _dl_dprintf (int fd, const char *fmt, ...)
/* Test whether given NAME matches any of the names of the given object. */
int
-internal_function
_dl_name_match_p (const char *name, const struct link_map *map)
{
if (strcmp (name, map->l_name) == 0)
@@ -302,7 +296,6 @@ _dl_name_match_p (const char *name, const struct link_map *map)
unsigned long int
-internal_function
_dl_higher_prime_number (unsigned long int n)
{
/* These are primes that are near, but slightly smaller than, a
@@ -364,3 +357,86 @@ _dl_higher_prime_number (unsigned long int n)
return *low;
}
+
+/* A stripped down strtoul-like implementation for very early use. It
+ does not set errno if the result is outside bounds because it may get
+ called before errno may have been set up. */
+
+uint64_t
+_dl_strtoul (const char *nptr, char **endptr)
+{
+ uint64_t result = 0;
+ bool positive = true;
+ unsigned max_digit;
+
+ while (*nptr == ' ' || *nptr == '\t')
+ ++nptr;
+
+ if (*nptr == '-')
+ {
+ positive = false;
+ ++nptr;
+ }
+ else if (*nptr == '+')
+ ++nptr;
+
+ if (*nptr < '0' || *nptr > '9')
+ {
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return 0UL;
+ }
+
+ int base = 10;
+ max_digit = 9;
+ if (*nptr == '0')
+ {
+ if (nptr[1] == 'x' || nptr[1] == 'X')
+ {
+ base = 16;
+ nptr += 2;
+ }
+ else
+ {
+ base = 8;
+ max_digit = 7;
+ }
+ }
+
+ while (1)
+ {
+ int digval;
+ if (*nptr >= '0' && *nptr <= '0' + max_digit)
+ digval = *nptr - '0';
+ else if (base == 16)
+ {
+ if (*nptr >= 'a' && *nptr <= 'f')
+ digval = *nptr - 'a' + 10;
+ else if (*nptr >= 'A' && *nptr <= 'F')
+ digval = *nptr - 'A' + 10;
+ else
+ break;
+ }
+ else
+ break;
+
+ if (result >= (UINT64_MAX - digval) / base)
+ {
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return UINT64_MAX;
+ }
+ result *= base;
+ result += digval;
+ ++nptr;
+ }
+
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+
+ /* Avoid 64-bit multiplication. */
+ if (!positive)
+ result = -result;
+
+ return result;
+}
diff --git a/elf/dl-object.c b/elf/dl-object.c
index 362992b261..b37bcc1295 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -1,5 +1,5 @@
/* Storage management for the chain of loaded shared objects.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -27,7 +27,6 @@
/* Add the new link_map NEW to the end of the namespace list. */
void
-internal_function
_dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
{
/* We modify the list of loaded objects. */
@@ -55,7 +54,6 @@ _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
/* Allocate a `struct link_map' for a new object being loaded,
and enter it into the _dl_loaded list. */
struct link_map *
-internal_function
_dl_new_object (char *realname, const char *libname, int type,
struct link_map *loader, int mode, Lmid_t nsid)
{
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 6f178b333d..f6c8ef1043 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -1,5 +1,5 @@
/* Load a shared object at runtime, relocate it, and run its initializer.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
@@ -28,17 +28,16 @@
#include <sys/param.h>
#include <libc-lock.h>
#include <ldsodefs.h>
-#include <caller.h>
#include <sysdep-cancel.h>
#include <tls.h>
#include <stap-probe.h>
#include <atomic.h>
+#include <libc-internal.h>
#include <dl-dst.h>
+#include <dl-prop.h>
-extern int __libc_multiple_libcs; /* Defined in init-first.c. */
-
/* We must be careful not to leave us in an inconsistent state. Thus we
catch any error and re-raise it after cleaning up. */
@@ -48,8 +47,6 @@ struct dl_open_args
int mode;
/* This is the caller of the dlopen() function. */
const void *caller_dlopen;
- /* This is the caller of _dl_open(). */
- const void *caller_dl_open;
struct link_map *map;
/* Namespace ID. */
Lmid_t nsid;
@@ -162,7 +159,6 @@ add_to_global (struct link_map *new)
address ADDR. Returns the pointer to the link map of the matching DSO, or
NULL if a match is not found. */
struct link_map *
-internal_function
_dl_find_dso_for_object (const ElfW(Addr) addr)
{
struct link_map *l;
@@ -189,11 +185,6 @@ dl_open_worker (void *a)
int mode = args->mode;
struct link_map *call_map = NULL;
- /* Check whether _dl_open() has been called from a valid DSO. */
- if (__check_caller (args->caller_dl_open,
- allow_libc|allow_libdl|allow_ldso) != 0)
- _dl_signal_error (0, "dlopen", NULL, N_("invalid caller"));
-
/* Determine the caller's map if necessary. This is needed in case
we have a DST, when we don't know the namespace ID we have to put
the new object in, or when the file name has no path in which
@@ -226,12 +217,6 @@ dl_open_worker (void *a)
args->map = new = _dl_map_object (call_map, file, lt_loaded, 0,
mode | __RTLD_CALLMAP, args->nsid);
- /* Mark the object as not deletable if the RTLD_NODELETE flags was passed.
- Do this early so that we don't skip marking the object if it was
- already loaded. */
- if (__glibc_unlikely (mode & RTLD_NODELETE))
- new->l_flags_1 |= DF_1_NODELETE;
-
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
set and the object is not already loaded. */
if (new == NULL)
@@ -240,6 +225,12 @@ dl_open_worker (void *a)
return;
}
+ /* Mark the object as not deletable if the RTLD_NODELETE flags was passed.
+ Do this early so that we don't skip marking the object if it was
+ already loaded. */
+ if (__glibc_unlikely (mode & RTLD_NODELETE))
+ new->l_flags_1 |= DF_1_NODELETE;
+
if (__glibc_unlikely (mode & __RTLD_SPROF))
/* This happens only if we load a DSO for 'sprof'. */
return;
@@ -301,6 +292,8 @@ dl_open_worker (void *a)
_dl_debug_state ();
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
+ _dl_open_check (new);
+
/* Print scope information. */
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
_dl_show_scope (new, 0);
@@ -313,7 +306,7 @@ dl_open_worker (void *a)
/* Sort the objects by dependency for the relocation process. This
allows IFUNC relocations to work and it also means copy
relocation of dependencies are if necessary overwritten. */
- size_t nmaps = 0;
+ unsigned int nmaps = 0;
struct link_map *l = new;
do
{
@@ -332,62 +325,11 @@ dl_open_worker (void *a)
l = l->l_next;
}
while (l != NULL);
- if (nmaps > 1)
- {
- uint16_t seen[nmaps];
- memset (seen, '\0', sizeof (seen));
- size_t i = 0;
- while (1)
- {
- ++seen[i];
- struct link_map *thisp = maps[i];
-
- /* Find the last object in the list for which the current one is
- a dependency and move the current object behind the object
- with the dependency. */
- size_t k = nmaps - 1;
- while (k > i)
- {
- struct link_map **runp = maps[k]->l_initfini;
- if (runp != NULL)
- /* Look through the dependencies of the object. */
- while (*runp != NULL)
- if (__glibc_unlikely (*runp++ == thisp))
- {
- /* Move the current object to the back past the last
- object with it as the dependency. */
- memmove (&maps[i], &maps[i + 1],
- (k - i) * sizeof (maps[0]));
- maps[k] = thisp;
-
- if (seen[i + 1] > nmaps - i)
- {
- ++i;
- goto next_clear;
- }
-
- uint16_t this_seen = seen[i];
- memmove (&seen[i], &seen[i + 1],
- (k - i) * sizeof (seen[0]));
- seen[k] = this_seen;
-
- goto next;
- }
-
- --k;
- }
-
- if (++i == nmaps)
- break;
- next_clear:
- memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0]));
- next:;
- }
- }
+ _dl_sort_maps (maps, nmaps, NULL, false);
int relocation_in_progress = 0;
- for (size_t i = nmaps; i-- > 0; )
+ for (unsigned int i = nmaps; i-- > 0; )
{
l = maps[i];
@@ -636,18 +578,14 @@ no more namespaces available for dlmopen()"));
args.file = file;
args.mode = mode;
args.caller_dlopen = caller_dlopen;
- args.caller_dl_open = RETURN_ADDRESS (0);
args.map = NULL;
args.nsid = nsid;
args.argc = argc;
args.argv = argv;
args.env = env;
- const char *objname;
- const char *errstring;
- bool malloced;
- int errcode = _dl_catch_error (&objname, &errstring, &malloced,
- dl_open_worker, &args);
+ 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. */
@@ -655,7 +593,7 @@ no more namespaces available for dlmopen()"));
#endif
/* See if an error occurred during loading. */
- if (__glibc_unlikely (errstring != NULL))
+ if (__glibc_unlikely (exception.errstring != NULL))
{
/* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */
@@ -679,28 +617,8 @@ no more namespaces available for dlmopen()"));
/* Release the lock. */
__rtld_lock_unlock_recursive (GL(dl_load_lock));
- /* Make a local copy of the error string so that we can release the
- memory allocated for it. */
- size_t len_errstring = strlen (errstring) + 1;
- char *local_errstring;
- if (objname == errstring + len_errstring)
- {
- size_t total_len = len_errstring + strlen (objname) + 1;
- local_errstring = alloca (total_len);
- memcpy (local_errstring, errstring, total_len);
- objname = local_errstring + len_errstring;
- }
- else
- {
- local_errstring = alloca (len_errstring);
- memcpy (local_errstring, errstring, len_errstring);
- }
-
- if (malloced)
- free ((char *) errstring);
-
/* Reraise the error. */
- _dl_signal_error (errcode, objname, NULL, local_errstring);
+ _dl_signal_exception (errcode, &exception, NULL);
}
assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
@@ -735,21 +653,3 @@ _dl_show_scope (struct link_map *l, int from)
_dl_debug_printf (" no scope\n");
_dl_debug_printf ("\n");
}
-
-#if IS_IN (rtld)
-/* Return non-zero if ADDR lies within one of L's segments. */
-int
-internal_function
-_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
-{
- int n = l->l_phnum;
- const ElfW(Addr) reladdr = addr - l->l_addr;
-
- while (--n >= 0)
- if (l->l_phdr[n].p_type == PT_LOAD
- && reladdr - l->l_phdr[n].p_vaddr >= 0
- && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
- return 1;
- return 0;
-}
-#endif
diff --git a/elf/dl-origin.c b/elf/dl-origin.c
index 0204d268d9..02026969b0 100644
--- a/elf/dl-origin.c
+++ b/elf/dl-origin.c
@@ -1,5 +1,5 @@
/* Find path of executable.
- Copyright (C) 1998-2016 Free Software Foundation, Inc.
+ Copyright (C) 1998-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
diff --git a/elf/dl-profile.c b/elf/dl-profile.c
index dd7d57079d..bac3718c11 100644
--- a/elf/dl-profile.c
+++ b/elf/dl-profile.c
@@ -1,5 +1,5 @@
/* Profiling of shared libraries.
- Copyright (C) 1997-2016 Free Software Foundation, Inc.
+ Copyright (C) 1997-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
Based on the BSD mcount implementation.
@@ -35,6 +35,7 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <atomic.h>
+#include <not-cancel.h>
/* The LD_PROFILE feature has to be implemented different to the
normal profiling using the gmon/ functions. The problem is that an
@@ -180,7 +181,6 @@ static unsigned int log_hashfraction;
/* Set up profiling data to profile object desribed by MAP. The output
file is found (or created) in OUTPUT_DIR. */
void
-internal_function
_dl_start_profile (void)
{
char *filename;
@@ -325,12 +325,7 @@ _dl_start_profile (void)
*cp++ = '/';
__stpcpy (__stpcpy (cp, GLRO(dl_profile)), ".profile");
-#ifdef O_NOFOLLOW
-# define EXTRA_FLAGS | O_NOFOLLOW
-#else
-# define EXTRA_FLAGS
-#endif
- fd = __open (filename, O_RDWR | O_CREAT EXTRA_FLAGS, DEFFILEMODE);
+ fd = __open64_nocancel (filename, O_RDWR|O_CREAT|O_NOFOLLOW, DEFFILEMODE);
if (fd == -1)
{
char buf[400];
@@ -341,7 +336,7 @@ _dl_start_profile (void)
print_error:
errnum = errno;
if (fd != -1)
- __close (fd);
+ __close_nocancel (fd);
_dl_error_printf (errstr, filename,
__strerror_r (errnum, buf, sizeof buf));
return;
@@ -370,15 +365,14 @@ _dl_start_profile (void)
goto print_error;
}
- if (TEMP_FAILURE_RETRY (__libc_write (fd, buf, (expected_size
- & (GLRO(dl_pagesize)
- - 1))))
+ if (TEMP_FAILURE_RETRY
+ (__write_nocancel (fd, buf, (expected_size & (GLRO(dl_pagesize) - 1))))
< 0)
goto cannot_create;
}
else if (st.st_size != expected_size)
{
- __close (fd);
+ __close_nocancel (fd);
wrong_format:
if (addr != NULL)
@@ -398,7 +392,7 @@ _dl_start_profile (void)
}
/* We don't need the file descriptor anymore. */
- __close (fd);
+ __close_nocancel (fd);
/* Pointer to data after the header. */
hist = (char *) (addr + 1);
diff --git a/elf/dl-profstub.c b/elf/dl-profstub.c
index 8b0c89837d..98ba07ef02 100644
--- a/elf/dl-profstub.c
+++ b/elf/dl-profstub.c
@@ -1,5 +1,5 @@
/* Helper definitions for profiling of shared libraries.
- Copyright (C) 1998-2016 Free Software Foundation, Inc.
+ Copyright (C) 1998-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
new file mode 100644
index 0000000000..ab1ce0eacc
--- /dev/null
+++ b/elf/dl-reloc-static-pie.c
@@ -0,0 +1,68 @@
+/* Support for relocating static PIE.
+ Copyright (C) 2017-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#if ENABLE_STATIC_PIE
+#include <unistd.h>
+#include <ldsodefs.h>
+#include "dynamic-link.h"
+
+/* Relocate static executable with PIE. */
+
+void
+_dl_relocate_static_pie (void)
+{
+ struct link_map *main_map = _dl_get_dl_main_map ();
+
+# define STATIC_PIE_BOOTSTRAP
+# define BOOTSTRAP_MAP (main_map)
+# define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
+# include "dynamic-link.h"
+
+ /* Figure out the run-time load address of static PIE. */
+ main_map->l_addr = elf_machine_load_address ();
+
+ /* Read our own dynamic section and fill in the info array. */
+ main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
+ elf_get_dynamic_info (main_map, NULL);
+
+# ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
+ ELF_MACHINE_BEFORE_RTLD_RELOC (main_map->l_info);
+# endif
+
+ /* Relocate ourselves so we can do normal function calls and
+ data access using the global offset table. */
+ ELF_DYNAMIC_RELOCATE (main_map, 0, 0, 0);
+ main_map->l_relocated = 1;
+
+ /* Initialize _r_debug. */
+ struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
+ r->r_state = RT_CONSISTENT;
+
+ /* Set up debugging before the debugger is notified for the first
+ time. */
+# ifdef ELF_MACHINE_DEBUG_SETUP
+ /* Some machines (e.g. MIPS) don't use DT_DEBUG in this way. */
+ ELF_MACHINE_DEBUG_SETUP (main_map, r);
+# else
+ if (main_map->l_info[DT_DEBUG] != NULL)
+ /* There is a DT_DEBUG entry in the dynamic section. Fill it in
+ with the run-time address of the r_debug structure */
+ main_map->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r;
+# endif
+}
+#endif
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 14709f960d..053916eeae 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -1,5 +1,5 @@
/* Relocate a shared object and resolve its references to other loaded objects.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -25,8 +25,8 @@
#include <sys/param.h>
#include <sys/types.h>
#include <_itoa.h>
+#include <libc-pointer-arith.h>
#include "dynamic-link.h"
-#include <libc-internal.h>
/* Statistics function. */
#ifdef SHARED
@@ -45,7 +45,6 @@
directly, as static TLS should be rare and code handling it should
not be inlined as much as possible. */
int
-internal_function
_dl_try_allocate_static_tls (struct link_map *map)
{
/* If we've already used the variable with dynamic access, or if the
@@ -112,7 +111,7 @@ _dl_try_allocate_static_tls (struct link_map *map)
}
void
-internal_function __attribute_noinline__
+__attribute_noinline__
_dl_allocate_static_tls (struct link_map *map)
{
if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
@@ -233,7 +232,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
/* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */
#define RESOLVE_MAP(ref, version, r_type) \
- (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \
+ ((ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \
+ && __glibc_likely (!dl_symbol_visibility_binds_local_p (*ref))) \
? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \
&& elf_machine_type_class (r_type) == l->l_lookup_cache.type_class) \
? (bump_num_cache_relocations (), \
@@ -307,7 +307,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
}
-void internal_function
+void
_dl_protect_relro (struct link_map *l)
{
ElfW(Addr) start = ALIGN_DOWN((l->l_addr
@@ -327,7 +327,7 @@ cannot apply additional memory protection after relocation");
}
void
-internal_function __attribute_noinline__
+__attribute_noinline__
_dl_reloc_bad_type (struct link_map *map, unsigned int type, int plt)
{
#define DIGIT(b) _itoa_lower_digits[(b) & 0xf];
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 92596acf99..63bbc89776 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -1,5 +1,5 @@
/* On-demand PLT fixup for shared objects.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -71,6 +71,7 @@ _dl_fixup (
const PLTREL *const reloc
= (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+ const ElfW(Sym) *refsym = sym;
void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
lookup_t result;
DL_FIXUP_VALUE_TYPE value;
@@ -123,14 +124,13 @@ _dl_fixup (
of the object that defines sym. Now add in the symbol
offset. */
value = DL_FIXUP_MAKE_VALUE (result,
- sym ? (LOOKUP_VALUE_ADDRESS (result)
- + sym->st_value) : 0);
+ SYMBOL_ADDRESS (result, sym, false));
}
else
{
/* We already found the symbol. The module (and therefore its load
address) is also known. */
- value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value);
+ value = DL_FIXUP_MAKE_VALUE (l, SYMBOL_ADDRESS (l, sym, true));
result = l;
}
@@ -145,7 +145,7 @@ _dl_fixup (
if (__glibc_unlikely (GLRO(dl_bind_not)))
return value;
- return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
+ return elf_machine_fixup_plt (l, result, refsym, sym, reloc, rel_addr, value);
}
#ifndef PROF
@@ -240,9 +240,7 @@ _dl_profile_fixup (
of the object that defines sym. Now add in the symbol
offset. */
value = DL_FIXUP_MAKE_VALUE (result,
- defsym != NULL
- ? LOOKUP_VALUE_ADDRESS (result)
- + defsym->st_value : 0);
+ SYMBOL_ADDRESS (result, defsym, false));
if (defsym != NULL
&& __builtin_expect (ELFW(ST_TYPE) (defsym->st_info)
@@ -253,7 +251,7 @@ _dl_profile_fixup (
{
/* We already found the symbol. The module (and therefore its load
address) is also known. */
- value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + refsym->st_value);
+ value = DL_FIXUP_MAKE_VALUE (l, SYMBOL_ADDRESS (l, refsym, true));
if (__builtin_expect (ELFW(ST_TYPE) (refsym->st_info)
== STT_GNU_IFUNC, 0))
diff --git a/elf/dl-scope.c b/elf/dl-scope.c
index 32b276751a..2775412f31 100644
--- a/elf/dl-scope.c
+++ b/elf/dl-scope.c
@@ -1,5 +1,5 @@
/* Memory handling for the scope data structures.
- Copyright (C) 2009-2016 Free Software Foundation, Inc.
+ Copyright (C) 2009-2018 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
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
new file mode 100644
index 0000000000..b2a01ede62
--- /dev/null
+++ b/elf/dl-sort-maps.c
@@ -0,0 +1,122 @@
+/* Sort array of link maps according to dependencies.
+ Copyright (C) 2017-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+
+
+/* Sort array MAPS according to dependencies of the contained objects.
+ Array USED, if non-NULL, is permutated along MAPS. If FOR_FINI this is
+ called for finishing an object. */
+void
+_dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
+ bool for_fini)
+{
+ /* A list of one element need not be sorted. */
+ if (nmaps <= 1)
+ return;
+
+ unsigned int i = 0;
+ uint16_t seen[nmaps];
+ memset (seen, 0, nmaps * sizeof (seen[0]));
+ while (1)
+ {
+ /* Keep track of which object we looked at this round. */
+ ++seen[i];
+ struct link_map *thisp = maps[i];
+
+ if (__glibc_unlikely (for_fini))
+ {
+ /* Do not handle ld.so in secondary namespaces and objects which
+ are not removed. */
+ if (thisp != thisp->l_real || thisp->l_idx == -1)
+ goto skip;
+ }
+
+ /* Find the last object in the list for which the current one is
+ a dependency and move the current object behind the object
+ with the dependency. */
+ unsigned int k = nmaps - 1;
+ while (k > i)
+ {
+ struct link_map **runp = maps[k]->l_initfini;
+ if (runp != NULL)
+ /* Look through the dependencies of the object. */
+ while (*runp != NULL)
+ if (__glibc_unlikely (*runp++ == thisp))
+ {
+ move:
+ /* Move the current object to the back past the last
+ object with it as the dependency. */
+ memmove (&maps[i], &maps[i + 1],
+ (k - i) * sizeof (maps[0]));
+ maps[k] = thisp;
+
+ if (used != NULL)
+ {
+ char here_used = used[i];
+ memmove (&used[i], &used[i + 1],
+ (k - i) * sizeof (used[0]));
+ used[k] = here_used;
+ }
+
+ if (seen[i + 1] > nmaps - i)
+ {
+ ++i;
+ goto next_clear;
+ }
+
+ uint16_t this_seen = seen[i];
+ memmove (&seen[i], &seen[i + 1], (k - i) * sizeof (seen[0]));
+ seen[k] = this_seen;
+
+ goto next;
+ }
+
+ if (__glibc_unlikely (for_fini && maps[k]->l_reldeps != NULL))
+ {
+ unsigned int m = maps[k]->l_reldeps->act;
+ struct link_map **relmaps = &maps[k]->l_reldeps->list[0];
+
+ /* Look through the relocation dependencies of the object. */
+ while (m-- > 0)
+ if (__glibc_unlikely (relmaps[m] == thisp))
+ {
+ /* If a cycle exists with a link time dependency,
+ preserve the latter. */
+ struct link_map **runp = thisp->l_initfini;
+ if (runp != NULL)
+ while (*runp != NULL)
+ if (__glibc_unlikely (*runp++ == maps[k]))
+ goto ignore;
+ goto move;
+ }
+ ignore:;
+ }
+
+ --k;
+ }
+
+ skip:
+ if (++i == nmaps)
+ break;
+ next_clear:
+ memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0]));
+
+ next:;
+ }
+}
diff --git a/elf/dl-support.c b/elf/dl-support.c
index c30194c7b7..b5f10d5aa5 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -1,5 +1,5 @@
/* Support for dynamic linking code in static libc.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
@@ -126,6 +126,7 @@ int _dl_starting_up = 1;
void *_dl_random;
/* Get architecture specific initializer. */
+#include <dl-procruntime.c>
#include <dl-procinfo.c>
/* Initial value of the CPU clock. */
@@ -164,6 +165,7 @@ uint64_t _dl_hwcap2 __attribute__ ((nocommon));
/* The value of the FPU control word the kernel will preset in hardware. */
fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
+#if !HAVE_TUNABLES
/* This is not initialized to HWCAP_IMPORTANT, matching the definition
of _dl_important_hwcaps, below, where no hwcap strings are ever
used. This mask is still used to mediate the lookups in the cache
@@ -171,6 +173,7 @@ fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
LD_HWCAP_MASK environment variable here), there is no real point in
setting _dl_hwcap nonzero below, but we do anyway. */
uint64_t _dl_hwcap_mask __attribute__ ((nocommon));
+#endif
/* Prevailing state of the stack. Generally this includes PF_X, indicating it's
* executable but this isn't true for all platforms. */
@@ -179,13 +182,15 @@ ElfW(Word) _dl_stack_flags = DEFAULT_STACK_PERMS;
/* If loading a shared object requires that we make the stack executable
when it was not, we do it by calling this function.
It returns an errno code or zero on success. */
-int (*_dl_make_stack_executable_hook) (void **) internal_function
- = _dl_make_stack_executable;
+int (*_dl_make_stack_executable_hook) (void **) = _dl_make_stack_executable;
/* Function in libpthread to wait for termination of lookups. */
void (*_dl_wait_lookup_done) (void);
+#if !THREAD_GSCOPE_IN_TCB
+int _dl_thread_gscope_count;
+#endif
struct dl_scope_free_list *_dl_scope_free_list;
#ifdef NEED_DL_SYSINFO
@@ -220,7 +225,6 @@ __rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
int _dl_clktck;
void
-internal_function
_dl_aux_init (ElfW(auxv_t) *av)
{
int seen = 0;
@@ -304,7 +308,6 @@ _dl_aux_init (ElfW(auxv_t) *av)
void
-internal_function
_dl_non_dynamic_init (void)
{
_dl_main_map.l_origin = _dl_get_origin ();
@@ -354,8 +357,10 @@ _dl_non_dynamic_init (void)
cp = (const char *) __rawmemchr (cp, '\0') + 1;
}
+#if !HAVE_TUNABLES
if (__access ("/etc/suid-debug", F_OK) != 0)
__unsetenv ("MALLOC_CHECK_");
+#endif
}
#ifdef DL_PLATFORM_INIT
@@ -383,3 +388,14 @@ _dl_non_dynamic_init (void)
#ifdef DL_SYSINFO_IMPLEMENTATION
DL_SYSINFO_IMPLEMENTATION
#endif
+
+#if ENABLE_STATIC_PIE
+/* Since relocation to hidden _dl_main_map causes relocation overflow on
+ aarch64, a function is used to get the address of _dl_main_map. */
+
+struct link_map *
+_dl_get_dl_main_map (void)
+{
+ return &_dl_main_map;
+}
+#endif
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 6431c22614..189628adc0 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -1,5 +1,5 @@
/* Look up a symbol in a shared object loaded by `dlopen'.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2018 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
@@ -41,7 +41,6 @@
/* Return the symbol address given the map of the module it is in and
the symbol record. This is used in dl-sym.c. */
static void *
-internal_function
_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
{
# ifndef DONT_USE_TLS_INDEX
@@ -83,7 +82,6 @@ call_dl_lookup (void *ptr)
static void *
-internal_function
do_sym (void *handle, const char *name, void *who,
struct r_found_version *vers, int flags)
{
@@ -119,26 +117,11 @@ do_sym (void *handle, const char *name, void *who,
args.refp = &ref;
THREAD_GSCOPE_SET_FLAG ();
-
- const char *objname;
- const char *errstring = NULL;
- bool malloced;
- int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced,
- call_dl_lookup, &args);
-
+ struct dl_exception exception;
+ int err = _dl_catch_exception (&exception, call_dl_lookup, &args);
THREAD_GSCOPE_RESET_FLAG ();
-
- if (__glibc_unlikely (errstring != NULL))
- {
- /* The lookup was unsuccessful. Rethrow the error. */
- char *errstring_dup = strdupa (errstring);
- char *objname_dup = strdupa (objname);
- if (malloced)
- free ((char *) errstring);
-
- GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
- /* NOTREACHED */
- }
+ if (__glibc_unlikely (exception.errstring != NULL))
+ _dl_signal_exception (err, &exception, NULL);
result = args.map;
}
@@ -150,7 +133,7 @@ do_sym (void *handle, const char *name, void *who,
if (match == NULL
|| caller < match->l_map_start
|| caller >= match->l_map_end)
- GLRO(dl_signal_error) (0, NULL, NULL, N_("\
+ _dl_signal_error (0, NULL, NULL, N_("\
RTLD_NEXT used in code not dynamically loaded"));
}
@@ -250,7 +233,6 @@ RTLD_NEXT used in code not dynamically loaded"));
void *
-internal_function
_dl_vsym (void *handle, const char *name, const char *version, void *who)
{
struct r_found_version vers;
@@ -267,7 +249,6 @@ _dl_vsym (void *handle, const char *name, const char *version, void *who)
void *
-internal_function
_dl_sym (void *handle, const char *name, void *who)
{
return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
diff --git a/elf/dl-symaddr.c b/elf/dl-symaddr.c
index b3b97418c5..7f1ccc2516 100644
--- a/elf/dl-symaddr.c
+++ b/elf/dl-symaddr.c
@@ -1,5 +1,5 @@
/* Get the symbol address. Generic version.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2018 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
@@ -22,7 +22,7 @@
void *
_dl_symbol_address (struct link_map *map, const ElfW(Sym) *ref)
{
- ElfW(Addr) value = (map ? map->l_addr : 0) + ref->st_value;
+ ElfW(Addr) value = SYMBOL_ADDRESS (map, ref, false);
/* Return the pointer to function descriptor. */
if (ELFW(ST_TYPE) (ref->st_info) == STT_FUNC)
diff --git a/elf/dl-sysdep-open.h b/elf/dl-sysdep-open.h
index 471315270d..dbe9299b95 100644
--- a/elf/dl-sysdep-open.h
+++ b/elf/dl-sysdep-open.h
@@ -1,5 +1,5 @@
/* System-specific call to open a shared object by name. Stub version.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index eaa71556d2..998c5d52bc 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -1,5 +1,5 @@
/* Operating system support for run-time dynamic linker. Generic Unix version.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -41,9 +41,11 @@
#include <dl-machine.h>
#include <dl-procinfo.h>
#include <dl-osinfo.h>
-#include <hp-timing.h>
+#include <libc-internal.h>
#include <tls.h>
+#include <dl-tunables.h>
+
extern char **_environ attribute_hidden;
extern char _end[] attribute_hidden;
@@ -219,6 +221,8 @@ _dl_sysdep_start (void **start_argptr,
}
#endif
+ __tunables_init (_environ);
+
#ifdef DL_SYSDEP_INIT
DL_SYSDEP_INIT;
#endif
@@ -251,13 +255,11 @@ _dl_sysdep_start (void **start_argptr,
}
void
-internal_function
_dl_sysdep_start_cleanup (void)
{
}
void
-internal_function
_dl_show_auxv (void)
{
char buf[64];
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index ed13fd950b..c87caf13d6 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -1,5 +1,5 @@
/* Thread-local storage handling in the ELF dynamic linker. Generic version.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2018 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
@@ -44,7 +44,6 @@ oom (void)
size_t
-internal_function
_dl_next_tls_modid (void)
{
size_t result;
@@ -105,7 +104,6 @@ _dl_next_tls_modid (void)
size_t
-internal_function
_dl_count_modids (void)
{
/* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where
@@ -133,7 +131,6 @@ _dl_count_modids (void)
#ifdef SHARED
void
-internal_function
_dl_determine_tlsoffset (void)
{
size_t max_align = TLS_TCB_ALIGN;
@@ -274,42 +271,9 @@ _dl_determine_tlsoffset (void)
/* The alignment requirement for the static TLS block. */
GL(dl_tls_static_align) = max_align;
}
-
-
-/* This is called only when the data structure setup was skipped at startup,
- when there was no need for it then. Now we have dynamically loaded
- something needing TLS, or libpthread needs it. */
-int
-internal_function
-_dl_tls_setup (void)
-{
- assert (GL(dl_tls_dtv_slotinfo_list) == NULL);
- assert (GL(dl_tls_max_dtv_idx) == 0);
-
- const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS;
-
- GL(dl_tls_dtv_slotinfo_list)
- = calloc (1, (sizeof (struct dtv_slotinfo_list)
- + nelem * sizeof (struct dtv_slotinfo)));
- if (GL(dl_tls_dtv_slotinfo_list) == NULL)
- return -1;
-
- GL(dl_tls_dtv_slotinfo_list)->len = nelem;
-
- /* Number of elements in the static TLS block. It can't be zero
- because of various assumptions. The one element is null. */
- GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx) = 1;
-
- /* This initializes more variables for us. */
- _dl_determine_tlsoffset ();
-
- return 0;
-}
-rtld_hidden_def (_dl_tls_setup)
-#endif
+#endif /* SHARED */
static void *
-internal_function
allocate_dtv (void *result)
{
dtv_t *dtv;
@@ -340,16 +304,30 @@ allocate_dtv (void *result)
/* Get size and alignment requirements of the static TLS block. */
void
-internal_function
_dl_get_tls_static_info (size_t *sizep, size_t *alignp)
{
*sizep = GL(dl_tls_static_size);
*alignp = GL(dl_tls_static_align);
}
+/* Derive the location of the pointer to the start of the original
+ allocation (before alignment) from the pointer to the TCB. */
+static inline void **
+tcb_to_pointer_to_free_location (void *tcb)
+{
+#if TLS_TCB_AT_TP
+ /* The TCB follows the TLS blocks, and the pointer to the front
+ follows the TCB. */
+ void **original_pointer_location = tcb + TLS_TCB_SIZE;
+#elif TLS_DTV_AT_TP
+ /* The TCB comes first, preceded by the pre-TCB, and the pointer is
+ before that. */
+ void **original_pointer_location = tcb - TLS_PRE_TCB_SIZE - sizeof (void *);
+#endif
+ return original_pointer_location;
+}
void *
-internal_function
_dl_allocate_tls_storage (void)
{
void *result;
@@ -359,39 +337,50 @@ _dl_allocate_tls_storage (void)
/* Memory layout is:
[ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ]
^ This should be returned. */
- size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
- & ~(GL(dl_tls_static_align) - 1);
+ size += TLS_PRE_TCB_SIZE;
#endif
- /* Allocate a correctly aligned chunk of memory. */
- result = __libc_memalign (GL(dl_tls_static_align), size);
- if (__builtin_expect (result != NULL, 1))
- {
- /* Allocate the DTV. */
- void *allocated = result;
+ /* Perform the allocation. Reserve space for the required alignment
+ and the pointer to the original allocation. */
+ size_t alignment = GL(dl_tls_static_align);
+ void *allocated = malloc (size + alignment + sizeof (void *));
+ if (__glibc_unlikely (allocated == NULL))
+ return NULL;
+ /* Perform alignment and allocate the DTV. */
#if TLS_TCB_AT_TP
- /* The TCB follows the TLS blocks. */
- result = (char *) result + size - TLS_TCB_SIZE;
-
- /* Clear the TCB data structure. We can't ask the caller (i.e.
- libpthread) to do it, because we will initialize the DTV et al. */
- memset (result, '\0', TLS_TCB_SIZE);
+ /* The TCB follows the TLS blocks, which determine the alignment.
+ (TCB alignment requirements have been taken into account when
+ calculating GL(dl_tls_static_align).) */
+ void *aligned = (void *) roundup ((uintptr_t) allocated, alignment);
+ result = aligned + size - TLS_TCB_SIZE;
+
+ /* Clear the TCB data structure. We can't ask the caller (i.e.
+ libpthread) to do it, because we will initialize the DTV et al. */
+ memset (result, '\0', TLS_TCB_SIZE);
#elif TLS_DTV_AT_TP
- result = (char *) result + size - GL(dl_tls_static_size);
-
- /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
- We can't ask the caller (i.e. libpthread) to do it, because we will
- initialize the DTV et al. */
- memset ((char *) result - TLS_PRE_TCB_SIZE, '\0',
- TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
+ /* Pre-TCB and TCB come before the TLS blocks. The layout computed
+ in _dl_determine_tlsoffset assumes that the TCB is aligned to the
+ TLS block alignment, and not just the TLS blocks after it. This
+ can leave an unused alignment gap between the TCB and the TLS
+ blocks. */
+ result = (void *) roundup
+ (sizeof (void *) + TLS_PRE_TCB_SIZE + (uintptr_t) allocated,
+ alignment);
+
+ /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before
+ it. We can't ask the caller (i.e. libpthread) to do it, because
+ we will initialize the DTV et al. */
+ memset (result - TLS_PRE_TCB_SIZE, '\0', TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
#endif
- result = allocate_dtv (result);
- if (result == NULL)
- free (allocated);
- }
+ /* Record the value of the original pointer for later
+ deallocation. */
+ *tcb_to_pointer_to_free_location (result) = allocated;
+ result = allocate_dtv (result);
+ if (result == NULL)
+ free (allocated);
return result;
}
@@ -444,7 +433,6 @@ _dl_resize_dtv (dtv_t *dtv)
void *
-internal_function
_dl_allocate_tls_init (void *result)
{
if (result == NULL)
@@ -494,7 +482,7 @@ _dl_allocate_tls_init (void *result)
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
- dtv[map->l_tls_modid].pointer.is_static = false;
+ dtv[map->l_tls_modid].pointer.to_free = NULL;
if (map->l_tls_offset == NO_TLS_OFFSET
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
@@ -511,6 +499,10 @@ _dl_allocate_tls_init (void *result)
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
+ /* Set up the DTV entry. The simplified __tls_get_addr that
+ some platforms use in static programs requires it. */
+ dtv[map->l_tls_modid].pointer.val = dest;
+
/* Copy the initialization image and clear the BSS part. */
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',
@@ -533,7 +525,6 @@ _dl_allocate_tls_init (void *result)
rtld_hidden_def (_dl_allocate_tls_init)
void *
-internal_function
_dl_allocate_tls (void *mem)
{
return _dl_allocate_tls_init (mem == NULL
@@ -544,33 +535,20 @@ rtld_hidden_def (_dl_allocate_tls)
void
-internal_function
_dl_deallocate_tls (void *tcb, bool dealloc_tcb)
{
dtv_t *dtv = GET_DTV (tcb);
/* We need to free the memory allocated for non-static TLS. */
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
- if (! dtv[1 + cnt].pointer.is_static
- && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
- free (dtv[1 + cnt].pointer.val);
+ free (dtv[1 + cnt].pointer.to_free);
/* The array starts with dtv[-1]. */
if (dtv != GL(dl_initial_dtv))
free (dtv - 1);
if (dealloc_tcb)
- {
-#if TLS_TCB_AT_TP
- /* The TCB follows the TLS blocks. Back up to free the whole block. */
- tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE;
-#elif TLS_DTV_AT_TP
- /* Back up the TLS_PRE_TCB_SIZE bytes. */
- tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
- & ~(GL(dl_tls_static_align) - 1);
-#endif
- free (tcb);
- }
+ free (*tcb_to_pointer_to_free_location (tcb));
}
rtld_hidden_def (_dl_deallocate_tls)
@@ -594,21 +572,49 @@ rtld_hidden_def (_dl_deallocate_tls)
# define GET_ADDR_OFFSET ti->ti_offset
# endif
+/* Allocate one DTV entry. */
+static struct dtv_pointer
+allocate_dtv_entry (size_t alignment, size_t size)
+{
+ if (powerof2 (alignment) && alignment <= _Alignof (max_align_t))
+ {
+ /* The alignment is supported by malloc. */
+ void *ptr = malloc (size);
+ return (struct dtv_pointer) { ptr, ptr };
+ }
+
+ /* Emulate memalign to by manually aligning a pointer returned by
+ malloc. First compute the size with an overflow check. */
+ size_t alloc_size = size + alignment;
+ if (alloc_size < size)
+ return (struct dtv_pointer) {};
-static void *
+ /* Perform the allocation. This is the pointer we need to free
+ later. */
+ void *start = malloc (alloc_size);
+ if (start == NULL)
+ return (struct dtv_pointer) {};
+
+ /* Find the aligned position within the larger allocation. */
+ void *aligned = (void *) roundup ((uintptr_t) start, alignment);
+
+ return (struct dtv_pointer) { .val = aligned, .to_free = start };
+}
+
+static struct dtv_pointer
allocate_and_init (struct link_map *map)
{
- void *newp;
-
- newp = __libc_memalign (map->l_tls_align, map->l_tls_blocksize);
- if (newp == NULL)
+ struct dtv_pointer result = allocate_dtv_entry
+ (map->l_tls_align, map->l_tls_blocksize);
+ if (result.val == NULL)
oom ();
/* Initialize the memory. */
- memset (__mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size),
+ memset (__mempcpy (result.val, map->l_tls_initimage,
+ map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
- return newp;
+ return result;
}
@@ -678,12 +684,9 @@ _dl_update_slotinfo (unsigned long int req_modid)
{
/* If this modid was used at some point the memory
might still be allocated. */
- if (! dtv[total + cnt].pointer.is_static
- && (dtv[total + cnt].pointer.val
- != TLS_DTV_UNALLOCATED))
- free (dtv[total + cnt].pointer.val);
+ free (dtv[total + cnt].pointer.to_free);
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
- dtv[total + cnt].pointer.is_static = false;
+ dtv[total + cnt].pointer.to_free = NULL;
}
continue;
@@ -708,16 +711,9 @@ _dl_update_slotinfo (unsigned long int req_modid)
dtv entry free it. */
/* XXX Ideally we will at some point create a memory
pool. */
- if (! dtv[modid].pointer.is_static
- && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
- /* Note that free is called for NULL is well. We
- deallocate even if it is this dtv entry we are
- supposed to load. The reason is that we call
- memalign and not malloc. */
- free (dtv[modid].pointer.val);
-
+ free (dtv[modid].pointer.to_free);
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
- dtv[modid].pointer.is_static = false;
+ dtv[modid].pointer.to_free = NULL;
if (modid == req_modid)
the_map = map;
@@ -780,7 +776,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
#endif
__rtld_lock_unlock_recursive (GL(dl_load_lock));
- dtv[GET_ADDR_MODULE].pointer.is_static = true;
+ dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
dtv[GET_ADDR_MODULE].pointer.val = p;
return (char *) p + GET_ADDR_OFFSET;
@@ -788,10 +784,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
else
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}
- void *p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
- assert (!dtv[GET_ADDR_MODULE].pointer.is_static);
+ struct dtv_pointer result = allocate_and_init (the_map);
+ dtv[GET_ADDR_MODULE].pointer = result;
+ assert (result.to_free != NULL);
- return (char *) p + GET_ADDR_OFFSET;
+ return (char *) result.val + GET_ADDR_OFFSET;
}
diff --git a/elf/dl-tsd.c b/elf/dl-tsd.c
deleted file mode 100644
index 7181e1c9e0..0000000000
--- a/elf/dl-tsd.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Thread-local data used by error handling for runtime dynamic linker.
- Copyright (C) 2002-2016 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
- <http://www.gnu.org/licenses/>. */
-
-#ifdef _LIBC_REENTRANT
-
-# include <ldsodefs.h>
-# include <tls.h>
-
-# ifndef SHARED
-
-/* _dl_error_catch_tsd points to this for the single-threaded case.
- It's reset by the thread library for multithreaded programs
- if we're not using __thread. */
-void ** __attribute__ ((const))
-_dl_initial_error_catch_tsd (void)
-{
- static __thread void *data;
- return &data;
-}
-void **(*_dl_error_catch_tsd) (void) __attribute__ ((const))
- = &_dl_initial_error_catch_tsd;
-
-# else
-
-/* libpthread sets _dl_error_catch_tsd to point to this function.
- We define it here instead of in libpthread so that it doesn't
- need to have a TLS segment of its own just for this one pointer. */
-
-void ** __attribute__ ((const))
-__libc_dl_error_tsd (void)
-{
- static __thread void *data attribute_tls_model_ie;
- return &data;
-}
-
-# endif /* SHARED */
-
-#endif /* _LIBC_REENTRANT */
diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h
new file mode 100644
index 0000000000..884a0b04d0
--- /dev/null
+++ b/elf/dl-tunable-types.h
@@ -0,0 +1,62 @@
+/* Tunable type information.
+
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TUNABLE_TYPES_H_
+# define _TUNABLE_TYPES_H_
+#include <stddef.h>
+
+typedef enum
+{
+ TUNABLE_TYPE_INT_32,
+ TUNABLE_TYPE_UINT_64,
+ TUNABLE_TYPE_SIZE_T,
+ TUNABLE_TYPE_STRING
+} tunable_type_code_t;
+
+typedef struct
+{
+ tunable_type_code_t type_code;
+ int64_t min;
+ int64_t max;
+} tunable_type_t;
+
+typedef union
+{
+ int64_t numval;
+ const char *strval;
+} tunable_val_t;
+
+typedef void (*tunable_callback_t) (tunable_val_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;
+
+
+#endif
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
new file mode 100644
index 0000000000..4c9d36e398
--- /dev/null
+++ b/elf/dl-tunables.c
@@ -0,0 +1,403 @@
+/* The tunable framework. See the README.tunables to know how to use the
+ tunable in a glibc module.
+
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <startup.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <fcntl.h>
+#include <ldsodefs.h>
+
+#define TUNABLES_INTERNAL 1
+#include "dl-tunables.h"
+
+#include <not-errno.h>
+
+#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
+# define GLIBC_TUNABLES "GLIBC_TUNABLES"
+#endif
+
+#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
+static char *
+tunables_strdup (const char *in)
+{
+ size_t i = 0;
+
+ while (in[i++] != '\0');
+ char *out = __sbrk (i);
+
+ /* FIXME: In reality if the allocation fails, __sbrk will crash attempting to
+ set the thread-local errno since the TCB has not yet been set up. This
+ needs to be fixed with an __sbrk implementation that does not set
+ errno. */
+ if (out == (void *)-1)
+ return NULL;
+
+ i--;
+
+ while (i-- > 0)
+ out[i] = in[i];
+
+ return out;
+}
+#endif
+
+static char **
+get_next_env (char **envp, char **name, size_t *namelen, char **val,
+ char ***prev_envp)
+{
+ while (envp != NULL && *envp != NULL)
+ {
+ char **prev = envp;
+ char *envline = *envp++;
+ int len = 0;
+
+ while (envline[len] != '\0' && envline[len] != '=')
+ len++;
+
+ /* Just the name and no value, go to the next one. */
+ if (envline[len] == '\0')
+ continue;
+
+ *name = envline;
+ *namelen = len;
+ *val = &envline[len + 1];
+ *prev_envp = prev;
+
+ return envp;
+ }
+
+ return NULL;
+}
+
+#define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type) \
+({ \
+ __type min = (__cur)->type.min; \
+ __type max = (__cur)->type.max; \
+ \
+ if ((__type) (__val) >= min && (__type) (val) <= max) \
+ { \
+ (__cur)->val.numval = val; \
+ (__cur)->initialized = true; \
+ } \
+})
+
+static void
+do_tunable_update_val (tunable_t *cur, const void *valp)
+{
+ uint64_t val;
+
+ if (cur->type.type_code != TUNABLE_TYPE_STRING)
+ val = *((int64_t *) valp);
+
+ switch (cur->type.type_code)
+ {
+ case TUNABLE_TYPE_INT_32:
+ {
+ TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t);
+ break;
+ }
+ case TUNABLE_TYPE_UINT_64:
+ {
+ TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t);
+ break;
+ }
+ case TUNABLE_TYPE_SIZE_T:
+ {
+ TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t);
+ break;
+ }
+ case TUNABLE_TYPE_STRING:
+ {
+ cur->val.strval = valp;
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+/* Validate range of the input value and initialize the tunable CUR if it looks
+ good. */
+static void
+tunable_initialize (tunable_t *cur, const char *strval)
+{
+ uint64_t val;
+ const void *valp;
+
+ if (cur->type.type_code != TUNABLE_TYPE_STRING)
+ {
+ val = _dl_strtoul (strval, NULL);
+ valp = &val;
+ }
+ else
+ {
+ cur->initialized = true;
+ valp = strval;
+ }
+ do_tunable_update_val (cur, valp);
+}
+
+void
+__tunable_set_val (tunable_id_t id, void *valp)
+{
+ tunable_t *cur = &tunable_list[id];
+
+ do_tunable_update_val (cur, valp);
+}
+
+#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
+/* Parse the tunable string TUNESTR and adjust it to drop any tunables that may
+ be unsafe for AT_SECURE processes so that it can be used as the new
+ environment variable value for GLIBC_TUNABLES. VALSTRING is the original
+ environment variable string which we use to make NULL terminated values so
+ that we don't have to allocate memory again for it. */
+static void
+parse_tunables (char *tunestr, char *valstring)
+{
+ if (tunestr == NULL || *tunestr == '\0')
+ return;
+
+ char *p = tunestr;
+
+ while (true)
+ {
+ char *name = p;
+ size_t len = 0;
+
+ /* First, find where the name ends. */
+ while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
+ len++;
+
+ /* If we reach the end of the string before getting a valid name-value
+ pair, bail out. */
+ if (p[len] == '\0')
+ return;
+
+ /* We did not find a valid name-value pair before encountering the
+ colon. */
+ if (p[len]== ':')
+ {
+ p += len + 1;
+ continue;
+ }
+
+ p += len + 1;
+
+ /* Take the value from the valstring since we need to NULL terminate it. */
+ char *value = &valstring[p - tunestr];
+ len = 0;
+
+ while (p[len] != ':' && p[len] != '\0')
+ len++;
+
+ /* Add the tunable if it exists. */
+ for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
+ {
+ tunable_t *cur = &tunable_list[i];
+
+ if (tunable_is_name (cur->name, name))
+ {
+ /* If we are in a secure context (AT_SECURE) then ignore the tunable
+ unless it is explicitly marked as secure. Tunable values take
+ precendence over their envvar aliases. */
+ if (__libc_enable_secure)
+ {
+ if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
+ {
+ if (p[len] == '\0')
+ {
+ /* Last tunable in the valstring. Null-terminate and
+ return. */
+ *name = '\0';
+ return;
+ }
+ else
+ {
+ /* Remove the current tunable from the string. We do
+ this by overwriting the string starting from NAME
+ (which is where the current tunable begins) with
+ the remainder of the string. We then have P point
+ to NAME so that we continue in the correct
+ position in the valstring. */
+ char *q = &p[len + 1];
+ p = name;
+ while (*q != '\0')
+ *name++ = *q++;
+ name[0] = '\0';
+ len = 0;
+ }
+ }
+
+ if (cur->security_level != TUNABLE_SECLEVEL_NONE)
+ break;
+ }
+
+ value[len] = '\0';
+ tunable_initialize (cur, value);
+ break;
+ }
+ }
+
+ if (p[len] == '\0')
+ return;
+ else
+ p += len + 1;
+ }
+}
+#endif
+
+/* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
+ the system administrator has created the /etc/suid-debug file. This is a
+ special case where we want to conditionally enable/disable a tunable even
+ for setuid binaries. We use the special version of access() to avoid
+ setting ERRNO, which is a TLS variable since TLS has not yet been set
+ up. */
+static inline void
+__always_inline
+maybe_enable_malloc_check (void)
+{
+ tunable_id_t id = TUNABLE_ENUM_NAME (glibc, malloc, check);
+ if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) == 0)
+ tunable_list[id].security_level = TUNABLE_SECLEVEL_NONE;
+}
+
+/* Initialize the tunables list from the environment. For now we only use the
+ ENV_ALIAS to find values. Later we will also use the tunable names to find
+ values. */
+void
+__tunables_init (char **envp)
+{
+ char *envname = NULL;
+ char *envval = NULL;
+ size_t len = 0;
+ char **prev_envp = envp;
+
+ maybe_enable_malloc_check ();
+
+ while ((envp = get_next_env (envp, &envname, &len, &envval,
+ &prev_envp)) != NULL)
+ {
+#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
+ if (tunable_is_name (GLIBC_TUNABLES, envname))
+ {
+ char *new_env = tunables_strdup (envname);
+ if (new_env != NULL)
+ parse_tunables (new_env + len + 1, envval);
+ /* Put in the updated envval. */
+ *prev_envp = new_env;
+ continue;
+ }
+#endif
+
+ for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
+ {
+ tunable_t *cur = &tunable_list[i];
+
+ /* Skip over tunables that have either been set already or should be
+ skipped. */
+ if (cur->initialized || cur->env_alias == NULL)
+ continue;
+
+ const char *name = cur->env_alias;
+
+ /* We have a match. Initialize and move on to the next line. */
+ if (tunable_is_name (name, envname))
+ {
+ /* For AT_SECURE binaries, we need to check the security settings of
+ the tunable and decide whether we read the value and also whether
+ we erase the value so that child processes don't inherit them in
+ the environment. */
+ if (__libc_enable_secure)
+ {
+ if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
+ {
+ /* Erase the environment variable. */
+ char **ep = prev_envp;
+
+ while (*ep != NULL)
+ {
+ if (tunable_is_name (name, *ep))
+ {
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ }
+ else
+ ++ep;
+ }
+ /* Reset the iterator so that we read the environment again
+ from the point we erased. */
+ envp = prev_envp;
+ }
+
+ if (cur->security_level != TUNABLE_SECLEVEL_NONE)
+ continue;
+ }
+
+ tunable_initialize (cur, envval);
+ break;
+ }
+ }
+ }
+}
+
+/* Set the tunable value. This is called by the module that the tunable exists
+ in. */
+void
+__tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
+{
+ tunable_t *cur = &tunable_list[id];
+
+ switch (cur->type.type_code)
+ {
+ case TUNABLE_TYPE_UINT_64:
+ {
+ *((uint64_t *) valp) = (uint64_t) cur->val.numval;
+ break;
+ }
+ case TUNABLE_TYPE_INT_32:
+ {
+ *((int32_t *) valp) = (int32_t) cur->val.numval;
+ break;
+ }
+ case TUNABLE_TYPE_SIZE_T:
+ {
+ *((size_t *) valp) = (size_t) cur->val.numval;
+ break;
+ }
+ case TUNABLE_TYPE_STRING:
+ {
+ *((const char **)valp) = cur->val.strval;
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+
+ if (cur->initialized && callback != NULL)
+ callback (&cur->val);
+}
+
+rtld_hidden_def (__tunable_get_val)
diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h
new file mode 100644
index 0000000000..928b30dde9
--- /dev/null
+++ b/elf/dl-tunables.h
@@ -0,0 +1,132 @@
+/* The tunable framework. See the README to know how to use the tunable in
+ a glibc module.
+
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TUNABLES_H_
+#define _TUNABLES_H_
+
+#if !HAVE_TUNABLES
+static inline void
+__always_inline
+__tunables_init (char **unused __attribute__ ((unused)))
+{
+ /* This is optimized out if tunables are not enabled. */
+}
+#else
+
+# include <stddef.h>
+# include "dl-tunable-types.h"
+
+/* A tunable. */
+struct _tunable
+{
+ const char *name; /* Internal name of the tunable. */
+ tunable_type_t type; /* Data type of the tunable. */
+ tunable_val_t val; /* The value. */
+ bool initialized; /* Flag to indicate that the tunable is
+ initialized. */
+ tunable_seclevel_t security_level; /* Specify the security level for the
+ tunable with respect to AT_SECURE
+ programs. See description of
+ tunable_seclevel_t to see a
+ description of the values.
+
+ Note that even if the tunable is
+ read, it may not get used by the
+ target module if the value is
+ considered unsafe. */
+ /* Compatibility elements. */
+ const char *env_alias; /* The compatibility environment
+ variable name. */
+};
+
+typedef struct _tunable tunable_t;
+
+/* Full name for a tunable is top_ns.tunable_ns.id. */
+# define TUNABLE_NAME_S(top,ns,id) #top "." #ns "." #id
+
+# define TUNABLE_ENUM_NAME(__top,__ns,__id) TUNABLE_ENUM_NAME1 (__top,__ns,__id)
+# define TUNABLE_ENUM_NAME1(__top,__ns,__id) __top ## _ ## __ns ## _ ## __id
+
+# include "dl-tunable-list.h"
+
+extern void __tunables_init (char **);
+extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t);
+extern void __tunable_set_val (tunable_id_t, void *);
+rtld_hidden_proto (__tunables_init)
+rtld_hidden_proto (__tunable_get_val)
+
+/* 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
+ tunables within a module. */
+#if defined TOP_NAMESPACE && defined TUNABLE_NAMESPACE
+# define TUNABLE_GET(__id, __type, __cb) \
+ TUNABLE_GET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __cb)
+# define TUNABLE_SET(__id, __type, __val) \
+ TUNABLE_SET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __val)
+#else
+# define TUNABLE_GET(__top, __ns, __id, __type, __cb) \
+ TUNABLE_GET_FULL (__top, __ns, __id, __type, __cb)
+# define TUNABLE_SET(__top, __ns, __id, __type, __val) \
+ TUNABLE_SET_FULL (__top, __ns, __id, __type, __val)
+#endif
+
+/* Get and return a tunable value. If the tunable was set externally and __CB
+ is defined then call __CB before returning the value. */
+# define TUNABLE_GET_FULL(__top, __ns, __id, __type, __cb) \
+({ \
+ tunable_id_t id = TUNABLE_ENUM_NAME (__top, __ns, __id); \
+ __type ret; \
+ __tunable_get_val (id, &ret, __cb); \
+ ret; \
+})
+
+/* Set a tunable value. */
+# define TUNABLE_SET_FULL(__top, __ns, __id, __type, __val) \
+({ \
+ __tunable_set_val (TUNABLE_ENUM_NAME (__top, __ns, __id), \
+ & (__type) {__val}); \
+})
+
+/* Namespace sanity for callback functions. Use this macro to keep the
+ namespace of the modules clean. */
+# define TUNABLE_CALLBACK(__name) _dl_tunable_ ## __name
+
+# define TUNABLES_FRONTEND_valstring 1
+/* The default value for TUNABLES_FRONTEND. */
+# define TUNABLES_FRONTEND_yes TUNABLES_FRONTEND_valstring
+
+/* Compare two name strings, bounded by the name hardcoded in glibc. */
+static inline bool
+__always_inline
+tunable_is_name (const char *orig, const char *envname)
+{
+ for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
+ if (*orig != *envname)
+ break;
+
+ /* The ENVNAME is immediately followed by a value. */
+ if (*orig == '\0' && *envname == '=')
+ return true;
+ else
+ return false;
+}
+
+#endif
+#endif
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
new file mode 100644
index 0000000000..1f8ecb8437
--- /dev/null
+++ b/elf/dl-tunables.list
@@ -0,0 +1,124 @@
+# Copyright (C) 2016-2018 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
+# <http://www.gnu.org/licenses/>.
+
+# Allowed attributes for tunables:
+#
+# type: Defaults to STRING
+# minval: Optional minimum acceptable value
+# maxval: Optional maximum acceptable value
+# env_alias: An alias environment variable
+# security_level: Specify security level of the tunable. Valid values are:
+#
+# SXID_ERASE: (default) Don't read for AT_SECURE binaries and
+# removed so that child processes can't read it.
+# SXID_IGNORE: Don't read for AT_SECURE binaries, but retained for
+# non-AT_SECURE subprocesses.
+# NONE: Read all the time.
+
+glibc {
+ malloc {
+ check {
+ type: INT_32
+ minval: 0
+ maxval: 3
+ env_alias: MALLOC_CHECK_
+ }
+ top_pad {
+ type: SIZE_T
+ env_alias: MALLOC_TOP_PAD_
+ security_level: SXID_IGNORE
+ }
+ perturb {
+ type: INT_32
+ minval: 0
+ maxval: 0xff
+ env_alias: MALLOC_PERTURB_
+ security_level: SXID_IGNORE
+ }
+ mmap_threshold {
+ type: SIZE_T
+ env_alias: MALLOC_MMAP_THRESHOLD_
+ security_level: SXID_IGNORE
+ }
+ trim_threshold {
+ type: SIZE_T
+ env_alias: MALLOC_TRIM_THRESHOLD_
+ security_level: SXID_IGNORE
+ }
+ mmap_max {
+ type: INT_32
+ env_alias: MALLOC_MMAP_MAX_
+ security_level: SXID_IGNORE
+ }
+ arena_max {
+ type: SIZE_T
+ env_alias: MALLOC_ARENA_MAX
+ minval: 1
+ security_level: SXID_IGNORE
+ }
+ arena_test {
+ type: SIZE_T
+ env_alias: MALLOC_ARENA_TEST
+ minval: 1
+ security_level: SXID_IGNORE
+ }
+ tcache_max {
+ type: SIZE_T
+ }
+ tcache_count {
+ type: SIZE_T
+ }
+ tcache_unsorted_limit {
+ type: SIZE_T
+ }
+ }
+ tune {
+ hwcap_mask {
+ type: UINT_64
+ env_alias: LD_HWCAP_MASK
+ default: HWCAP_IMPORTANT
+ }
+ }
+
+ elision {
+ enable {
+ type: INT_32
+ minval: 0
+ maxval: 1
+ }
+ skip_lock_busy {
+ type: INT_32
+ default: 3
+ }
+ skip_lock_internal_abort {
+ type: INT_32
+ default: 3
+ }
+ skip_lock_after_retries {
+ type: INT_32
+ default: 3
+ }
+ tries {
+ type: INT_32
+ default: 3
+ }
+ skip_trylock_internal_abort {
+ type: INT_32
+ default: 3
+ }
+ }
+}
diff --git a/elf/dl-unmap-segments.h b/elf/dl-unmap-segments.h
index 44d91c4398..3294326425 100644
--- a/elf/dl-unmap-segments.h
+++ b/elf/dl-unmap-segments.h
@@ -1,5 +1,5 @@
/* Unmap a shared object's segments. Generic version.
- Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Copyright (C) 2014-2018 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
diff --git a/elf/dl-version.c b/elf/dl-version.c
index 3843f8fdf0..7860cc817e 100644
--- a/elf/dl-version.c
+++ b/elf/dl-version.c
@@ -1,5 +1,5 @@
/* Handle symbol and library versioning.
- Copyright (C) 1997-2016 Free Software Foundation, Inc.
+ Copyright (C) 1997-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -27,25 +27,6 @@
#include <assert.h>
-
-#define make_string(string, rest...) \
- ({ \
- const char *all[] = { string, ## rest }; \
- size_t len, cnt; \
- char *result, *cp; \
- \
- len = 1; \
- for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- len += strlen (all[cnt]); \
- \
- cp = result = alloca (len); \
- for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- cp = __stpcpy (cp, all[cnt]); \
- \
- result; \
- })
-
-
static inline struct link_map *
__attribute ((always_inline))
find_needed (const char *name, struct link_map *map)
@@ -70,7 +51,6 @@ find_needed (const char *name, struct link_map *map)
static int
-internal_function
match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
struct link_map *map, int verbose, int weak)
{
@@ -78,8 +58,8 @@ match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
ElfW(Addr) def_offset;
ElfW(Verdef) *def;
/* Initialize to make the compiler happy. */
- const char *errstring = NULL;
int result = 0;
+ struct dl_exception exception;
/* Display information about what we are doing while debugging. */
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
@@ -96,8 +76,9 @@ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
if (verbose)
{
/* XXX We cannot translate the messages. */
- errstring = make_string ("\
-no version information available (required by ", name, ")");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "no version information available (required by %s)", name);
goto call_cerror;
}
return 0;
@@ -116,10 +97,10 @@ no version information available (required by ", name, ")");
char buf[20];
buf[sizeof (buf) - 1] = '\0';
/* XXX We cannot translate the message. */
- errstring = make_string ("unsupported version ",
- _itoa (def->vd_version,
- &buf[sizeof (buf) - 1], 10, 0),
- " of Verdef record");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "unsupported version %s of Verdef record",
+ _itoa (def->vd_version, &buf[sizeof (buf) - 1], 10, 0));
result = 1;
goto call_cerror;
}
@@ -150,26 +131,27 @@ no version information available (required by ", name, ")");
if (verbose)
{
/* XXX We cannot translate the message. */
- errstring = make_string ("weak version `", string,
- "' not found (required by ", name, ")");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "weak version `%s' not found (required by %s)", string, name);
goto call_cerror;
}
return 0;
}
/* XXX We cannot translate the message. */
- errstring = make_string ("version `", string, "' not found (required by ",
- name, ")");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "version `%s' not found (required by %s)", string, name);
result = 1;
call_cerror:
- _dl_signal_cerror (0, DSO_FILENAME (map->l_name),
- N_("version lookup error"), errstring);
+ _dl_signal_cexception (0, &exception, N_("version lookup error"));
+ _dl_exception_free (&exception);
return result;
}
int
-internal_function
_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
{
int result = 0;
@@ -181,8 +163,8 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
/* We need to find out which is the highest version index used
in a dependecy. */
unsigned int ndx_high = 0;
+ struct dl_exception exception;
/* Initialize to make the compiler happy. */
- const char *errstring = NULL;
int errval = 0;
/* If we don't have a string table, we must be ok. */
@@ -205,13 +187,12 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
char buf[20];
buf[sizeof (buf) - 1] = '\0';
/* XXX We cannot translate the message. */
- errstring = make_string ("unsupported version ",
- _itoa (ent->vn_version,
- &buf[sizeof (buf) - 1], 10, 0),
- " of Verneed record\n");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "unsupported version %s of Verneed record",
+ _itoa (ent->vn_version, &buf[sizeof (buf) - 1], 10, 0));
call_error:
- _dl_signal_error (errval, DSO_FILENAME (map->l_name),
- NULL, errstring);
+ _dl_signal_exception (errval, &exception, NULL);
}
while (1)
@@ -293,7 +274,9 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
calloc (ndx_high + 1, sizeof (*map->l_versions));
if (__glibc_unlikely (map->l_versions == NULL))
{
- errstring = N_("cannot allocate version reference table");
+ _dl_exception_create
+ (&exception, DSO_FILENAME (map->l_name),
+ N_("cannot allocate version reference table"));
errval = ENOMEM;
goto call_error;
}
@@ -375,7 +358,6 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
int
-internal_function
_dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
{
struct link_map *l;
diff --git a/elf/dl-writev.h b/elf/dl-writev.h
index 0c8c787cc9..e8d0057e30 100644
--- a/elf/dl-writev.h
+++ b/elf/dl-writev.h
@@ -1,5 +1,5 @@
/* Message-writing for the dynamic linker. Generic version.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2018 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
diff --git a/elf/do-rel.h b/elf/do-rel.h
index 10c284661d..19cb5d236e 100644
--- a/elf/do-rel.h
+++ b/elf/do-rel.h
@@ -1,5 +1,5 @@
/* Do relocations for ELF dynamic linking.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 9fb6459236..9e9d5a3b28 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -1,5 +1,5 @@
/* Inline functions for dynamic linking.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -42,8 +42,7 @@
&& (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \
|| _dl_try_allocate_static_tls (sym_map) == 0))
-int internal_function attribute_hidden
- _dl_try_allocate_static_tls (struct link_map *map);
+int _dl_try_allocate_static_tls (struct link_map *map) attribute_hidden;
#include <elf.h>
@@ -95,7 +94,7 @@ elf_machine_lazy_rel (struct link_map *map,
#ifdef RESOLVE_MAP
-# ifdef RTLD_BOOTSTRAP
+# if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP
# define ELF_DURING_STARTUP (1)
# else
# define ELF_DURING_STARTUP (0)
diff --git a/elf/elf.h b/elf/elf.h
index 15f5a75dec..7e2b072a7f 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1,5 +1,5 @@
/* This file defines standard ELF types, structures, and macros.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -172,89 +172,200 @@ typedef struct
/* Legal values for e_machine (architecture). */
-#define EM_NONE 0 /* No machine */
-#define EM_M32 1 /* AT&T WE 32100 */
-#define EM_SPARC 2 /* SUN SPARC */
-#define EM_386 3 /* Intel 80386 */
-#define EM_68K 4 /* Motorola m68k family */
-#define EM_88K 5 /* Motorola m88k family */
-#define EM_860 7 /* Intel 80860 */
-#define EM_MIPS 8 /* MIPS R3000 big-endian */
-#define EM_S370 9 /* IBM System/370 */
-#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
-
-#define EM_PARISC 15 /* HPPA */
-#define EM_VPP500 17 /* Fujitsu VPP500 */
-#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
-#define EM_960 19 /* Intel 80960 */
-#define EM_PPC 20 /* PowerPC */
-#define EM_PPC64 21 /* PowerPC 64-bit */
-#define EM_S390 22 /* IBM S390 */
-
-#define EM_V800 36 /* NEC V800 series */
-#define EM_FR20 37 /* Fujitsu FR20 */
-#define EM_RH32 38 /* TRW RH-32 */
-#define EM_RCE 39 /* Motorola RCE */
-#define EM_ARM 40 /* ARM */
-#define EM_FAKE_ALPHA 41 /* Digital Alpha */
-#define EM_SH 42 /* Hitachi SH */
-#define EM_SPARCV9 43 /* SPARC v9 64-bit */
-#define EM_TRICORE 44 /* Siemens Tricore */
-#define EM_ARC 45 /* Argonaut RISC Core */
-#define EM_H8_300 46 /* Hitachi H8/300 */
-#define EM_H8_300H 47 /* Hitachi H8/300H */
-#define EM_H8S 48 /* Hitachi H8S */
-#define EM_H8_500 49 /* Hitachi H8/500 */
-#define EM_IA_64 50 /* Intel Merced */
-#define EM_MIPS_X 51 /* Stanford MIPS-X */
-#define EM_COLDFIRE 52 /* Motorola Coldfire */
-#define EM_68HC12 53 /* Motorola M68HC12 */
-#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
-#define EM_PCP 55 /* Siemens PCP */
-#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
-#define EM_NDR1 57 /* Denso NDR1 microprocessor */
-#define EM_STARCORE 58 /* Motorola Start*Core processor */
-#define EM_ME16 59 /* Toyota ME16 processor */
-#define EM_ST100 60 /* STMicroelectronic ST100 processor */
-#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
-#define EM_X86_64 62 /* AMD x86-64 architecture */
-#define EM_PDSP 63 /* Sony DSP Processor */
-
-#define EM_FX66 66 /* Siemens FX66 microcontroller */
-#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
-#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
-#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
-#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
-#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
-#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
-#define EM_SVX 73 /* Silicon Graphics SVx */
-#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
-#define EM_VAX 75 /* Digital VAX */
-#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
-#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
-#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
-#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
-#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
-#define EM_HUANY 81 /* Harvard University machine-independent object files */
-#define EM_PRISM 82 /* SiTera Prism */
-#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
-#define EM_FR30 84 /* Fujitsu FR30 */
-#define EM_D10V 85 /* Mitsubishi D10V */
-#define EM_D30V 86 /* Mitsubishi D30V */
-#define EM_V850 87 /* NEC v850 */
-#define EM_M32R 88 /* Mitsubishi M32R */
-#define EM_MN10300 89 /* Matsushita MN10300 */
-#define EM_MN10200 90 /* Matsushita MN10200 */
-#define EM_PJ 91 /* picoJava */
-#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
-#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
-#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
-#define EM_ALTERA_NIOS2 113 /* Altera Nios II */
-#define EM_AARCH64 183 /* ARM AARCH64 */
-#define EM_TILEPRO 188 /* Tilera TILEPro */
-#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
-#define EM_TILEGX 191 /* Tilera TILE-Gx */
-#define EM_NUM 192
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_IAMCU 6 /* Intel MCU */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 big-endian */
+#define EM_S370 9 /* IBM System/370 */
+#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
+ /* reserved 11-14 */
+#define EM_PARISC 15 /* HPPA */
+ /* reserved 16 */
+#define EM_VPP500 17 /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+#define EM_960 19 /* Intel 80960 */
+#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC 64-bit */
+#define EM_S390 22 /* IBM S390 */
+#define EM_SPU 23 /* IBM SPU/SPC */
+ /* reserved 24-35 */
+#define EM_V800 36 /* NEC V800 series */
+#define EM_FR20 37 /* Fujitsu FR20 */
+#define EM_RH32 38 /* TRW RH-32 */
+#define EM_RCE 39 /* Motorola RCE */
+#define EM_ARM 40 /* ARM */
+#define EM_FAKE_ALPHA 41 /* Digital Alpha */
+#define EM_SH 42 /* Hitachi SH */
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+#define EM_TRICORE 44 /* Siemens Tricore */
+#define EM_ARC 45 /* Argonaut RISC Core */
+#define EM_H8_300 46 /* Hitachi H8/300 */
+#define EM_H8_300H 47 /* Hitachi H8/300H */
+#define EM_H8S 48 /* Hitachi H8S */
+#define EM_H8_500 49 /* Hitachi H8/500 */
+#define EM_IA_64 50 /* Intel Merced */
+#define EM_MIPS_X 51 /* Stanford MIPS-X */
+#define EM_COLDFIRE 52 /* Motorola Coldfire */
+#define EM_68HC12 53 /* Motorola M68HC12 */
+#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */
+#define EM_PCP 55 /* Siemens PCP */
+#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
+#define EM_NDR1 57 /* Denso NDR1 microprocessor */
+#define EM_STARCORE 58 /* Motorola Start*Core processor */
+#define EM_ME16 59 /* Toyota ME16 processor */
+#define EM_ST100 60 /* STMicroelectronic ST100 processor */
+#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam */
+#define EM_X86_64 62 /* AMD x86-64 architecture */
+#define EM_PDSP 63 /* Sony DSP Processor */
+#define EM_PDP10 64 /* Digital PDP-10 */
+#define EM_PDP11 65 /* Digital PDP-11 */
+#define EM_FX66 66 /* Siemens FX66 microcontroller */
+#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
+#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
+#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
+#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
+#define EM_SVX 73 /* Silicon Graphics SVx */
+#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX 75 /* Digital VAX */
+#define EM_CRIS 76 /* Axis Communications 32-bit emb.proc */
+#define EM_JAVELIN 77 /* Infineon Technologies 32-bit emb.proc */
+#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
+#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX 80 /* Donald Knuth's educational 64-bit proc */
+#define EM_HUANY 81 /* Harvard University machine-independent object files */
+#define EM_PRISM 82 /* SiTera Prism */
+#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
+#define EM_FR30 84 /* Fujitsu FR30 */
+#define EM_D10V 85 /* Mitsubishi D10V */
+#define EM_D30V 86 /* Mitsubishi D30V */
+#define EM_V850 87 /* NEC v850 */
+#define EM_M32R 88 /* Mitsubishi M32R */
+#define EM_MN10300 89 /* Matsushita MN10300 */
+#define EM_MN10200 90 /* Matsushita MN10200 */
+#define EM_PJ 91 /* picoJava */
+#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
+#define EM_ARC_COMPACT 93 /* ARC International ARCompact */
+#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
+#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore */
+#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose Proc */
+#define EM_NS32K 97 /* National Semi. 32000 */
+#define EM_TPC 98 /* Tenor Network TPC */
+#define EM_SNP1K 99 /* Trebia SNP 1000 */
+#define EM_ST200 100 /* STMicroelectronics ST200 */
+#define EM_IP2K 101 /* Ubicom IP2xxx */
+#define EM_MAX 102 /* MAX processor */
+#define EM_CR 103 /* National Semi. CompactRISC */
+#define EM_F2MC16 104 /* Fujitsu F2MC16 */
+#define EM_MSP430 105 /* Texas Instruments msp430 */
+#define EM_BLACKFIN 106 /* Analog Devices Blackfin DSP */
+#define EM_SE_C33 107 /* Seiko Epson S1C33 family */
+#define EM_SEP 108 /* Sharp embedded microprocessor */
+#define EM_ARCA 109 /* Arca RISC */
+#define EM_UNICORE 110 /* PKU-Unity & MPRC Peking Uni. mc series */
+#define EM_EXCESS 111 /* eXcess configurable cpu */
+#define EM_DXP 112 /* Icera Semi. Deep Execution Processor */
+#define EM_ALTERA_NIOS2 113 /* Altera Nios II */
+#define EM_CRX 114 /* National Semi. CompactRISC CRX */
+#define EM_XGATE 115 /* Motorola XGATE */
+#define EM_C166 116 /* Infineon C16x/XC16x */
+#define EM_M16C 117 /* Renesas M16C */
+#define EM_DSPIC30F 118 /* Microchip Technology dsPIC30F */
+#define EM_CE 119 /* Freescale Communication Engine RISC */
+#define EM_M32C 120 /* Renesas M32C */
+ /* reserved 121-130 */
+#define EM_TSK3000 131 /* Altium TSK3000 */
+#define EM_RS08 132 /* Freescale RS08 */
+#define EM_SHARC 133 /* Analog Devices SHARC family */
+#define EM_ECOG2 134 /* Cyan Technology eCOG2 */
+#define EM_SCORE7 135 /* Sunplus S+core7 RISC */
+#define EM_DSP24 136 /* New Japan Radio (NJR) 24-bit DSP */
+#define EM_VIDEOCORE3 137 /* Broadcom VideoCore III */
+#define EM_LATTICEMICO32 138 /* RISC for Lattice FPGA */
+#define EM_SE_C17 139 /* Seiko Epson C17 */
+#define EM_TI_C6000 140 /* Texas Instruments TMS320C6000 DSP */
+#define EM_TI_C2000 141 /* Texas Instruments TMS320C2000 DSP */
+#define EM_TI_C5500 142 /* Texas Instruments TMS320C55x DSP */
+#define EM_TI_ARP32 143 /* Texas Instruments App. Specific RISC */
+#define EM_TI_PRU 144 /* Texas Instruments Prog. Realtime Unit */
+ /* reserved 145-159 */
+#define EM_MMDSP_PLUS 160 /* STMicroelectronics 64bit VLIW DSP */
+#define EM_CYPRESS_M8C 161 /* Cypress M8C */
+#define EM_R32C 162 /* Renesas R32C */
+#define EM_TRIMEDIA 163 /* NXP Semi. TriMedia */
+#define EM_QDSP6 164 /* QUALCOMM DSP6 */
+#define EM_8051 165 /* Intel 8051 and variants */
+#define EM_STXP7X 166 /* STMicroelectronics STxP7x */
+#define EM_NDS32 167 /* Andes Tech. compact code emb. RISC */
+#define EM_ECOG1X 168 /* Cyan Technology eCOG1X */
+#define EM_MAXQ30 169 /* Dallas Semi. MAXQ30 mc */
+#define EM_XIMO16 170 /* New Japan Radio (NJR) 16-bit DSP */
+#define EM_MANIK 171 /* M2000 Reconfigurable RISC */
+#define EM_CRAYNV2 172 /* Cray NV2 vector architecture */
+#define EM_RX 173 /* Renesas RX */
+#define EM_METAG 174 /* Imagination Tech. META */
+#define EM_MCST_ELBRUS 175 /* MCST Elbrus */
+#define EM_ECOG16 176 /* Cyan Technology eCOG16 */
+#define EM_CR16 177 /* National Semi. CompactRISC CR16 */
+#define EM_ETPU 178 /* Freescale Extended Time Processing Unit */
+#define EM_SLE9X 179 /* Infineon Tech. SLE9X */
+#define EM_L10M 180 /* Intel L10M */
+#define EM_K10M 181 /* Intel K10M */
+ /* reserved 182 */
+#define EM_AARCH64 183 /* ARM AARCH64 */
+ /* reserved 184 */
+#define EM_AVR32 185 /* Amtel 32-bit microprocessor */
+#define EM_STM8 186 /* STMicroelectronics STM8 */
+#define EM_TILE64 187 /* Tileta TILE64 */
+#define EM_TILEPRO 188 /* Tilera TILEPro */
+#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
+#define EM_CUDA 190 /* NVIDIA CUDA */
+#define EM_TILEGX 191 /* Tilera TILE-Gx */
+#define EM_CLOUDSHIELD 192 /* CloudShield */
+#define EM_COREA_1ST 193 /* KIPO-KAIST Core-A 1st gen. */
+#define EM_COREA_2ND 194 /* KIPO-KAIST Core-A 2nd gen. */
+#define EM_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */
+#define EM_OPEN8 196 /* Open8 RISC */
+#define EM_RL78 197 /* Renesas RL78 */
+#define EM_VIDEOCORE5 198 /* Broadcom VideoCore V */
+#define EM_78KOR 199 /* Renesas 78KOR */
+#define EM_56800EX 200 /* Freescale 56800EX DSC */
+#define EM_BA1 201 /* Beyond BA1 */
+#define EM_BA2 202 /* Beyond BA2 */
+#define EM_XCORE 203 /* XMOS xCORE */
+#define EM_MCHP_PIC 204 /* Microchip 8-bit PIC(r) */
+ /* reserved 205-209 */
+#define EM_KM32 210 /* KM211 KM32 */
+#define EM_KMX32 211 /* KM211 KMX32 */
+#define EM_EMX16 212 /* KM211 KMX16 */
+#define EM_EMX8 213 /* KM211 KMX8 */
+#define EM_KVARC 214 /* KM211 KVARC */
+#define EM_CDP 215 /* Paneve CDP */
+#define EM_COGE 216 /* Cognitive Smart Memory Processor */
+#define EM_COOL 217 /* Bluechip CoolEngine */
+#define EM_NORC 218 /* Nanoradio Optimized RISC */
+#define EM_CSR_KALIMBA 219 /* CSR Kalimba */
+#define EM_Z80 220 /* Zilog Z80 */
+#define EM_VISIUM 221 /* Controls and Data Services VISIUMcore */
+#define EM_FT32 222 /* FTDI Chip FT32 */
+#define EM_MOXIE 223 /* Moxie processor */
+#define EM_AMDGPU 224 /* AMD GPU */
+ /* reserved 225-242 */
+#define EM_RISCV 243 /* RISC-V */
+
+#define EM_BPF 247 /* Linux BPF -- in-kernel virtual machine */
+
+#define EM_NUM 248
+
+/* Old spellings/synonyms. */
+
+#define EM_ARC_A5 EM_ARC_COMPACT
/* If it is necessary to assign new unofficial EM_* values, please
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
@@ -628,6 +739,8 @@ typedef struct
/* Legal values for note segment descriptor types for core files. */
#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+#define NT_PRFPREG 2 /* Contains copy of fpregset
+ struct. */
#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
#define NT_PRXREG 4 /* Contains copy of prxregset struct */
@@ -651,6 +764,24 @@ typedef struct
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
+#define NT_PPC_TAR 0x103 /* Target Address Register */
+#define NT_PPC_PPR 0x104 /* Program Priority Register */
+#define NT_PPC_DSCR 0x105 /* Data Stream Control Register */
+#define NT_PPC_EBB 0x106 /* Event Based Branch Registers */
+#define NT_PPC_PMU 0x107 /* Performance Monitor Registers */
+#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */
+#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */
+#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */
+#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */
+#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */
+#define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address
+ Register */
+#define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority
+ Register */
+#define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control
+ Register */
+#define NT_PPC_PKEY 0x110 /* Memory Protection Keys
+ registers. */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
@@ -663,10 +794,20 @@ typedef struct
#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
+#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15
+ upper half. */
+#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31. */
+#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers. */
+#define NT_S390_GS_BC 0x30c /* s390 guarded storage
+ broadcast control block. */
+#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation. */
#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
#define NT_ARM_TLS 0x401 /* ARM TLS register */
#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
+#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
+#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension
+ registers */
/* Legal values for the note segment descriptor types for object files. */
@@ -731,7 +872,8 @@ typedef struct
#define DT_ENCODING 32 /* Start of encoded range */
#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
-#define DT_NUM 34 /* Number used */
+#define DT_SYMTAB_SHNDX 34 /* Address of SYMTAB_SHNDX section */
+#define DT_NUM 35 /* Number used */
#define DT_LOOS 0x6000000d /* Start of OS-specific */
#define DT_HIOS 0x6ffff000 /* End of OS-specific */
#define DT_LOPROC 0x70000000 /* Start of processor-specific */
@@ -839,6 +981,8 @@ typedef struct
#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */
#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */
#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */
+#define DF_1_STUB 0x04000000
+#define DF_1_PIE 0x08000000
/* Flags for the feature selection in DT_FEATURE_1. */
#define DTF_1_PARINIT 0x00000001
@@ -1058,6 +1202,18 @@ typedef struct
#define AT_L2_CACHESHAPE 36
#define AT_L3_CACHESHAPE 37
+/* Shapes of the caches, with more room to describe them.
+ *GEOMETRY are comprised of cache line size in bytes in the bottom 16 bits
+ and the cache associativity in the next 16 bits. */
+#define AT_L1I_CACHESIZE 40
+#define AT_L1I_CACHEGEOMETRY 41
+#define AT_L1D_CACHESIZE 42
+#define AT_L1D_CACHEGEOMETRY 43
+#define AT_L2_CACHESIZE 44
+#define AT_L2_CACHEGEOMETRY 45
+#define AT_L3_CACHESIZE 46
+#define AT_L3_CACHEGEOMETRY 47
+
/* Note section contents. Each entry in the note section begins with
a header of a fixed form. */
@@ -1123,6 +1279,62 @@ typedef struct
/* Version note generated by GNU gold containing a version string. */
#define NT_GNU_GOLD_VERSION 4
+/* Program property. */
+#define NT_GNU_PROPERTY_TYPE_0 5
+
+/* Note section name of program property. */
+#define NOTE_GNU_PROPERTY_SECTION_NAME ".note.gnu.property"
+
+/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */
+
+/* Stack size. */
+#define GNU_PROPERTY_STACK_SIZE 1
+/* No copy relocation on protected data symbol. */
+#define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2
+
+/* Processor-specific semantics, lo */
+#define GNU_PROPERTY_LOPROC 0xc0000000
+/* Processor-specific semantics, hi */
+#define GNU_PROPERTY_HIPROC 0xdfffffff
+/* Application-specific semantics, lo */
+#define GNU_PROPERTY_LOUSER 0xe0000000
+/* Application-specific semantics, hi */
+#define GNU_PROPERTY_HIUSER 0xffffffff
+
+/* The x86 instruction sets indicated by the corresponding bits are
+ used in program. Their support in the hardware is optional. */
+#define GNU_PROPERTY_X86_ISA_1_USED 0xc0000000
+/* The x86 instruction sets indicated by the corresponding bits are
+ used in program and they must be supported by the hardware. */
+#define GNU_PROPERTY_X86_ISA_1_NEEDED 0xc0000001
+/* X86 processor-specific features used in program. */
+#define GNU_PROPERTY_X86_FEATURE_1_AND 0xc0000002
+
+#define GNU_PROPERTY_X86_ISA_1_486 (1U << 0)
+#define GNU_PROPERTY_X86_ISA_1_586 (1U << 1)
+#define GNU_PROPERTY_X86_ISA_1_686 (1U << 2)
+#define GNU_PROPERTY_X86_ISA_1_SSE (1U << 3)
+#define GNU_PROPERTY_X86_ISA_1_SSE2 (1U << 4)
+#define GNU_PROPERTY_X86_ISA_1_SSE3 (1U << 5)
+#define GNU_PROPERTY_X86_ISA_1_SSSE3 (1U << 6)
+#define GNU_PROPERTY_X86_ISA_1_SSE4_1 (1U << 7)
+#define GNU_PROPERTY_X86_ISA_1_SSE4_2 (1U << 8)
+#define GNU_PROPERTY_X86_ISA_1_AVX (1U << 9)
+#define GNU_PROPERTY_X86_ISA_1_AVX2 (1U << 10)
+#define GNU_PROPERTY_X86_ISA_1_AVX512F (1U << 11)
+#define GNU_PROPERTY_X86_ISA_1_AVX512CD (1U << 12)
+#define GNU_PROPERTY_X86_ISA_1_AVX512ER (1U << 13)
+#define GNU_PROPERTY_X86_ISA_1_AVX512PF (1U << 14)
+#define GNU_PROPERTY_X86_ISA_1_AVX512VL (1U << 15)
+#define GNU_PROPERTY_X86_ISA_1_AVX512DQ (1U << 16)
+#define GNU_PROPERTY_X86_ISA_1_AVX512BW (1U << 17)
+
+/* This indicates that all executable sections are compatible with
+ IBT. */
+#define GNU_PROPERTY_X86_FEATURE_1_IBT (1U << 0)
+/* This indicates that all executable sections are compatible with
+ SHSTK. */
+#define GNU_PROPERTY_X86_FEATURE_1_SHSTK (1U << 1)
/* Move records. */
typedef struct
@@ -1269,8 +1481,10 @@ typedef struct
argument, returning the TLS
offset for the symbol. */
#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
+#define R_386_GOT32X 43 /* Load from 32 bit GOT entry,
+ relaxable. */
/* Keep this the last entry. */
-#define R_386_NUM 43
+#define R_386_NUM 44
/* SUN SPARC specific definitions. */
@@ -2418,9 +2632,10 @@ enum
#define DT_PPC64_OPT (DT_LOPROC + 3)
#define DT_PPC64_NUM 4
-/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry. */
+/* PowerPC64 specific bits in the DT_PPC64_OPT Dyn entry. */
#define PPC64_OPT_TLS 1
#define PPC64_OPT_MULTI_TOC 2
+#define PPC64_OPT_LOCALENTRY 4
/* PowerPC64 specific values for the Elf64_Sym st_other field. */
#define STO_PPC64_LOCAL_BIT 5
@@ -3144,8 +3359,18 @@ enum
#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */
+ /* 39 Reserved was R_X86_64_PC32_BND */
+ /* 40 Reserved was R_X86_64_PLT32_BND */
+#define R_X86_64_GOTPCRELX 41 /* Load from 32 bit signed pc relative
+ offset to GOT entry without REX
+ prefix, relaxable. */
+#define R_X86_64_REX_GOTPCRELX 42 /* Load from 32 bit signed pc relative
+ offset to GOT entry with REX prefix,
+ relaxable. */
+#define R_X86_64_NUM 43
-#define R_X86_64_NUM 39
+/* x86-64 sh_type values. */
+#define SHT_X86_64_UNWIND 0x70000001 /* Unwind information. */
/* AM33 relocations. */
@@ -3556,6 +3781,149 @@ enum
#define R_TILEGX_NUM 130
+/* RISC-V ELF Flags */
+#define EF_RISCV_RVC 0x0001
+#define EF_RISCV_FLOAT_ABI 0x0006
+#define EF_RISCV_FLOAT_ABI_SOFT 0x0000
+#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002
+#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004
+#define EF_RISCV_FLOAT_ABI_QUAD 0x0006
+
+/* RISC-V relocations. */
+#define R_RISCV_NONE 0
+#define R_RISCV_32 1
+#define R_RISCV_64 2
+#define R_RISCV_RELATIVE 3
+#define R_RISCV_COPY 4
+#define R_RISCV_JUMP_SLOT 5
+#define R_RISCV_TLS_DTPMOD32 6
+#define R_RISCV_TLS_DTPMOD64 7
+#define R_RISCV_TLS_DTPREL32 8
+#define R_RISCV_TLS_DTPREL64 9
+#define R_RISCV_TLS_TPREL32 10
+#define R_RISCV_TLS_TPREL64 11
+#define R_RISCV_BRANCH 16
+#define R_RISCV_JAL 17
+#define R_RISCV_CALL 18
+#define R_RISCV_CALL_PLT 19
+#define R_RISCV_GOT_HI20 20
+#define R_RISCV_TLS_GOT_HI20 21
+#define R_RISCV_TLS_GD_HI20 22
+#define R_RISCV_PCREL_HI20 23
+#define R_RISCV_PCREL_LO12_I 24
+#define R_RISCV_PCREL_LO12_S 25
+#define R_RISCV_HI20 26
+#define R_RISCV_LO12_I 27
+#define R_RISCV_LO12_S 28
+#define R_RISCV_TPREL_HI20 29
+#define R_RISCV_TPREL_LO12_I 30
+#define R_RISCV_TPREL_LO12_S 31
+#define R_RISCV_TPREL_ADD 32
+#define R_RISCV_ADD8 33
+#define R_RISCV_ADD16 34
+#define R_RISCV_ADD32 35
+#define R_RISCV_ADD64 36
+#define R_RISCV_SUB8 37
+#define R_RISCV_SUB16 38
+#define R_RISCV_SUB32 39
+#define R_RISCV_SUB64 40
+#define R_RISCV_GNU_VTINHERIT 41
+#define R_RISCV_GNU_VTENTRY 42
+#define R_RISCV_ALIGN 43
+#define R_RISCV_RVC_BRANCH 44
+#define R_RISCV_RVC_JUMP 45
+#define R_RISCV_RVC_LUI 46
+#define R_RISCV_GPREL_I 47
+#define R_RISCV_GPREL_S 48
+#define R_RISCV_TPREL_I 49
+#define R_RISCV_TPREL_S 50
+#define R_RISCV_RELAX 51
+#define R_RISCV_SUB6 52
+#define R_RISCV_SET6 53
+#define R_RISCV_SET8 54
+#define R_RISCV_SET16 55
+#define R_RISCV_SET32 56
+#define R_RISCV_32_PCREL 57
+
+#define R_RISCV_NUM 58
+
+/* BPF specific declarations. */
+
+#define R_BPF_NONE 0 /* No reloc */
+#define R_BPF_64_64 1
+#define R_BPF_64_32 10
+
+/* Imagination Meta specific relocations. */
+
+#define R_METAG_HIADDR16 0
+#define R_METAG_LOADDR16 1
+#define R_METAG_ADDR32 2 /* 32bit absolute address */
+#define R_METAG_NONE 3 /* No reloc */
+#define R_METAG_RELBRANCH 4
+#define R_METAG_GETSETOFF 5
+
+/* Backward compatability */
+#define R_METAG_REG32OP1 6
+#define R_METAG_REG32OP2 7
+#define R_METAG_REG32OP3 8
+#define R_METAG_REG16OP1 9
+#define R_METAG_REG16OP2 10
+#define R_METAG_REG16OP3 11
+#define R_METAG_REG32OP4 12
+
+#define R_METAG_HIOG 13
+#define R_METAG_LOOG 14
+
+#define R_METAG_REL8 15
+#define R_METAG_REL16 16
+
+/* GNU */
+#define R_METAG_GNU_VTINHERIT 30
+#define R_METAG_GNU_VTENTRY 31
+
+/* PIC relocations */
+#define R_METAG_HI16_GOTOFF 32
+#define R_METAG_LO16_GOTOFF 33
+#define R_METAG_GETSET_GOTOFF 34
+#define R_METAG_GETSET_GOT 35
+#define R_METAG_HI16_GOTPC 36
+#define R_METAG_LO16_GOTPC 37
+#define R_METAG_HI16_PLT 38
+#define R_METAG_LO16_PLT 39
+#define R_METAG_RELBRANCH_PLT 40
+#define R_METAG_GOTOFF 41
+#define R_METAG_PLT 42
+#define R_METAG_COPY 43
+#define R_METAG_JMP_SLOT 44
+#define R_METAG_RELATIVE 45
+#define R_METAG_GLOB_DAT 46
+
+/* TLS relocations */
+#define R_METAG_TLS_GD 47
+#define R_METAG_TLS_LDM 48
+#define R_METAG_TLS_LDO_HI16 49
+#define R_METAG_TLS_LDO_LO16 50
+#define R_METAG_TLS_LDO 51
+#define R_METAG_TLS_IE 52
+#define R_METAG_TLS_IENONPIC 53
+#define R_METAG_TLS_IENONPIC_HI16 54
+#define R_METAG_TLS_IENONPIC_LO16 55
+#define R_METAG_TLS_TPOFF 56
+#define R_METAG_TLS_DTPMOD 57
+#define R_METAG_TLS_DTPOFF 58
+#define R_METAG_TLS_LE 59
+#define R_METAG_TLS_LE_HI16 60
+#define R_METAG_TLS_LE_LO16 61
+
+/* NDS32 relocations. */
+#define R_NDS32_NONE 0
+#define R_NDS32_32_RELA 20
+#define R_NDS32_COPY 39
+#define R_NDS32_GLOB_DAT 40
+#define R_NDS32_JMP_SLOT 41
+#define R_NDS32_RELATIVE 42
+#define R_NDS32_TLS_TPOFF 102
+#define R_NDS32_TLS_DESC 119
__END_DECLS
diff --git a/elf/enbl-secure.c b/elf/enbl-secure.c
index 5ac4e5ac91..f03750cbdd 100644
--- a/elf/enbl-secure.c
+++ b/elf/enbl-secure.c
@@ -1,5 +1,5 @@
/* Define and initialize the `__libc_enable_secure' flag. Generic version.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
index 4cf18a46cc..4b1ea7c407 100644
--- a/elf/get-dynamic-info.h
+++ b/elf/get-dynamic-info.h
@@ -1,5 +1,5 @@
/* Read the dynamic section at DYN and fill in INFO with indices DT_*.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2018 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
@@ -16,8 +16,11 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+/* This file is included multiple times and therefore lacks a header
+ file inclusion guard. */
+
#include <assert.h>
-#include <libc-internal.h>
+#include <libc-diag.h>
#ifndef RESOLVE_MAP
static
@@ -35,7 +38,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
typedef Elf64_Xword d_tag_utype;
#endif
-#ifndef RTLD_BOOTSTRAP
+#if !defined RTLD_BOOTSTRAP && !defined STATIC_PIE_BOOTSTRAP
if (dyn == NULL)
return;
#endif
@@ -107,8 +110,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
# endif
ADJUST_DYN_INFO (DT_JMPREL);
ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
- ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
- + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
+ ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH));
# undef ADJUST_DYN_INFO
assert (cnt <= DL_RO_DYN_TEMP_CNT);
}
@@ -136,9 +138,11 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
/* Only the bind now flags are allowed. */
assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL
|| (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0);
+ /* Flags must not be set for ld.so. */
assert (info[DT_FLAGS] == NULL
|| (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0);
- /* Flags must not be set for ld.so. */
+#endif
+#if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP
assert (info[DT_RUNPATH] == NULL);
assert (info[DT_RPATH] == NULL);
#else
diff --git a/elf/ifuncdep2.c b/elf/ifuncdep2.c
index 6e66d318a6..d87d61d5be 100644
--- a/elf/ifuncdep2.c
+++ b/elf/ifuncdep2.c
@@ -32,6 +32,7 @@ void * foo1_ifunc (void) __asm__ ("foo1");
__asm__(".type foo1, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo1_ifunc (void)
{
return ifunc_sel (one, minus_one, zero);
@@ -41,6 +42,7 @@ void * foo2_ifunc (void) __asm__ ("foo2");
__asm__(".type foo2, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo2_ifunc (void)
{
return ifunc_sel (minus_one, one, zero);
@@ -50,6 +52,7 @@ void * foo3_ifunc (void) __asm__ ("foo3");
__asm__(".type foo3, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo3_ifunc (void)
{
return ifunc_sel (one, zero, minus_one);
diff --git a/elf/ifuncmain6pie.c b/elf/ifuncmain6pie.c
index 8478d4c408..04faeb86ef 100644
--- a/elf/ifuncmain6pie.c
+++ b/elf/ifuncmain6pie.c
@@ -21,6 +21,7 @@ void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo_ifunc (void)
{
return ifunc_one (one);
diff --git a/elf/ifuncmain7.c b/elf/ifuncmain7.c
index 617a596d5e..1e8f7ea38e 100644
--- a/elf/ifuncmain7.c
+++ b/elf/ifuncmain7.c
@@ -20,6 +20,7 @@ __asm__(".type foo, %gnu_indirect_function");
static void *
__attribute__ ((used))
+inhibit_stack_protector
foo_ifunc (void)
{
return ifunc_one (one);
diff --git a/elf/ifuncmod1.c b/elf/ifuncmod1.c
index 0b6138056d..f0bf5fb45f 100644
--- a/elf/ifuncmod1.c
+++ b/elf/ifuncmod1.c
@@ -36,6 +36,7 @@ void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo_ifunc (void)
{
return ifunc_sel (one, minus_one, zero);
@@ -45,6 +46,7 @@ void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
__asm__(".type foo_hidden, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo_hidden_ifunc (void)
{
return ifunc_sel (minus_one, one, zero);
@@ -54,6 +56,7 @@ void * foo_protected_ifunc (void) __asm__ ("foo_protected");
__asm__(".type foo_protected, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo_protected_ifunc (void)
{
return ifunc_sel (one, zero, minus_one);
diff --git a/elf/ifuncmod5.c b/elf/ifuncmod5.c
index 0e65a63691..5a957800e8 100644
--- a/elf/ifuncmod5.c
+++ b/elf/ifuncmod5.c
@@ -31,6 +31,7 @@ void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo_ifunc (void)
{
return ifunc_sel (one, minus_one, zero);
@@ -40,6 +41,7 @@ void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
__asm__(".type foo_hidden, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo_hidden_ifunc (void)
{
return ifunc_sel (minus_one, one, zero);
@@ -49,6 +51,7 @@ void * foo_protected_ifunc (void) __asm__ ("foo_protected");
__asm__(".type foo_protected, %gnu_indirect_function");
void *
+inhibit_stack_protector
foo_protected_ifunc (void)
{
return ifunc_sel (one, zero, minus_one);
diff --git a/elf/interp.c b/elf/interp.c
index 9448802a8b..9cd50c7291 100644
--- a/elf/interp.c
+++ b/elf/interp.c
@@ -1,5 +1,5 @@
/* interp - add information about dynamic loader to shared library objects.
- Copyright (C) 1996-2016 Free Software Foundation, Inc.
+ Copyright (C) 1996-2018 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
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 9c6f2ba791..fbdd814edf 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999.
@@ -100,7 +100,8 @@ int opt_format = 1;
/* Build cache. */
static int opt_build_cache = 1;
-/* Generate links. */
+/* Enable symbolic link processing. If set, create or update symbolic
+ links, and remove stale symbolic links. */
static int opt_link = 1;
/* Only process directories specified on the command line. */
@@ -141,7 +142,7 @@ static const struct argp_option options[] =
{ "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
{ "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
{ NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
- { NULL, 'X', NULL, 0, N_("Don't generate links"), 0},
+ { 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"), 0},
@@ -324,7 +325,7 @@ print_version (FILE *stream, struct argp_state *state)
Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2016");
+"), "2018");
fprintf (stream, gettext ("Written by %s.\n"),
"Andreas Jaeger");
}
@@ -709,25 +710,20 @@ search_dir (const struct dir_entry *entry)
while ((direntry = readdir64 (dir)) != NULL)
{
int flag;
-#ifdef _DIRENT_HAVE_D_TYPE
/* We only look at links and regular files. */
if (direntry->d_type != DT_UNKNOWN
&& direntry->d_type != DT_LNK
&& direntry->d_type != DT_REG
&& direntry->d_type != DT_DIR)
continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
/* Does this file look like a shared library or is it a hwcap
subdirectory? The dynamic linker is also considered as
shared library. */
if (((strncmp (direntry->d_name, "lib", 3) != 0
&& strncmp (direntry->d_name, "ld-", 3) != 0)
|| strstr (direntry->d_name, ".so") == NULL)
- && (
-#ifdef _DIRENT_HAVE_D_TYPE
- direntry->d_type == DT_REG ||
-#endif
- !is_hwcap_platform (direntry->d_name)))
+ && (direntry->d_type == DT_REG
+ || !is_hwcap_platform (direntry->d_name)))
continue;
size_t len = strlen (direntry->d_name);
@@ -764,12 +760,10 @@ search_dir (const struct dir_entry *entry)
}
struct stat64 lstat_buf;
-#ifdef _DIRENT_HAVE_D_TYPE
/* We optimize and try to do the lstat call only if needed. */
if (direntry->d_type != DT_UNKNOWN)
lstat_buf.st_mode = DTTOIF (direntry->d_type);
else
-#endif
if (__glibc_unlikely (lstat64 (real_file_name, &lstat_buf)))
{
error (0, errno, _("Cannot lstat %s"), file_name);
@@ -800,7 +794,7 @@ search_dir (const struct dir_entry *entry)
error (0, errno, _("Cannot stat %s"), file_name);
/* Remove stale symlinks. */
- if (strstr (direntry->d_name, ".so."))
+ if (opt_link && strstr (direntry->d_name, ".so."))
unlink (real_file_name);
continue;
}
@@ -824,9 +818,6 @@ search_dir (const struct dir_entry *entry)
new_entry->path = xstrdup (file_name);
new_entry->flag = entry->flag;
new_entry->next = NULL;
-#ifdef _DIRENT_HAVE_D_TYPE
- /* We have filled in lstat only #ifndef
- _DIRENT_HAVE_D_TYPE. Fill it in if needed. */
if (!is_link
&& direntry->d_type != DT_UNKNOWN
&& __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
@@ -836,7 +827,6 @@ search_dir (const struct dir_entry *entry)
free (new_entry);
continue;
}
-#endif
new_entry->ino = lstat_buf.st_ino;
new_entry->dev = lstat_buf.st_dev;
add_single_dir (new_entry, 0);
@@ -859,7 +849,6 @@ search_dir (const struct dir_entry *entry)
else
real_name = real_file_name;
-#ifdef _DIRENT_HAVE_D_TYPE
/* Call lstat64 if not done yet. */
if (!is_link
&& direntry->d_type != DT_UNKNOWN
@@ -868,7 +857,6 @@ search_dir (const struct dir_entry *entry)
error (0, errno, _("Cannot lstat %s"), file_name);
continue;
}
-#endif
/* First search whether the auxiliary cache contains this
library already and it's not changed. */
@@ -1271,6 +1259,10 @@ main (int argc, char **argv)
/* Set locale via LC_ALL. */
setlocale (LC_ALL, "");
+ /* But keep the C collation. That way `include' directives using
+ globbing patterns are processed in a locale-independent order. */
+ setlocale (LC_COLLATE, "C");
+
/* Set the text message domain. */
textdomain (_libc_intl_domainname);
diff --git a/elf/ldd.bash.in b/elf/ldd.bash.in
index 80a7cd59cd..14f9787d1a 100644
--- a/elf/ldd.bash.in
+++ b/elf/ldd.bash.in
@@ -1,5 +1,5 @@
#! @BASH@
-# Copyright (C) 1996-2016 Free Software Foundation, Inc.
+# Copyright (C) 1996-2018 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
@@ -38,7 +38,7 @@ while test $# -gt 0; do
printf $"Copyright (C) %s Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-" "2016"
+" "2018"
printf $"Written by %s and %s.
" "Roland McGrath" "Ulrich Drepper"
exit 0
@@ -164,18 +164,6 @@ warning: you do not have execution permission for" "\`$file'" >&2
fi
done
case $ret in
- 0)
- # If the program exits with exit code 5, it means the process has been
- # invoked with __libc_enable_secure. Fall back to running it through
- # the dynamic linker.
- try_trace "$file"
- rc=$?
- if [ $rc = 5 ]; then
- try_trace "$RTLD" "$file"
- rc=$?
- fi
- [ $rc = 0 ] || result=1
- ;;
1)
# This can be a non-ELF binary or no binary at all.
nonelf "$file" || {
@@ -183,7 +171,7 @@ warning: you do not have execution permission for" "\`$file'" >&2
result=1
}
;;
- 2)
+ 0|2)
try_trace "$RTLD" "$file" || result=1
;;
*)
diff --git a/elf/link.h b/elf/link.h
index f448141bab..c67a50dd8e 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -1,6 +1,6 @@
/* Data structure for communication from the run-time dynamic linker for
loaded ELF shared objects.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
diff --git a/elf/loadtest.c b/elf/loadtest.c
index 727469b496..b5eab5e93c 100644
--- a/elf/loadtest.c
+++ b/elf/loadtest.c
@@ -72,12 +72,16 @@ static const struct
#define MAPS ((struct link_map *) _r_debug.r_map)
-#define OUT \
- for (map = MAPS; map != NULL; map = map->l_next) \
- if (map->l_type == lt_loaded) \
- printf ("name = \"%s\", direct_opencount = %d\n", \
- map->l_name, (int) map->l_direct_opencount); \
- fflush (stdout)
+#define OUT \
+ do \
+ { \
+ for (map = MAPS; map != NULL; map = map->l_next) \
+ if (map->l_type == lt_loaded) \
+ printf ("name = \"%s\", direct_opencount = %d\n", \
+ map->l_name, (int) map->l_direct_opencount); \
+ fflush (stdout); \
+ } \
+ while (0)
int
diff --git a/elf/next.c b/elf/next.c
index 6a3670c214..a0d532b8c3 100644
--- a/elf/next.c
+++ b/elf/next.c
@@ -40,5 +40,4 @@ do_test (void)
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/nodelete.c b/elf/nodelete.c
index 78364a278a..c8d71152f2 100644
--- a/elf/nodelete.c
+++ b/elf/nodelete.c
@@ -18,7 +18,6 @@ handler (int sig)
}
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -208,4 +207,4 @@ do_test (void)
return result;
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/order2.c b/elf/order2.c
index 3dbfdd153e..bcf266d5b1 100644
--- a/elf/order2.c
+++ b/elf/order2.c
@@ -34,8 +34,7 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
static void
__attribute__ ((destructor))
diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c
index 76f7ab43fd..2823dea662 100644
--- a/elf/pldd-xx.c
+++ b/elf/pldd-xx.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2011-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
diff --git a/elf/pldd.c b/elf/pldd.c
index 1bf74442ba..b8106fdc33 100644
--- a/elf/pldd.c
+++ b/elf/pldd.c
@@ -1,5 +1,5 @@
/* List dynamic shared objects linked into given process.
- Copyright (C) 2011-2016 Free Software Foundation, Inc.
+ Copyright (C) 2011-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
@@ -269,7 +269,7 @@ print_version (FILE *stream, struct argp_state *state)
Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2016");
+"), "2018");
fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
}
diff --git a/elf/readelflib.c b/elf/readelflib.c
index 89b5292a2a..5a1e2dc2df 100644
--- a/elf/readelflib.c
+++ b/elf/readelflib.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
Jakub Jelinek <jakub@redhat.com>, 1999.
@@ -131,15 +131,26 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents
+ segment->p_offset);
ElfW(Addr) size = segment->p_filesz;
+ /* NB: Some PT_NOTE segment may have alignment value of 0
+ or 1. gABI specifies that PT_NOTE segments should be
+ aligned to 4 bytes in 32-bit objects and to 8 bytes in
+ 64-bit objects. As a Linux extension, we also support
+ 4 byte alignment in 64-bit objects. If p_align is less
+ than 4, we treate alignment as 4 bytes since some note
+ segments have 0 or 1 byte alignment. */
+ ElfW(Addr) align = segment->p_align;
+ if (align < 4)
+ align = 4;
+ else if (align != 4 && align != 8)
+ continue;
while (abi_note [0] != 4 || abi_note [1] != 16
|| abi_note [2] != 1
|| memcmp (abi_note + 3, "GNU", 4) != 0)
{
-#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
- ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
- + ROUND (abi_note[0])
- + ROUND (abi_note[1]);
+ ElfW(Addr) note_size
+ = ELF_NOTE_NEXT_OFFSET (abi_note[0], abi_note[1],
+ align);
if (size - 32 < note_size || note_size == 0)
{
diff --git a/elf/readlib.c b/elf/readlib.c
index 8a66ffe9d4..573c01476c 100644
--- a/elf/readlib.c
+++ b/elf/readlib.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
Jakub Jelinek <jakub@redhat.com>, 1999.
diff --git a/elf/rtld-Rules b/elf/rtld-Rules
index 94ca39bff2..6fd9494ba3 100644
--- a/elf/rtld-Rules
+++ b/elf/rtld-Rules
@@ -1,6 +1,6 @@
# Subroutine makefile for compiling libc modules linked into dynamic linker.
-# Copyright (C) 2002-2016 Free Software Foundation, Inc.
+# Copyright (C) 2002-2018 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
@@ -29,7 +29,7 @@ rtld-all:
# When run from the elf/Makefile to build rtld-libc.a, $(subdir) is elf.
ifneq ($(subdir),elf)
ifndef rtld-modules
-error rtld-modules not set
+$(error rtld-modules not set)
endif
endif
@@ -37,7 +37,7 @@ ifndef rtld-modules
# Running to build rtld-libc.a, driving runs of $(rtld-subdir-make), below.
ifndef rtld-subdirs
-error This makefile is a subroutine of elf/Makefile not to be used directly
+$(error This makefile is a subroutine of elf/Makefile not to be used directly)
endif
include ../Makeconfig
@@ -90,7 +90,7 @@ else
rtld-compile-command.S = $(compile-command.S) $(rtld-CPPFLAGS)
rtld-compile-command.s = $(compile-command.s) $(rtld-CPPFLAGS)
-rtld-compile-command.c = $(compile-command.c) $(rtld-CPPFLAGS)
+rtld-compile-command.c = $(compile-command.c) $(rtld-CPPFLAGS) $(rtld-CFLAGS)
# These are the basic compilation rules corresponding to the Makerules ones.
# The sysd-rules generated makefile already defines pattern rules for rtld-%
@@ -142,6 +142,8 @@ endif
# Set libof-* for each routine.
cpp-srcs-left := $(rtld-modules:%.os=%)
lib := rtld
-include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left))
+include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
+
+rtld-CFLAGS += $(no-stack-protector)
endif
diff --git a/elf/rtld.c b/elf/rtld.c
index 647661ca45..1b0c74739f 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1,5 +1,5 @@
/* Run time dynamic linker.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -38,9 +38,11 @@
#include <dl-cache.h>
#include <dl-osinfo.h>
#include <dl-procinfo.h>
+#include <dl-prop.h>
#include <tls.h>
#include <stap-probe.h>
#include <stackinfo.h>
+#include <not-cancel.h>
#include <assert.h>
@@ -99,14 +101,121 @@ uintptr_t __pointer_chk_guard_local
strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
#endif
+/* Length limits for names and paths, to protect the dynamic linker,
+ particularly when __libc_enable_secure is active. */
+#ifdef NAME_MAX
+# define SECURE_NAME_LIMIT NAME_MAX
+#else
+# define SECURE_NAME_LIMIT 255
+#endif
+#ifdef PATH_MAX
+# define SECURE_PATH_LIMIT PATH_MAX
+#else
+# define SECURE_PATH_LIMIT 1024
+#endif
+
+/* Check that AT_SECURE=0, or that the passed name does not contain
+ directories and is not overly long. Reject empty names
+ unconditionally. */
+static bool
+dso_name_valid_for_suid (const char *p)
+{
+ if (__glibc_unlikely (__libc_enable_secure))
+ {
+ /* Ignore pathnames with directories for AT_SECURE=1
+ programs, and also skip overlong names. */
+ size_t len = strlen (p);
+ if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL)
+ return false;
+ }
+ return *p != '\0';
+}
-/* List of auditing DSOs. */
+/* LD_AUDIT variable contents. Must be processed before the
+ audit_list below. */
+const char *audit_list_string;
+
+/* Cyclic list of auditing DSOs. audit_list->next is the first
+ element. */
static struct audit_list
{
const char *name;
struct audit_list *next;
} *audit_list;
+/* Iterator for audit_list_string followed by audit_list. */
+struct audit_list_iter
+{
+ /* Tail of audit_list_string still needing processing, or NULL. */
+ const char *audit_list_tail;
+
+ /* The list element returned in the previous iteration. NULL before
+ the first element. */
+ struct audit_list *previous;
+
+ /* Scratch buffer for returning a name which is part of
+ audit_list_string. */
+ char fname[SECURE_NAME_LIMIT];
+};
+
+/* Initialize an audit list iterator. */
+static void
+audit_list_iter_init (struct audit_list_iter *iter)
+{
+ iter->audit_list_tail = audit_list_string;
+ iter->previous = NULL;
+}
+
+/* Iterate through both audit_list_string and audit_list. */
+static const char *
+audit_list_iter_next (struct audit_list_iter *iter)
+{
+ if (iter->audit_list_tail != NULL)
+ {
+ /* First iterate over audit_list_string. */
+ while (*iter->audit_list_tail != '\0')
+ {
+ /* Split audit list at colon. */
+ size_t len = strcspn (iter->audit_list_tail, ":");
+ if (len > 0 && len < sizeof (iter->fname))
+ {
+ memcpy (iter->fname, iter->audit_list_tail, len);
+ iter->fname[len] = '\0';
+ }
+ else
+ /* Do not return this name to the caller. */
+ iter->fname[0] = '\0';
+
+ /* Skip over the substring and the following delimiter. */
+ iter->audit_list_tail += len;
+ if (*iter->audit_list_tail == ':')
+ ++iter->audit_list_tail;
+
+ /* If the name is valid, return it. */
+ if (dso_name_valid_for_suid (iter->fname))
+ return iter->fname;
+ /* Otherwise, wrap around and try the next name. */
+ }
+ /* Fall through to the procesing of audit_list. */
+ }
+
+ if (iter->previous == NULL)
+ {
+ if (audit_list == NULL)
+ /* No pre-parsed audit list. */
+ return NULL;
+ /* Start of audit list. The first list element is at
+ audit_list->next (cyclic list). */
+ iter->previous = audit_list->next;
+ return iter->previous->name;
+ }
+ if (iter->previous == audit_list)
+ /* Cyclic list wrap-around. */
+ return NULL;
+ iter->previous = iter->previous->next;
+ return iter->previous->name;
+}
+
#ifndef HAVE_INLINED_SYSCALLS
/* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This
@@ -159,7 +268,9 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
._dl_debug_fd = STDERR_FILENO,
._dl_use_load_bias = -2,
._dl_correct_cache_id = _DL_CACHE_DEFAULT_ID,
+#if !HAVE_TUNABLES
._dl_hwcap_mask = HWCAP_IMPORTANT,
+#endif
._dl_lazy = 1,
._dl_fpu_control = _FPU_DEFAULT,
._dl_pagesize = EXEC_PAGESIZE,
@@ -167,11 +278,8 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
/* Function pointers. */
._dl_debug_printf = _dl_debug_printf,
- ._dl_catch_error = _dl_catch_error,
- ._dl_signal_error = _dl_signal_error,
._dl_mcount = _dl_mcount,
._dl_lookup_symbol_x = _dl_lookup_symbol_x,
- ._dl_check_caller = _dl_check_caller,
._dl_open = _dl_open,
._dl_close = _dl_close,
._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
@@ -332,7 +440,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
return start_addr;
}
-static ElfW(Addr) __attribute_used__ internal_function
+static ElfW(Addr) __attribute_used__
_dl_start (void *arg)
{
#ifdef DONT_USE_BOOTSTRAP_MAP
@@ -347,7 +455,8 @@ _dl_start (void *arg)
Since ld.so must not have any undefined symbols the result
is trivial: always the map of ld.so itself. */
#define RTLD_BOOTSTRAP
-#define RESOLVE_MAP(sym, version, flags) (&bootstrap_map)
+#define BOOTSTRAP_MAP (&bootstrap_map)
+#define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
#include "dynamic-link.h"
if (HP_TIMING_INLINE && HP_SMALL_TIMING_AVAIL)
@@ -622,7 +731,7 @@ init_tls (void)
void *tcbp = _dl_allocate_tls_storage ();
if (tcbp == NULL)
_dl_fatal_printf ("\
-cannot allocate TLS data structures for initial thread");
+cannot allocate TLS data structures for initial thread\n");
/* Store for detection of the special case by __tls_get_addr
so it knows not to pass this dtv to the normal realloc. */
@@ -637,18 +746,6 @@ cannot allocate TLS data structures for initial thread");
return tcbp;
}
-#ifdef _LIBC_REENTRANT
-/* _dl_error_catch_tsd points to this for the single-threaded case.
- It's reset by the thread library for multithreaded programs. */
-void ** __attribute__ ((const))
-_dl_initial_error_catch_tsd (void)
-{
- static void *data;
- return &data;
-}
-#endif
-
-
static unsigned int
do_preload (const char *fname, struct link_map *main_map, const char *where)
{
@@ -730,6 +827,42 @@ static const char *preloadlist attribute_relro;
/* Nonzero if information about versions has to be printed. */
static int version_info attribute_relro;
+/* The LD_PRELOAD environment variable gives list of libraries
+ separated by white space or colons that are loaded before the
+ executable's dependencies and prepended to the global scope list.
+ (If the binary is running setuid all elements containing a '/' are
+ ignored since it is insecure.) Return the number of preloads
+ performed. */
+unsigned int
+handle_ld_preload (const char *preloadlist, struct link_map *main_map)
+{
+ unsigned int npreloads = 0;
+ const char *p = preloadlist;
+ char fname[SECURE_PATH_LIMIT];
+
+ while (*p != '\0')
+ {
+ /* Split preload list at space/colon. */
+ size_t len = strcspn (p, " :");
+ if (len > 0 && len < sizeof (fname))
+ {
+ memcpy (fname, p, len);
+ fname[len] = '\0';
+ }
+ else
+ fname[0] = '\0';
+
+ /* Skip over the substring and the following delimiter. */
+ p += len;
+ if (*p != '\0')
+ ++p;
+
+ if (dso_name_valid_for_suid (fname))
+ npreloads += do_preload (fname, main_map, "LD_PRELOAD");
+ }
+ return npreloads;
+}
+
static void
dl_main (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
@@ -752,11 +885,6 @@ dl_main (const ElfW(Phdr) *phdr,
#endif
void *tcbp = NULL;
-#ifdef _LIBC_REENTRANT
- /* Explicit initialization since the reloc would just be more work. */
- GL(dl_error_catch_tsd) = &_dl_initial_error_catch_tsd;
-#endif
-
GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
#if defined SHARED && defined _LIBC_REENTRANT \
@@ -1114,6 +1242,12 @@ of this helper program; chances are you did not intend to run this program.\n\
main_map->l_relro_addr = ph->p_vaddr;
main_map->l_relro_size = ph->p_memsz;
break;
+
+ case PT_NOTE:
+ if (_rtld_process_pt_note (main_map, ph))
+ _dl_error_printf ("\
+ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
+ break;
}
/* Adjust the address of the TLS initialization image in case
@@ -1257,11 +1391,13 @@ of this helper program; chances are you did not intend to run this program.\n\
GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
/* If we have auditing DSOs to load, do it now. */
- if (__glibc_unlikely (audit_list != NULL))
+ bool need_security_init = true;
+ if (__glibc_unlikely (audit_list != NULL)
+ || __glibc_unlikely (audit_list_string != NULL))
{
- /* Iterate over all entries in the list. The order is important. */
struct audit_ifaces *last_audit = NULL;
- struct audit_list *al = audit_list->next;
+ struct audit_list_iter al_iter;
+ audit_list_iter_init (&al_iter);
/* Since we start using the auditing DSOs right away we need to
initialize the data structures now. */
@@ -1272,9 +1408,14 @@ of this helper program; chances are you did not intend to run this program.\n\
use different values (especially the pointer guard) and will
fail later on. */
security_init ();
+ need_security_init = false;
- do
+ while (true)
{
+ const char *name = audit_list_iter_next (&al_iter);
+ if (name == NULL)
+ break;
+
int tls_idx = GL(dl_tls_max_dtv_idx);
/* Now it is time to determine the layout of the static TLS
@@ -1283,7 +1424,7 @@ of this helper program; chances are you did not intend to run this program.\n\
no DF_STATIC_TLS bit is set. The reason is that we know
glibc will use the static model. */
struct dlmopen_args dlmargs;
- dlmargs.fname = al->name;
+ dlmargs.fname = name;
dlmargs.map = NULL;
const char *objname;
@@ -1296,7 +1437,7 @@ of this helper program; chances are you did not intend to run this program.\n\
not_loaded:
_dl_error_printf ("\
ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
- al->name, err_str);
+ name, err_str);
if (malloced)
free ((char *) err_str);
}
@@ -1400,10 +1541,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
goto not_loaded;
}
}
-
- al = al->next;
}
- while (al != audit_list->next);
/* If we have any auditing modules, announce that we already
have two objects loaded. */
@@ -1481,23 +1619,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
if (__glibc_unlikely (preloadlist != NULL))
{
- /* The LD_PRELOAD environment variable gives list of libraries
- separated by white space or colons that are loaded before the
- executable's dependencies and prepended to the global scope
- list. If the binary is running setuid all elements
- containing a '/' are ignored since it is insecure. */
- char *list = strdupa (preloadlist);
- char *p;
-
HP_TIMING_NOW (start);
-
- /* Prevent optimizing strsep. Speed is not important here. */
- while ((p = (strsep) (&list, " :")) != NULL)
- if (p[0] != '\0'
- && (__builtin_expect (! __libc_enable_secure, 1)
- || strchr (p, '/') == NULL))
- npreloads += do_preload (p, main_map, "LD_PRELOAD");
-
+ npreloads += handle_ld_preload (preloadlist, main_map);
HP_TIMING_NOW (stop);
HP_TIMING_DIFF (diff, start, stop);
HP_TIMING_ACCUM_NT (load_time, diff);
@@ -1682,7 +1805,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
if (tcbp == NULL)
tcbp = init_tls ();
- if (__glibc_likely (audit_list == NULL))
+ if (__glibc_likely (need_security_init))
/* Initialize security features. But only if we have not done it
earlier. */
security_init ();
@@ -1801,7 +1924,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
NULL, ELF_RTYPE_CLASS_PLT,
DL_LOOKUP_ADD_DEPENDENCY, NULL);
- loadbase = LOOKUP_VALUE_ADDRESS (result);
+ loadbase = LOOKUP_VALUE_ADDRESS (result, false);
_dl_printf ("%s found at 0x%0*Zd in object at 0x%0*Zd\n",
_dl_argv[i],
@@ -1980,7 +2103,9 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist;
/* Remember the last search directory added at startup, now that
- malloc will no longer be the one from dl-minimal.c. */
+ malloc will no longer be the one from dl-minimal.c. As a side
+ effect, this marks ld.so as initialized, so that the rtld_active
+ function returns true from now on. */
GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
/* Print scope information. */
@@ -1992,6 +2117,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
_dl_show_scope (l, 0);
}
+ _rtld_main_check (main_map, _dl_argv[0]);
+
if (prelinked)
{
if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
@@ -2093,7 +2220,9 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
/* Now that we have completed relocation, the initializer data
for the TLS blocks has its final values and we can copy them
- into the main thread's TLS area, which we allocated above. */
+ into the main thread's TLS area, which we allocated above.
+ Note: thread-local variables must only be accessed after completing
+ the next step. */
_dl_allocate_tls_init (tcbp);
/* And finally install it for the main thread. */
@@ -2313,9 +2442,7 @@ process_dl_audit (char *str)
char *p;
while ((p = (strsep) (&str, ":")) != NULL)
- if (p[0] != '\0'
- && (__builtin_expect (! __libc_enable_secure, 1)
- || strchr (p, '/') == NULL))
+ if (dso_name_valid_for_suid (p))
{
/* This is using the local malloc, not the system malloc. The
memory can never be freed. */
@@ -2379,7 +2506,7 @@ process_envvars (enum mode *modep)
break;
}
if (memcmp (envline, "AUDIT", 5) == 0)
- process_dl_audit (&envline[6]);
+ audit_list_string = &envline[6];
break;
case 7:
@@ -2421,12 +2548,14 @@ process_envvars (enum mode *modep)
_dl_show_auxv ();
break;
+#if !HAVE_TUNABLES
case 10:
/* Mask for the important hardware capabilities. */
- if (memcmp (envline, "HWCAP_MASK", 10) == 0)
- GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL,
- 0, 0);
+ if (!__libc_enable_secure
+ && memcmp (envline, "HWCAP_MASK", 10) == 0)
+ GLRO(dl_hwcap_mask) = _dl_strtoul (&envline[11], NULL);
break;
+#endif
case 11:
/* Path where the binary is found. */
@@ -2437,7 +2566,8 @@ process_envvars (enum mode *modep)
case 12:
/* The library search path. */
- if (memcmp (envline, "LIBRARY_PATH", 12) == 0)
+ if (!__libc_enable_secure
+ && memcmp (envline, "LIBRARY_PATH", 12) == 0)
{
library_path = &envline[13];
break;
@@ -2529,7 +2659,9 @@ process_envvars (enum mode *modep)
if (__access ("/etc/suid-debug", F_OK) != 0)
{
+#if !HAVE_TUNABLES
unsetenv ("MALLOC_CHECK_");
+#endif
GLRO(dl_debug_mask) = 0;
}
@@ -2541,11 +2673,7 @@ process_envvars (enum mode *modep)
messages to this file. */
else if (any_debug && debug_output != NULL)
{
-#ifdef O_NOFOLLOW
const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW;
-#else
- const int flags = O_WRONLY | O_APPEND | O_CREAT;
-#endif
size_t name_len = strlen (debug_output);
char buf[name_len + 12];
char *startp;
@@ -2555,7 +2683,7 @@ process_envvars (enum mode *modep)
*--startp = '.';
startp = memcpy (startp - name_len, debug_output, name_len);
- GLRO(dl_debug_fd) = __open (startp, flags, DEFFILEMODE);
+ GLRO(dl_debug_fd) = __open64_nocancel (startp, flags, DEFFILEMODE);
if (GLRO(dl_debug_fd) == -1)
/* We use standard output if opening the file failed. */
GLRO(dl_debug_fd) = STDOUT_FILENO;
diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h
index e6f1dd809b..34b1d5e8c3 100644
--- a/elf/setup-vdso.h
+++ b/elf/setup-vdso.h
@@ -1,5 +1,5 @@
/* Set up the data structures for the system-supplied DSO.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2018 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
diff --git a/elf/sln.c b/elf/sln.c
index 9d57be2df5..3d3b7e0525 100644
--- a/elf/sln.c
+++ b/elf/sln.c
@@ -1,5 +1,5 @@
/* `sln' program to create symbolic links between files.
- Copyright (C) 1998-2016 Free Software Foundation, Inc.
+ Copyright (C) 1998-2018 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
@@ -16,10 +16,6 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
#include <error.h>
#include <errno.h>
#include <libintl.h>
@@ -37,10 +33,6 @@
#define PACKAGE _libc_intl_domainname
-#if !defined S_ISDIR && defined S_IFDIR
-#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-
static int makesymlink (const char *src, const char *dest);
static int makesymlinks (const char *file);
static void usage (void);
@@ -89,9 +81,6 @@ usage (void)
static int
makesymlinks (const char *file)
{
-#ifndef PATH_MAX
-#define PATH_MAX 4095
-#endif
char *buffer = NULL;
size_t bufferlen = 0;
int ret;
@@ -164,11 +153,11 @@ makesymlinks (const char *file)
static int
makesymlink (const char *src, const char *dest)
{
- struct stat stats;
+ struct stat64 stats;
const char *error;
/* Destination must not be a directory. */
- if (lstat (dest, &stats) == 0)
+ if (lstat64 (dest, &stats) == 0)
{
if (S_ISDIR (stats.st_mode))
{
@@ -190,11 +179,7 @@ makesymlink (const char *src, const char *dest)
return -1;
}
-#ifdef S_ISLNK
if (symlink (src, dest) == 0)
-#else
- if (link (src, dest) == 0)
-#endif
{
/* Destination must exist by now. */
if (access (dest, F_OK))
diff --git a/elf/soinit.c b/elf/soinit.c
index 71398308d2..fe9935732b 100644
--- a/elf/soinit.c
+++ b/elf/soinit.c
@@ -4,7 +4,6 @@
calling those lists of functions. */
#ifndef NO_CTORS_DTORS_SECTIONS
-# include <libc-internal.h>
# include <stdlib.h>
static void (*const __CTOR_LIST__[1]) (void)
diff --git a/elf/sotruss-lib.c b/elf/sotruss-lib.c
index 174f53f7c5..f0a7e55599 100644
--- a/elf/sotruss-lib.c
+++ b/elf/sotruss-lib.c
@@ -1,5 +1,5 @@
/* Trace calls through PLTs and show caller, callee, and parameters.
- Copyright (C) 2011-2016 Free Software Foundation, Inc.
+ Copyright (C) 2011-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
@@ -84,11 +84,11 @@ init (void)
if (out_filename != NULL && out_filename[0] != 0)
{
- size_t out_filename_len = strlen (out_filename) + 12;
+ size_t out_filename_len = strlen (out_filename) + 13;
char fullname[out_filename_len];
char *endp = stpcpy (fullname, out_filename);
if (which_process == NULL || which_process[0] == '\0')
- snprintf (endp, 12, ".%lu", (unsigned long int) pid);
+ snprintf (endp, 13, ".%ld", (long int) pid);
out_fd = open (fullname, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (out_fd != -1)
diff --git a/elf/sotruss.sh b/elf/sotruss.sh
index 07f6281e6b..0231dc9935 100755
--- a/elf/sotruss.sh
+++ b/elf/sotruss.sh
@@ -1,5 +1,5 @@
#! @BASH@
-# Copyright (C) 2011-2016 Free Software Foundation, Inc.
+# Copyright (C) 2011-2018 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
@@ -75,7 +75,7 @@ while test $# -gt 0; do
printf $"Copyright (C) %s Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-" "2016"
+" "2018"
printf $"Written by %s.\n" "Ulrich Drepper"
exit 0
;;
diff --git a/elf/sprof.c b/elf/sprof.c
index acf2c205d6..ebd39cb581 100644
--- a/elf/sprof.c
+++ b/elf/sprof.c
@@ -1,5 +1,5 @@
/* Read and display shared object profiling data.
- Copyright (C) 1997-2016 Free Software Foundation, Inc.
+ Copyright (C) 1997-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -391,7 +391,7 @@ Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"),
- "2016");
+ "2018");
fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
}
diff --git a/elf/static-stubs.c b/elf/static-stubs.c
index 7af36fc8dd..0d3ea2f971 100644
--- a/elf/static-stubs.c
+++ b/elf/static-stubs.c
@@ -1,6 +1,6 @@
/* Stub implementations of functions to link into statically linked
programs without needing libgcc_eh.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2018 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
diff --git a/elf/testobj6.c b/elf/testobj6.c
index fcba01631d..84da4c9e22 100644
--- a/elf/testobj6.c
+++ b/elf/testobj6.c
@@ -1,3 +1,5 @@
+#include <stdio.h>
+
#include "testobj.h"
int
@@ -15,5 +17,6 @@ obj6func2 (int a)
int
preload (int a)
{
+ printf ("testobj6 preload\n");
return a;
}
diff --git a/elf/tlsdeschtab.h b/elf/tlsdeschtab.h
index 38eba77472..fea9eefe72 100644
--- a/elf/tlsdeschtab.h
+++ b/elf/tlsdeschtab.h
@@ -1,5 +1,5 @@
/* Hash table for TLS descriptors.
- Copyright (C) 2005-2016 Free Software Foundation, Inc.
+ Copyright (C) 2005-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Alexandre Oliva <aoliva@redhat.com>
@@ -79,7 +79,6 @@ map_generation (struct link_map *map)
}
void *
-internal_function
_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
{
struct hashtab *ht;
@@ -138,6 +137,7 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
avoid introducing such dependencies. */
static int
+__attribute__ ((unused))
_dl_tlsdesc_resolve_early_return_p (struct tlsdesc volatile *td, void *caller)
{
if (caller != atomic_load_relaxed (&td->entry))
@@ -156,6 +156,7 @@ _dl_tlsdesc_resolve_early_return_p (struct tlsdesc volatile *td, void *caller)
}
static void
+__attribute__ ((unused))
_dl_tlsdesc_wake_up_held_fixups (void)
{
__rtld_lock_unlock_recursive (GL(dl_load_lock));
diff --git a/elf/tst-_dl_addr_inside_object.c b/elf/tst-_dl_addr_inside_object.c
new file mode 100644
index 0000000000..ee525489d2
--- /dev/null
+++ b/elf/tst-_dl_addr_inside_object.c
@@ -0,0 +1,221 @@
+/* Unit test for _dl_addr_inside_object.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <link.h>
+#include <elf.h>
+#include <libc-symbols.h>
+
+extern int _dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr);
+
+static int
+do_test (void)
+{
+ int ret, err = 0;
+ ElfW(Addr) addr;
+ struct link_map map;
+ ElfW(Phdr) header;
+ map.l_phdr = &header;
+ map.l_phnum = 1;
+ map.l_addr = 0x0;
+ /* Segment spans 0x2000 -> 0x4000. */
+ header.p_vaddr = 0x2000;
+ header.p_memsz = 0x2000;
+ header.p_type = PT_LOAD;
+ /* Address is above the segment e.g. > 0x4000. */
+ addr = 0x5000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: Above: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: Above: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: Above: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is inside the segment e.g. 0x2000 < addr < 0x4000. */
+ addr = 0x3000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("FAIL: Inside: Address is detected as outside the segment.\n");
+ err++;
+ break;
+ case 1:
+ printf ("PASS: Inside: Address is detected as inside the segment.\n");
+ break;
+ default:
+ printf ("FAIL: Inside: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is below the segment e.g. < 0x2000. */
+ addr = 0x1000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: Below: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: Below: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: Below: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is in the segment and addr == p_vaddr. */
+ addr = 0x2000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("FAIL: At p_vaddr: Address is detected as outside the segment.\n");
+ err++;
+ break;
+ case 1:
+ printf ("PASS: At p_vaddr: Address is detected as inside the segment.\n");
+ break;
+ default:
+ printf ("FAIL: At p_vaddr: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is in the segment and addr == p_vaddr + p_memsz - 1. */
+ addr = 0x2000 + 0x2000 - 0x1;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("FAIL: At p_memsz-1: Address is detected as outside the segment.\n");
+ err++;
+ break;
+ case 1:
+ printf ("PASS: At p_memsz-1: Address is detected as inside the segment.\n");
+ break;
+ default:
+ printf ("FAIL: At p_memsz-1: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is outside the segment and addr == p_vaddr + p_memsz. */
+ addr = 0x2000 + 0x2000;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: At p_memsz: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: At p_memsz: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: At p_memsz: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is outside the segment and p_vaddr at maximum address. */
+ addr = 0x0 - 0x2;
+ header.p_vaddr = 0x0 - 0x1;
+ header.p_memsz = 0x1;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: At max: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: At max: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: At max: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is outside the segment and p_vaddr at minimum address. */
+ addr = 0x1;
+ header.p_vaddr = 0x0;
+ header.p_memsz = 0x1;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: At min: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: At min: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: At min: Invalid return value.\n");
+ exit (1);
+ }
+ /* Address is always inside the segment with p_memsz at max. */
+ addr = 0x0;
+ header.p_vaddr = 0x0;
+ header.p_memsz = 0x0 - 0x1;
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("FAIL: At maxmem: Address is detected as outside the segment.\n");
+ err++;
+ break;
+ case 1:
+ printf ("PASS: At maxmem: Address is detected as inside the segment.\n");
+ break;
+ default:
+ printf ("FAIL: At maxmem: Invalid return value.\n");
+ exit (1);
+ }
+ /* Attempt to wrap addr into the segment.
+ Pick a load address in the middle of the address space.
+ Place the test address at 0x0 so it wraps to the middle again. */
+ map.l_addr = 0x0 - 0x1;
+ map.l_addr = map.l_addr / 2;
+ addr = 0;
+ /* Setup a segment covering 1/2 the address space. */
+ header.p_vaddr = 0x0;
+ header.p_memsz = 0x0 - 0x1 - map.l_addr;
+ /* No matter where you place addr everything is shifted modulo l_addr
+ and even with this underflow you're always 1 byte away from being
+ in the range. */
+ ret = _dl_addr_inside_object (&map, addr);
+ switch (ret)
+ {
+ case 0:
+ printf ("PASS: Underflow: Address is detected as outside the segment.\n");
+ break;
+ case 1:
+ printf ("FAIL: Underflow: Address is detected as inside the segment.\n");
+ err++;
+ break;
+ default:
+ printf ("FAIL: Underflow: Invalid return value.\n");
+ exit (1);
+ }
+
+ return err;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-absolute-sym-lib.c b/elf/tst-absolute-sym-lib.c
new file mode 100644
index 0000000000..912cb0048a
--- /dev/null
+++ b/elf/tst-absolute-sym-lib.c
@@ -0,0 +1,25 @@
+/* BZ #19818 absolute symbol calculation shared module.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+extern char absolute;
+
+void *
+get_absolute (void)
+{
+ return &absolute;
+}
diff --git a/elf/tst-absolute-sym-lib.lds b/elf/tst-absolute-sym-lib.lds
new file mode 100644
index 0000000000..d4a4128514
--- /dev/null
+++ b/elf/tst-absolute-sym-lib.lds
@@ -0,0 +1,19 @@
+/* BZ #19818 absolute symbol calculation linker script.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+"absolute" = 0x55aa;
diff --git a/elf/tst-absolute-sym.c b/elf/tst-absolute-sym.c
new file mode 100644
index 0000000000..111491d159
--- /dev/null
+++ b/elf/tst-absolute-sym.c
@@ -0,0 +1,38 @@
+/* BZ #19818 absolute symbol calculation main executable.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+
+void *get_absolute (void);
+
+static int
+do_test (void)
+{
+ void *ref = (void *) 0x55aa;
+ void *ptr;
+
+ ptr = get_absolute ();
+ if (ptr != ref)
+ FAIL_EXIT1 ("Got %p, expected %p\n", ptr, ref);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-absolute-zero-lib.c b/elf/tst-absolute-zero-lib.c
new file mode 100644
index 0000000000..fba2af0bc5
--- /dev/null
+++ b/elf/tst-absolute-zero-lib.c
@@ -0,0 +1,25 @@
+/* BZ #23307 absolute zero symbol calculation shared module.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+extern char absolute;
+
+void *
+get_absolute (void)
+{
+ return &absolute;
+}
diff --git a/elf/tst-absolute-zero-lib.lds b/elf/tst-absolute-zero-lib.lds
new file mode 100644
index 0000000000..2fa65dc3f9
--- /dev/null
+++ b/elf/tst-absolute-zero-lib.lds
@@ -0,0 +1 @@
+"absolute" = 0;
diff --git a/elf/tst-absolute-zero.c b/elf/tst-absolute-zero.c
new file mode 100644
index 0000000000..6b998ba69e
--- /dev/null
+++ b/elf/tst-absolute-zero.c
@@ -0,0 +1,38 @@
+/* BZ #23307 absolute zero symbol calculation main executable.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+
+void *get_absolute (void);
+
+static int
+do_test (void)
+{
+ void *ref = (void *) 0;
+ void *ptr;
+
+ ptr = get_absolute ();
+ if (ptr != ref)
+ FAIL_EXIT1 ("Got %p, expected %p\n", ptr, ref);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-addr1.c b/elf/tst-addr1.c
index 637906e206..68ff74aabd 100644
--- a/elf/tst-addr1.c
+++ b/elf/tst-addr1.c
@@ -22,5 +22,4 @@ do_test (void)
&& strcmp (i.dli_sname, "_IO_printf") != 0);
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-align.c b/elf/tst-align.c
index 10caa41e3e..d3ff89e0b4 100644
--- a/elf/tst-align.c
+++ b/elf/tst-align.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
@@ -49,5 +49,4 @@ do_test (void)
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-align2.c b/elf/tst-align2.c
index d5ec4aaa8f..9f254fa8a5 100644
--- a/elf/tst-align2.c
+++ b/elf/tst-align2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2005-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
@@ -152,5 +152,4 @@ do_test (void)
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-alignmod.c b/elf/tst-alignmod.c
index c95b1f7387..fc06018066 100644
--- a/elf/tst-alignmod.c
+++ b/elf/tst-alignmod.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
diff --git a/elf/tst-alignmod2.c b/elf/tst-alignmod2.c
index 2b43bd41bb..02e332f59a 100644
--- a/elf/tst-alignmod2.c
+++ b/elf/tst-alignmod2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
diff --git a/elf/tst-audit11.c b/elf/tst-audit11.c
index 0bcfd85a57..2aa9b55ccf 100644
--- a/elf/tst-audit11.c
+++ b/elf/tst-audit11.c
@@ -1,5 +1,5 @@
/* Test version symbol binding can find a DSO replaced by la_objsearch.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
@@ -32,5 +32,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-audit11mod1.c b/elf/tst-audit11mod1.c
index 90be27780e..04dce643a0 100644
--- a/elf/tst-audit11mod1.c
+++ b/elf/tst-audit11mod1.c
@@ -1,5 +1,5 @@
/* DSO directly opened by tst-audit11.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-audit11mod2.c b/elf/tst-audit11mod2.c
index b0e4936586..0fa2d2b932 100644
--- a/elf/tst-audit11mod2.c
+++ b/elf/tst-audit11mod2.c
@@ -1,5 +1,5 @@
/* DSO indirectly opened by tst-audit11, with symbol versioning.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-audit11mod2.map b/elf/tst-audit11mod2.map
index b0b263df08..a27af6aeed 100644
--- a/elf/tst-audit11mod2.map
+++ b/elf/tst-audit11mod2.map
@@ -1,5 +1,5 @@
/* Symbol versioning for the DSO indirectly opened by tst-audit11.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-audit12.c b/elf/tst-audit12.c
index 03dcf49597..3ee3f14219 100644
--- a/elf/tst-audit12.c
+++ b/elf/tst-audit12.c
@@ -1,5 +1,5 @@
/* Test that symbol is bound to a DSO replaced by la_objsearch.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
@@ -45,5 +45,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-audit12mod1.c b/elf/tst-audit12mod1.c
index d452596185..1510cda41a 100644
--- a/elf/tst-audit12mod1.c
+++ b/elf/tst-audit12mod1.c
@@ -1,5 +1,5 @@
/* DSO directly opened by tst-audit12.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-audit12mod2.c b/elf/tst-audit12mod2.c
index bc81cebc77..d3729d276c 100644
--- a/elf/tst-audit12mod2.c
+++ b/elf/tst-audit12mod2.c
@@ -1,5 +1,5 @@
/* Replaced DSO referenced by tst-audit12mod1.so, for tst-audit12.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-audit12mod2.map b/elf/tst-audit12mod2.map
index 43ce1c8ca0..006f3622c3 100644
--- a/elf/tst-audit12mod2.map
+++ b/elf/tst-audit12mod2.map
@@ -1,5 +1,5 @@
/* Symbol versioning for tst-audit12mod2.so used by tst-audit12.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-audit12mod3.c b/elf/tst-audit12mod3.c
index 21f109c453..9fddec9c0e 100644
--- a/elf/tst-audit12mod3.c
+++ b/elf/tst-audit12mod3.c
@@ -1,5 +1,5 @@
/* Replacement DSO loaded by the audit module, for tst-audit12.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-audit2.c b/elf/tst-audit2.c
index 1d69cd669e..0e66f5c328 100644
--- a/elf/tst-audit2.c
+++ b/elf/tst-audit2.c
@@ -57,5 +57,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-audit9.c b/elf/tst-audit9.c
index 7b90a5ad2d..b9de1bf5a2 100644
--- a/elf/tst-audit9.c
+++ b/elf/tst-audit9.c
@@ -8,5 +8,4 @@ do_test (void)
return fp() - 1;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-auditmod1.c b/elf/tst-auditmod1.c
index 227a3b623a..573e37abd6 100644
--- a/elf/tst-auditmod1.c
+++ b/elf/tst-auditmod1.c
@@ -1,4 +1,6 @@
#include <dlfcn.h>
+#include <link.h>
+#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/elf/tst-auditmod11.c b/elf/tst-auditmod11.c
index 7e1403e797..81f63b4a4b 100644
--- a/elf/tst-auditmod11.c
+++ b/elf/tst-auditmod11.c
@@ -1,5 +1,5 @@
/* Audit module for tst-audit11.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-auditmod12.c b/elf/tst-auditmod12.c
index 9f0f1e7c64..94f4d738c1 100644
--- a/elf/tst-auditmod12.c
+++ b/elf/tst-auditmod12.c
@@ -1,5 +1,5 @@
/* Audit module for tst-audit12.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-auxv.c b/elf/tst-auxv.c
index f77e3e0f53..cdb65f039e 100644
--- a/elf/tst-auxv.c
+++ b/elf/tst-auxv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2013-2018 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
@@ -66,4 +66,5 @@ do_test (int argc, char *argv[])
return 0;
}
-#include "../test-skeleton.c"
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/elf/tst-big-note-lib.S b/elf/tst-big-note-lib.S
new file mode 100644
index 0000000000..6b514a03cc
--- /dev/null
+++ b/elf/tst-big-note-lib.S
@@ -0,0 +1,26 @@
+/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify()
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This creates a .so with 8MiB PT_NOTE segment.
+ On a typical Linux system with 8MiB "ulimit -s", that was enough
+ to trigger stack overflow in open_verify. */
+
+.pushsection .note.big,"a"
+.balign 4
+.fill 8*1024*1024, 1, 0
+.popsection
diff --git a/elf/tst-big-note.c b/elf/tst-big-note.c
new file mode 100644
index 0000000000..fcd2b0ed82
--- /dev/null
+++ b/elf/tst-big-note.c
@@ -0,0 +1,26 @@
+/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify()
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This file must be run from within a directory called "elf". */
+
+int main (int argc, char *argv[])
+{
+ /* Nothing to do here: merely linking against tst-big-note-lib.so triggers
+ the bug. */
+ return 0;
+}
diff --git a/elf/tst-debug1.c b/elf/tst-debug1.c
new file mode 100644
index 0000000000..6d3d8baf05
--- /dev/null
+++ b/elf/tst-debug1.c
@@ -0,0 +1,34 @@
+/* Unit test for dlopen on ELF object from "objcopy --only-keep-debug".
+ Copyright (C) 2017-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ void *h = dlopen ("tst-debug1mod1.so", RTLD_LAZY);
+ if (h != NULL)
+ {
+ puts ("shouldn't load tst-debug1mod1.so");
+ return 1;
+ }
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-deep1.c b/elf/tst-deep1.c
index 5428d13de4..97dce7ea4d 100644
--- a/elf/tst-deep1.c
+++ b/elf/tst-deep1.c
@@ -32,5 +32,4 @@ do_test (void)
return foo () + f ();
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-dl-iter-static.c b/elf/tst-dl-iter-static.c
index c525baaa01..4df1edd191 100644
--- a/elf/tst-dl-iter-static.c
+++ b/elf/tst-dl-iter-static.c
@@ -1,5 +1,5 @@
/* BZ #16046 dl_iterate_phdr static executable test.
- Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Copyright (C) 2014-2018 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
@@ -43,5 +43,4 @@ do_test (void)
return status || count != 1;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmodcount.c b/elf/tst-dlmodcount.c
index 71653c3e1a..062530637c 100644
--- a/elf/tst-dlmodcount.c
+++ b/elf/tst-dlmodcount.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by David Mosberger <davidm@hpl.hp.com>, 2004.
@@ -105,5 +105,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen1.c b/elf/tst-dlmopen1.c
index 5a05891846..24145cfca6 100644
--- a/elf/tst-dlmopen1.c
+++ b/elf/tst-dlmopen1.c
@@ -77,5 +77,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen2.c b/elf/tst-dlmopen2.c
index 0569997258..8489ffba08 100644
--- a/elf/tst-dlmopen2.c
+++ b/elf/tst-dlmopen2.c
@@ -66,5 +66,4 @@ round %d, namespace %d: duplicate allocate of namespace %ld",
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen3.c b/elf/tst-dlmopen3.c
index 26c86b2dca..8167507784 100644
--- a/elf/tst-dlmopen3.c
+++ b/elf/tst-dlmopen3.c
@@ -18,5 +18,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-dlopen-aout.c b/elf/tst-dlopen-aout.c
index 11dd3054c1..9038e2096a 100644
--- a/elf/tst-dlopen-aout.c
+++ b/elf/tst-dlopen-aout.c
@@ -3,7 +3,7 @@
Verify that incorrectly dlopen()ing an executable without
__RTLD_OPENEXEC does not cause assertion in ld.so.
- Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Copyright (C) 2014-2018 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
@@ -63,5 +63,5 @@ do_test (int argc, char *argv[])
return 0;
}
-#define TEST_FUNCTION do_test (argc, argv)
-#include "../test-skeleton.c"
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/elf/tst-dlopenrpath.c b/elf/tst-dlopenrpath.c
index 12fbf4ceaf..c1cf86fb51 100644
--- a/elf/tst-dlopenrpath.c
+++ b/elf/tst-dlopenrpath.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@@ -67,5 +67,4 @@ do_test (void)
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-dlopenrpathmod.c b/elf/tst-dlopenrpathmod.c
index d89cfcb285..3a29d84676 100644
--- a/elf/tst-dlopenrpathmod.c
+++ b/elf/tst-dlopenrpathmod.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
diff --git a/elf/tst-dlsym-error.c b/elf/tst-dlsym-error.c
new file mode 100644
index 0000000000..b4094c760a
--- /dev/null
+++ b/elf/tst-dlsym-error.c
@@ -0,0 +1,113 @@
+/* Test error reporting for dlsym, dlvsym failures.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Used to disambiguate symbol names. */
+static int counter;
+
+static void
+test_one (void *handle, const char *name, void *(func) (void *, const char *),
+ const char *suffix)
+{
+ ++counter;
+ char symbol[32];
+ snprintf (symbol, sizeof (symbol), "no_such_symbol_%d", counter);
+ char *expected_message;
+ if (asprintf (&expected_message, ": undefined symbol: %s%s",
+ symbol, suffix) < 0)
+ {
+ printf ("error: asprintf: %m\n");
+ abort ();
+ }
+
+ void *addr = func (handle, symbol);
+ if (addr != NULL)
+ {
+ printf ("error: %s: found symbol \"no_such_symbol\"\n", name);
+ abort ();
+ }
+ const char *message = dlerror ();
+ if (message == NULL)
+ {
+ printf ("error: %s: missing error message\n", name);
+ abort ();
+ }
+ const char *message_without_path = strchrnul (message, ':');
+ if (strcmp (message_without_path, expected_message) != 0)
+ {
+ printf ("error: %s: unexpected error message: %s\n", name, message);
+ abort ();
+ }
+ free (expected_message);
+
+ message = dlerror ();
+ if (message != NULL)
+ {
+ printf ("error: %s: unexpected error message: %s\n", name, message);
+ abort ();
+ }
+}
+
+static void
+test_handles (const char *name, void *(func) (void *, const char *),
+ const char *suffix)
+{
+ test_one (RTLD_DEFAULT, name, func, suffix);
+ test_one (RTLD_NEXT, name, func, suffix);
+
+ void *handle = dlopen (LIBC_SO, RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: cannot dlopen %s: %s\n", LIBC_SO, dlerror ());
+ abort ();
+ }
+ test_one (handle, name, func, suffix);
+ dlclose (handle);
+}
+
+static void *
+dlvsym_no_such_version (void *handle, const char *name)
+{
+ return dlvsym (handle, name, "NO_SUCH_VERSION");
+}
+
+static void *
+dlvsym_glibc_private (void *handle, const char *name)
+{
+ return dlvsym (handle, name, "GLIBC_PRIVATE");
+}
+
+static int
+do_test (void)
+{
+ test_handles ("dlsym", dlsym, "");
+ test_handles ("dlvsym", dlvsym_no_such_version,
+ ", version NO_SUCH_VERSION");
+ test_handles ("dlvsym", dlvsym_glibc_private,
+ ", version GLIBC_PRIVATE");
+
+ return 0;
+}
+
+
+#include <support/test-driver.c>
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
new file mode 100644
index 0000000000..d7c4f0d574
--- /dev/null
+++ b/elf/tst-env-setuid-tunables.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 2017-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* Verify that tunables correctly filter out unsafe tunables like
+ glibc.malloc.check and glibc.malloc.mmap_threshold but also retain
+ glibc.malloc.mmap_threshold in an unprivileged child. */
+
+/* This is compiled as part of the testsuite but needs to see
+ HAVE_TUNABLES. */
+#define _LIBC 1
+#include "config.h"
+#undef _LIBC
+
+#define test_parent test_parent_tunables
+#define test_child test_child_tunables
+
+static int test_child_tunables (void);
+static int test_parent_tunables (void);
+
+#include "tst-env-setuid.c"
+
+#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096"
+#define PARENT_VALSTRING_VALUE \
+ "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096"
+
+static int
+test_child_tunables (void)
+{
+ const char *val = getenv ("GLIBC_TUNABLES");
+
+#if HAVE_TUNABLES
+ if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0)
+ return 0;
+
+ if (val != NULL)
+ printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
+
+ return 1;
+#else
+ if (val != NULL)
+ {
+ printf ("GLIBC_TUNABLES not cleared\n");
+ return 1;
+ }
+ return 0;
+#endif
+}
+
+static int
+test_parent_tunables (void)
+{
+ const char *val = getenv ("GLIBC_TUNABLES");
+
+ if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0)
+ return 0;
+
+ if (val != NULL)
+ printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
+
+ return 1;
+}
diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c
new file mode 100644
index 0000000000..183a6dd133
--- /dev/null
+++ b/elf/tst-env-setuid.c
@@ -0,0 +1,296 @@
+/* Copyright (C) 2012-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* Verify that tunables correctly filter out unsafe environment variables like
+ MALLOC_CHECK_ and MALLOC_MMAP_THRESHOLD_ but also retain
+ MALLOC_MMAP_THRESHOLD_ in an unprivileged child. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <support/support.h>
+#include <support/test-driver.h>
+
+static char SETGID_CHILD[] = "setgid-child";
+#define CHILD_STATUS 42
+
+/* Return a GID which is not our current GID, but is present in the
+ supplementary group list. */
+static gid_t
+choose_gid (void)
+{
+ const int count = 64;
+ gid_t groups[count];
+ int ret = getgroups (count, groups);
+ if (ret < 0)
+ {
+ printf ("getgroups: %m\n");
+ exit (1);
+ }
+ gid_t current = getgid ();
+ for (int i = 0; i < ret; ++i)
+ {
+ if (groups[i] != current)
+ return groups[i];
+ }
+ return 0;
+}
+
+/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */
+static pid_t
+do_execve (char **args)
+{
+ pid_t kid = vfork ();
+
+ if (kid < 0)
+ {
+ printf ("vfork: %m\n");
+ return -1;
+ }
+
+ if (kid == 0)
+ {
+ /* Child process. */
+ execve (args[0], args, environ);
+ _exit (-errno);
+ }
+
+ if (kid < 0)
+ return 1;
+
+ int status;
+
+ if (waitpid (kid, &status, 0) < 0)
+ {
+ printf ("waitpid: %m\n");
+ return 1;
+ }
+
+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+ return EXIT_UNSUPPORTED;
+
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS)
+ {
+ printf ("Unexpected exit status %d from child process\n",
+ WEXITSTATUS (status));
+ return 1;
+ }
+ return 0;
+}
+
+/* Copies the executable into a restricted directory, so that we can
+ safely make it SGID with the TARGET group ID. Then runs the
+ executable. */
+static int
+run_executable_sgid (gid_t target)
+{
+ char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
+ test_dir, (intmax_t) getpid ());
+ char *execname = xasprintf ("%s/bin", dirname);
+ int infd = -1;
+ int outfd = -1;
+ int ret = 0;
+ if (mkdir (dirname, 0700) < 0)
+ {
+ printf ("mkdir: %m\n");
+ goto err;
+ }
+ infd = open ("/proc/self/exe", O_RDONLY);
+ if (infd < 0)
+ {
+ printf ("open (/proc/self/exe): %m\n");
+ goto err;
+ }
+ outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
+ if (outfd < 0)
+ {
+ printf ("open (%s): %m\n", execname);
+ goto err;
+ }
+ char buf[4096];
+ for (;;)
+ {
+ ssize_t rdcount = read (infd, buf, sizeof (buf));
+ if (rdcount < 0)
+ {
+ printf ("read: %m\n");
+ goto err;
+ }
+ if (rdcount == 0)
+ break;
+ char *p = buf;
+ char *end = buf + rdcount;
+ while (p != end)
+ {
+ ssize_t wrcount = write (outfd, buf, end - p);
+ if (wrcount == 0)
+ errno = ENOSPC;
+ if (wrcount <= 0)
+ {
+ printf ("write: %m\n");
+ goto err;
+ }
+ p += wrcount;
+ }
+ }
+ if (fchown (outfd, getuid (), target) < 0)
+ {
+ printf ("fchown (%s): %m\n", execname);
+ goto err;
+ }
+ if (fchmod (outfd, 02750) < 0)
+ {
+ printf ("fchmod (%s): %m\n", execname);
+ goto err;
+ }
+ if (close (outfd) < 0)
+ {
+ printf ("close (outfd): %m\n");
+ goto err;
+ }
+ if (close (infd) < 0)
+ {
+ printf ("close (infd): %m\n");
+ goto err;
+ }
+
+ char *args[] = {execname, SETGID_CHILD, NULL};
+
+ ret = do_execve (args);
+
+err:
+ if (outfd >= 0)
+ close (outfd);
+ if (infd >= 0)
+ close (infd);
+ if (execname)
+ {
+ unlink (execname);
+ free (execname);
+ }
+ if (dirname)
+ {
+ rmdir (dirname);
+ free (dirname);
+ }
+ return ret;
+}
+
+#ifndef test_child
+static int
+test_child (void)
+{
+ if (getenv ("MALLOC_CHECK_") != NULL)
+ {
+ printf ("MALLOC_CHECK_ is still set\n");
+ return 1;
+ }
+
+ if (getenv ("MALLOC_MMAP_THRESHOLD_") == NULL)
+ {
+ printf ("MALLOC_MMAP_THRESHOLD_ lost\n");
+ return 1;
+ }
+
+ if (getenv ("LD_HWCAP_MASK") != NULL)
+ {
+ printf ("LD_HWCAP_MASK still set\n");
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef test_parent
+static int
+test_parent (void)
+{
+ if (getenv ("MALLOC_CHECK_") == NULL)
+ {
+ printf ("MALLOC_CHECK_ lost\n");
+ return 1;
+ }
+
+ if (getenv ("MALLOC_MMAP_THRESHOLD_") == NULL)
+ {
+ printf ("MALLOC_MMAP_THRESHOLD_ lost\n");
+ return 1;
+ }
+
+ if (getenv ("LD_HWCAP_MASK") == NULL)
+ {
+ printf ("LD_HWCAP_MASK lost\n");
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+static int
+do_test (int argc, char **argv)
+{
+ /* Setgid child process. */
+ if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
+ {
+ if (getgid () == getegid ())
+ {
+ /* This can happen if the file system is mounted nosuid. */
+ fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
+ (intmax_t) getgid ());
+ exit (EXIT_UNSUPPORTED);
+ }
+
+ int ret = test_child ();
+
+ if (ret != 0)
+ exit (1);
+
+ exit (CHILD_STATUS);
+ }
+ else
+ {
+ if (test_parent () != 0)
+ exit (1);
+
+ /* Try running a setgid program. */
+ gid_t target = choose_gid ();
+ if (target == 0)
+ {
+ fprintf (stderr,
+ "Could not find a suitable GID for user %jd, skipping test\n",
+ (intmax_t) getuid ());
+ exit (0);
+ }
+
+ return run_executable_sgid (target);
+ }
+
+ /* Something went wrong and our argv was corrupted. */
+ _exit (1);
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/elf/tst-execstack-needed.c b/elf/tst-execstack-needed.c
index 03090f7dd6..8b794a3d47 100644
--- a/elf/tst-execstack-needed.c
+++ b/elf/tst-execstack-needed.c
@@ -31,6 +31,4 @@ deeper (void (*f) (void))
memfrob (stack, sizeof stack);
}
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-execstack-prog.c b/elf/tst-execstack-prog.c
index 5a66d63ca9..8663153372 100644
--- a/elf/tst-execstack-prog.c
+++ b/elf/tst-execstack-prog.c
@@ -30,6 +30,4 @@ deeper (void (*f) (void))
memfrob (stack, sizeof stack);
}
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-execstack.c b/elf/tst-execstack.c
index 02cc270d80..114f341d76 100644
--- a/elf/tst-execstack.c
+++ b/elf/tst-execstack.c
@@ -233,5 +233,4 @@ deeper (void (*f) (void))
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-global1.c b/elf/tst-global1.c
index 4df335c637..5dae74eec0 100644
--- a/elf/tst-global1.c
+++ b/elf/tst-global1.c
@@ -35,5 +35,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-gnu2-tls1.c b/elf/tst-gnu2-tls1.c
new file mode 100644
index 0000000000..e6f98e64be
--- /dev/null
+++ b/elf/tst-gnu2-tls1.c
@@ -0,0 +1,51 @@
+/* Test local and global dynamic models for GNU2 TLS.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int * get_gd (void);
+extern void set_gd (int);
+extern int test_gd (int);
+extern int * get_ld (void);
+extern void set_ld (int);
+extern int test_ld (int);
+
+__thread int gd = 1;
+
+static int
+do_test (void)
+{
+ int *p;
+
+ p = get_gd ();
+ set_gd (3);
+ if (*p != 3 || !test_gd (3))
+ abort ();
+
+ p = get_ld ();
+ set_ld (4);
+ if (*p != 4 || !test_ld (4))
+ abort ();
+
+ printf ("PASS\n");
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-gnu2-tls1mod.c b/elf/tst-gnu2-tls1mod.c
new file mode 100644
index 0000000000..190b9ad1c9
--- /dev/null
+++ b/elf/tst-gnu2-tls1mod.c
@@ -0,0 +1,56 @@
+/* DSO used by tst-gnu2-tls1.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+static __thread int ld;
+
+int *
+get_ld (void)
+{
+ return &ld;
+}
+
+void
+set_ld (int i)
+{
+ ld = i;
+}
+
+int
+test_ld (int i)
+{
+ return ld == i;
+}
+extern __thread int gd;
+
+int *
+get_gd (void)
+{
+ return &gd;
+}
+
+void
+set_gd (int i)
+{
+ gd = i;
+}
+
+int
+test_gd (int i)
+{
+ return gd == i;
+}
diff --git a/elf/tst-latepthread.c b/elf/tst-latepthread.c
new file mode 100644
index 0000000000..612bfc5814
--- /dev/null
+++ b/elf/tst-latepthread.c
@@ -0,0 +1,104 @@
+/* Test that loading libpthread does not break ld.so exceptions (bug 16628).
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ void *handle = dlopen ("tst-latepthreadmod.so", RTLD_LOCAL | RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: dlopen failed: %s\n", dlerror ());
+ return 1;
+ }
+ void *ptr = dlsym (handle, "trigger_dynlink_failure");
+ if (ptr == NULL)
+ {
+ printf ("error: dlsym failed: %s\n", dlerror ());
+ return 1;
+ }
+ int (*func) (void) = ptr;
+
+ /* Run the actual test in a subprocess, to capture the error. */
+ int fds[2];
+ if (pipe (fds) < 0)
+ {
+ printf ("error: pipe: %m\n");
+ return 1;
+ }
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("error: fork: %m\n");
+ return 1;
+ }
+ else if (pid == 0)
+ {
+ if (dup2 (fds[1], STDERR_FILENO) < 0)
+ _exit (2);
+ /* Trigger an abort. */
+ func ();
+ _exit (3);
+ }
+ /* NB: This assumes that the abort message is so short that the pipe
+ does not block. */
+ int status;
+ if (waitpid (pid, &status, 0) < 0)
+ {
+ printf ("error: waitpid: %m\n");
+ return 1;
+ }
+
+ /* Check the printed error message. */
+ if (close (fds[1]) < 0)
+ {
+ printf ("error: close: %m\n");
+ return 1;
+ }
+ char buf[512];
+ /* Leave room for the NUL terminator. */
+ ssize_t ret = read (fds[0], buf, sizeof (buf) - 1);
+ if (ret < 0)
+ {
+ printf ("error: read: %m\n");
+ return 1;
+ }
+ if (ret > 0 && buf[ret - 1] == '\n')
+ --ret;
+ buf[ret] = '\0';
+ printf ("info: exit status: %d, message: %s\n", status, buf);
+ if (strstr (buf, "undefined symbol: this_function_is_not_defined") == NULL)
+ {
+ printf ("error: message does not contain expected string\n");
+ return 1;
+ }
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != 127)
+ {
+ printf ("error: unexpected process exit status\n");
+ return 1;
+ }
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-latepthreadmod.c b/elf/tst-latepthreadmod.c
new file mode 100644
index 0000000000..c41b1be7ce
--- /dev/null
+++ b/elf/tst-latepthreadmod.c
@@ -0,0 +1,33 @@
+/* DSO which links against libpthread and triggers a lazy binding.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is compiled into a DSO which loads libpthread, but fails
+ the dynamic linker afterwards. */
+
+#include <pthread.h>
+
+/* Link in libpthread. */
+void *pthread_create_ptr = &pthread_create;
+
+int this_function_is_not_defined (void);
+
+int
+trigger_dynlink_failure (void)
+{
+ return this_function_is_not_defined ();
+}
diff --git a/elf/tst-ldconfig-X.sh b/elf/tst-ldconfig-X.sh
new file mode 100644
index 0000000000..fedc2d7b03
--- /dev/null
+++ b/elf/tst-ldconfig-X.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Test that ldconfig -X does not remove stale symbolic links.
+# Copyright (C) 2000-2018 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
+# <http://www.gnu.org/licenses/>.
+
+set -ex
+
+common_objpfx=$1
+test_wrapper_env=$2
+run_program_env=$3
+
+testroot="${common_objpfx}elf/bug19610-test-directory"
+cleanup () {
+ rm -rf "$testroot"
+}
+trap cleanup 0
+
+rm -rf "$testroot"
+mkdir -p $testroot/lib $testroot/etc
+
+# Relative symbolic link target.
+ln -s libdoesnotexist.so.1.1 $testroot/lib/libdoesnotexist.so.1
+
+# Absolute symbolic link target.
+ln -s $testroot/opt/sw/lib/libdoesnotexist2.so.1.1 $testroot/lib/
+
+errors=0
+check_files () {
+ for name in libdoesnotexist.so.1 libdoesnotexist2.so.1.1 ; do
+ path="$testroot/lib/$name"
+ if test ! -h $path ; then
+ echo "error: missing file: $path"
+ errors=1
+ fi
+ done
+}
+
+check_files
+
+${test_wrapper_env} \
+${run_program_env} \
+${common_objpfx}elf/ldconfig -X -f /dev/null \
+ -C $testroot/etc/ld.so.cache \
+ $testroot/lib
+
+check_files
+
+exit $errors
diff --git a/elf/tst-leaks1.c b/elf/tst-leaks1.c
index dcff28dafa..75bc92d25f 100644
--- a/elf/tst-leaks1.c
+++ b/elf/tst-leaks1.c
@@ -6,13 +6,28 @@
static int
do_test (void)
{
+ void *h;
+ int ret = 0;
+ /* Carry out *one* failing call to dlopen before starting mtrace to
+ force any one-time inintialization that may happen to the
+ executable link map e.g. expansion and caching of $ORIGIN. */
+ h = dlopen ("$ORIGIN/tst-leaks1.o", RTLD_LAZY);
+ if (h != NULL)
+ {
+ puts ("dlopen unexpectedly succeeded");
+ ret = 1;
+ dlclose (h);
+ }
+
+ /* Start tracing and run each test 5 times to see if there are any
+ leaks in the failing dlopen. */
mtrace ();
- int ret = 0;
for (int i = 0; i < 10; i++)
{
- void *h = dlopen (i < 5 ? "./tst-leaks1.c"
- : "$ORIGIN/tst-leaks1.o", RTLD_LAZY);
+ h = dlopen (i < 5
+ ? "./tst-leaks1.c"
+ : "$ORIGIN/tst-leaks1.o", RTLD_LAZY);
if (h != NULL)
{
puts ("dlopen unexpectedly succeeded");
@@ -24,5 +39,4 @@ do_test (void)
return ret;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-libc_dlvsym-dso.c b/elf/tst-libc_dlvsym-dso.c
new file mode 100644
index 0000000000..d74c1ead61
--- /dev/null
+++ b/elf/tst-libc_dlvsym-dso.c
@@ -0,0 +1,25 @@
+/* Compare dlvsym and __libc_dlvsym results. Shared object code.
+ Copyright (C) 2017 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
+ <http://www.gnu.org/licenses/>. */
+
+#include "tst-libc_dlvsym.h"
+
+void
+compare_vsyms_global (void)
+{
+ compare_vsyms ();
+}
diff --git a/elf/tst-libc_dlvsym-static.c b/elf/tst-libc_dlvsym-static.c
new file mode 100644
index 0000000000..955f28d754
--- /dev/null
+++ b/elf/tst-libc_dlvsym-static.c
@@ -0,0 +1,32 @@
+/* Compare dlvsym and __libc_dlvsym results. Static version.
+ Copyright (C) 2017 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+ void *handle = xdlopen ("tst-libc_dlvsym-dso.so", RTLD_LAZY);
+ void (*compare) (void) = xdlsym (handle, "compare_vsyms_global");
+ compare ();
+ xdlclose (handle);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-libc_dlvsym.c b/elf/tst-libc_dlvsym.c
new file mode 100644
index 0000000000..864db4ee6a
--- /dev/null
+++ b/elf/tst-libc_dlvsym.c
@@ -0,0 +1,34 @@
+/* Compare dlvsym and __libc_dlvsym results. Dynamic version.
+ Copyright (C) 2017 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
+ <http://www.gnu.org/licenses/>. */
+
+#include "tst-libc_dlvsym.h"
+
+static int
+do_test (void)
+{
+ compare_vsyms ();
+
+ void *handle = xdlopen ("tst-libc_dlvsym-dso.so", RTLD_LAZY);
+ void (*compare) (void) = xdlsym (handle, "compare_vsyms_global");
+ compare ();
+ xdlclose (handle);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-libc_dlvsym.h b/elf/tst-libc_dlvsym.h
new file mode 100644
index 0000000000..6b1d8d5b3a
--- /dev/null
+++ b/elf/tst-libc_dlvsym.h
@@ -0,0 +1,125 @@
+/* Compare dlvsym and __libc_dlvsym results. Common code.
+ Copyright (C) 2017 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
+ <http://www.gnu.org/licenses/>. */
+
+/* compare_vsyms is the main entry point for these tests.
+
+ Indirectly, It calls __libc_dlvsym (from libc.so; internal
+ interface) and dlvsym (from libdl.so; public interface) to compare
+ the results for a selected set of symbols in libc.so which
+ typically have more than one symbol version. The two functions are
+ implemented by somewhat different code, and this test checks that
+ their results are the same.
+
+ The versions are generated to range from GLIBC_2.0 to GLIBC_2.Y,
+ with Y being the current __GLIBC_MINOR__ version plus two. In
+ addition, there is a list of special symbol versions of the form
+ GLIBC_2.Y.Z, which were used for some releases.
+
+ Comparing the two dlvsym results at versions which do not actually
+ exist does not test much, but it will not contribute to false test
+ failures, either. */
+
+#include <array_length.h>
+#include <gnu/lib-names.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+/* Run consistency check for versioned symbol NAME@VERSION. NB: We
+ may execute in a shared object, so exit on error for proper error
+ reporting. */
+static void
+compare_vsyms_0 (void *libc_handle, const char *name, const char *version,
+ bool *pfound)
+{
+ void *dlvsym_address = dlvsym (libc_handle, name, version);
+ void *libc_dlvsym_address
+ = __libc_dlvsym (libc_handle, name, version);
+ if (dlvsym_address != libc_dlvsym_address)
+ FAIL_EXIT1 ("%s@%s mismatch: %p != %p",
+ name, version, dlvsym_address, libc_dlvsym_address);
+ if (dlvsym_address != NULL)
+ *pfound = true;
+}
+
+
+/* Run consistency check for versioned symbol NAME at multiple symbol
+ version. */
+static void
+compare_vsyms_1 (void *libc_handle, const char *name)
+{
+ bool found = false;
+
+ /* Historic versions which do not follow the usual GLIBC_2.Y
+ pattern, to increase test coverage. Not all architectures have
+ those, but probing additional versions does not hurt. */
+ static const char special_versions[][12] =
+ {
+ "GLIBC_2.1.1",
+ "GLIBC_2.1.2",
+ "GLIBC_2.1.3",
+ "GLIBC_2.1.4",
+ "GLIBC_2.2.1",
+ "GLIBC_2.2.2",
+ "GLIBC_2.2.3",
+ "GLIBC_2.2.4",
+ "GLIBC_2.2.5",
+ "GLIBC_2.2.6",
+ "GLIBC_2.3.2",
+ "GLIBC_2.3.3",
+ "GLIBC_2.3.4",
+ };
+ for (int i = 0; i < array_length (special_versions); ++i)
+ compare_vsyms_0 (libc_handle, name, special_versions[i], &found);
+
+ /* Iterate to an out-of-range version, to cover some unused symbols
+ as well. */
+ for (int minor_version = 0; minor_version <= __GLIBC_MINOR__ + 2;
+ ++minor_version)
+ {
+ char version[30];
+ snprintf (version, sizeof (version), "GLIBC_%d.%d",
+ __GLIBC__, minor_version);
+ compare_vsyms_0 (libc_handle, name, version, &found);
+ }
+
+ if (!found)
+ FAIL_EXIT1 ("symbol %s not found at any version", name);
+}
+
+/* Run consistency checks for various symbols which usually have
+ multiple versions. */
+static void
+compare_vsyms (void)
+{
+ /* The minor version loop in compare_vsyms_1 needs updating in case
+ we ever switch to glibc 3.0. */
+ if (__GLIBC__ != 2)
+ FAIL_EXIT1 ("unexpected glibc major version: %d", __GLIBC__);
+
+ /* __libc_dlvsym does not recognize the special RTLD_* handles, so
+ obtain an explicit handle for libc.so. */
+ void *libc_handle = xdlopen (LIBC_SO, RTLD_LAZY | RTLD_NOLOAD);
+
+ compare_vsyms_1 (libc_handle, "_sys_errlist");
+ compare_vsyms_1 (libc_handle, "_sys_siglist");
+ compare_vsyms_1 (libc_handle, "quick_exit");
+
+ xdlclose (libc_handle);
+}
diff --git a/elf/tst-linkall-static.c b/elf/tst-linkall-static.c
new file mode 100644
index 0000000000..d0f2592e67
--- /dev/null
+++ b/elf/tst-linkall-static.c
@@ -0,0 +1,54 @@
+/* Test static linking against multiple libraries, to find symbol conflicts.
+ Copyright (C) 2016-2018 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 <http://www.gnu.org/licenses/>. */
+
+#include <math.h>
+#include <pthread.h>
+#if USE_CRYPT
+# include <crypt.h>
+#endif
+#include <resolv.h>
+#include <dlfcn.h>
+#include <utmp.h>
+#include <aio.h>
+#include <netdb.h>
+
+/* These references force linking the executable against central
+ functions in the static libraries, pulling significant parts of
+ each library into the link. */
+void *references[] =
+ {
+ &pow, /* libm */
+ &pthread_create, /* libpthread */
+#if USE_CRYPT
+ &crypt, /* libcrypt */
+#endif
+ &res_send, /* libresolv */
+ &dlopen, /* libdl */
+ &login, /* libutil */
+ &aio_init, /* librt */
+ &getaddrinfo_a, /* libanl */
+ };
+
+static int
+do_test (void)
+{
+ /* This is a link-time test. There is nothing to run here. */
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-main1.c b/elf/tst-main1.c
new file mode 100644
index 0000000000..ab0eaea01b
--- /dev/null
+++ b/elf/tst-main1.c
@@ -0,0 +1,19 @@
+/* Unit test for main () in a shared object.
+ Copyright (C) 2017-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This is empty. */
diff --git a/elf/tst-main1mod.c b/elf/tst-main1mod.c
new file mode 100644
index 0000000000..a40f628c22
--- /dev/null
+++ b/elf/tst-main1mod.c
@@ -0,0 +1,25 @@
+/* Unit test for main () in a shared object.
+ Copyright (C) 2017-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+static int
+do_test (void)
+{
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-nodelete-dlclose-dso.c b/elf/tst-nodelete-dlclose-dso.c
new file mode 100644
index 0000000000..7936239c87
--- /dev/null
+++ b/elf/tst-nodelete-dlclose-dso.c
@@ -0,0 +1,90 @@
+/* Bug 11941: Improper assert map->l_init_called in dlclose.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This is the primary DSO that is loaded by the appliation. This DSO
+ then loads a plugin with RTLD_NODELETE. This plugin depends on this
+ DSO. This dependency chain means that at application shutdown the
+ plugin will be destructed first. Thus by the time this DSO is
+ destructed we will be calling dlclose on an object that has already
+ been destructed. It is allowed to call dlclose in this way and
+ should not assert. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+/* 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.
+ We do this to avoid any future --as-needed from removing the
+ plugin's DT_NEEDED on this DSO (required for the test). */
+void
+primary_reference (void)
+{
+ printf ("INFO: Called primary_reference function.\n");
+}
+
+void
+primary (void)
+{
+ char *error;
+
+ plugin_lib = dlopen (LIB_PLUGIN, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE);
+ if (plugin_lib == NULL)
+ {
+ printf ("ERROR: Unable to load plugin library.\n");
+ exit (EXIT_FAILURE);
+ }
+ dlerror ();
+
+ plugin_func = (void (*) (void)) dlsym (plugin_lib, "plugin_func");
+ error = dlerror ();
+ if (error != NULL)
+ {
+ printf ("ERROR: Unable to find symbol with error \"%s\".",
+ error);
+ exit (EXIT_FAILURE);
+ }
+
+ return;
+}
+
+__attribute__ ((destructor))
+static void
+primary_dtor (void)
+{
+ int ret;
+
+ printf ("INFO: Calling primary destructor.\n");
+
+ /* The destructor runs in the test driver also, which
+ hasn't called primary, in that case do nothing. */
+ if (plugin_lib == NULL)
+ return;
+
+ ret = dlclose (plugin_lib);
+ if (ret != 0)
+ {
+ printf ("ERROR: Calling dlclose failed with \"%s\"\n",
+ dlerror ());
+ exit (EXIT_FAILURE);
+ }
+}
diff --git a/elf/tst-nodelete-dlclose-plugin.c b/elf/tst-nodelete-dlclose-plugin.c
new file mode 100644
index 0000000000..077275a2b8
--- /dev/null
+++ b/elf/tst-nodelete-dlclose-plugin.c
@@ -0,0 +1,40 @@
+/* Bug 11941: Improper assert map->l_init_called in dlclose.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This DSO simulates a plugin with a dependency on the
+ primary DSO loaded by the appliation. */
+#include <stdio.h>
+
+extern void primary_reference (void);
+
+void
+plugin_func (void)
+{
+ printf ("INFO: Calling plugin function.\n");
+ /* Need a reference to the DSO to ensure that a potential --as-needed
+ doesn't remove the DT_NEEDED entry which we rely upon to ensure
+ destruction ordering. */
+ primary_reference ();
+}
+
+__attribute__ ((destructor))
+static void
+plugin_dtor (void)
+{
+ printf ("INFO: Calling plugin destructor.\n");
+}
diff --git a/elf/tst-nodelete-dlclose.c b/elf/tst-nodelete-dlclose.c
new file mode 100644
index 0000000000..90ba7c7260
--- /dev/null
+++ b/elf/tst-nodelete-dlclose.c
@@ -0,0 +1,35 @@
+/* Bug 11941: Improper assert map->l_init_called in dlclose.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This simulates an application using the primary DSO which loads the
+ plugin DSO. */
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void primary (void);
+
+static int
+do_test (void)
+{
+ printf ("INFO: Starting application.\n");
+ primary ();
+ printf ("INFO: Exiting application.\n");
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-nodelete-opened-lib.c b/elf/tst-nodelete-opened-lib.c
index 8acb1d8ee1..7c65024255 100644
--- a/elf/tst-nodelete-opened-lib.c
+++ b/elf/tst-nodelete-opened-lib.c
@@ -1,5 +1,5 @@
/* Verify that objects opened with RTLD_NODELETE are not unloaded - the DSO.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
diff --git a/elf/tst-nodelete-opened.c b/elf/tst-nodelete-opened.c
index 75d382eba3..322ead2122 100644
--- a/elf/tst-nodelete-opened.c
+++ b/elf/tst-nodelete-opened.c
@@ -1,7 +1,7 @@
/* Verify that an already opened DSO opened agained with RTLD_NODELETE actually
sets the NODELETE flag.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
@@ -65,5 +65,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-nodelete.cc b/elf/tst-nodelete.cc
index 176cb68836..5752e7df26 100644
--- a/elf/tst-nodelete.cc
+++ b/elf/tst-nodelete.cc
@@ -47,5 +47,4 @@ do_test (void)
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-nodelete2.c b/elf/tst-nodelete2.c
index 388e8afb32..010c4ae237 100644
--- a/elf/tst-nodelete2.c
+++ b/elf/tst-nodelete2.c
@@ -33,5 +33,4 @@ do_test (void)
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-noload.c b/elf/tst-noload.c
new file mode 100644
index 0000000000..70609e0416
--- /dev/null
+++ b/elf/tst-noload.c
@@ -0,0 +1,72 @@
+/* Verify that RTLD_NOLOAD works as expected.
+
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <gnu/lib-names.h>
+
+static int
+do_test (void)
+{
+ /* Test that no object is loaded with RTLD_NOLOAD. */
+ void *h1 = dlopen (LIBM_SO, RTLD_LAZY | RTLD_NOLOAD);
+ if (h1 != NULL)
+ {
+ printf ("h1: DSO has been loaded while it should have not\n");
+ return 1;
+ }
+
+ /* This used to segfault in some glibc versions. */
+ void *h2 = dlopen (LIBM_SO, RTLD_LAZY | RTLD_NOLOAD | RTLD_NODELETE);
+ if (h2 != NULL)
+ {
+ printf ("h2: DSO has been loaded while it should have not\n");
+ return 1;
+ }
+
+ /* Test that loading an already loaded object returns the same. */
+ void *h3 = dlopen (LIBM_SO, RTLD_LAZY);
+ if (h3 == NULL)
+ {
+ printf ("h3: failed to open DSO: %s\n", dlerror ());
+ return 1;
+ }
+ void *h4 = dlopen (LIBM_SO, RTLD_LAZY | RTLD_NOLOAD);
+ if (h4 == NULL)
+ {
+ printf ("h4: failed to open DSO: %s\n", dlerror ());
+ return 1;
+ }
+ if (h4 != h3)
+ {
+ printf ("h4: should return the same object\n");
+ return 1;
+ }
+
+ /* Cleanup */
+ if (dlclose (h3) != 0)
+ {
+ printf ("h3: dlclose failed: %s\n", dlerror ());
+ return 1;
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-null-argv-lib.c b/elf/tst-null-argv-lib.c
index 6eba436813..9264601642 100644
--- a/elf/tst-null-argv-lib.c
+++ b/elf/tst-null-argv-lib.c
@@ -1,6 +1,6 @@
/* Verify that program does not crash when LD_DEBUG is set and the program name
is not available. This is the library.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2018 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
diff --git a/elf/tst-null-argv.c b/elf/tst-null-argv.c
index e9a621e76e..53ba6dd005 100644
--- a/elf/tst-null-argv.c
+++ b/elf/tst-null-argv.c
@@ -1,6 +1,6 @@
/* Verify that program does not crash when LD_DEBUG is set and the program name
is not available.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2018 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
@@ -32,4 +32,5 @@ do_test (int argc, char **argv)
return 0;
}
-#include <test-skeleton.c>
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/elf/tst-order-main.c b/elf/tst-order-main.c
index 339778a93a..2a90130db6 100644
--- a/elf/tst-order-main.c
+++ b/elf/tst-order-main.c
@@ -9,5 +9,4 @@ do_test (void)
exit(EXIT_SUCCESS);
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-pathopt.c b/elf/tst-pathopt.c
index 8d73ad4def..e2c96fbc72 100644
--- a/elf/tst-pathopt.c
+++ b/elf/tst-pathopt.c
@@ -38,5 +38,4 @@ do_test (void)
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-pathopt.sh b/elf/tst-pathopt.sh
index 309b628bc9..0a9d67fd45 100755
--- a/elf/tst-pathopt.sh
+++ b/elf/tst-pathopt.sh
@@ -1,6 +1,6 @@
#!/bin/sh
# Test lookup path optimization.
-# Copyright (C) 2000-2016 Free Software Foundation, Inc.
+# Copyright (C) 2000-2018 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
diff --git a/elf/tst-pie2.c b/elf/tst-pie2.c
index 4c2daffb47..9dded6e4d5 100644
--- a/elf/tst-pie2.c
+++ b/elf/tst-pie2.c
@@ -1,6 +1,6 @@
/* Test case for BZ #16381
- Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Copyright (C) 2014-2018 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
@@ -37,5 +37,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-piemod1.c b/elf/tst-piemod1.c
index 6e98b5f0c2..72d7e0a187 100644
--- a/elf/tst-piemod1.c
+++ b/elf/tst-piemod1.c
@@ -19,5 +19,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-prelink.c b/elf/tst-prelink.c
index bb6df7ade7..9065a8412b 100644
--- a/elf/tst-prelink.c
+++ b/elf/tst-prelink.c
@@ -1,6 +1,6 @@
/* Test the output from the environment variable, LD_TRACE_PRELINKING,
for prelink.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
@@ -26,5 +26,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-protected1a.c b/elf/tst-protected1a.c
index 1c55440624..afaf2d5635 100644
--- a/elf/tst-protected1a.c
+++ b/elf/tst-protected1a.c
@@ -7,7 +7,7 @@
4. Symbol, protected2, defined in main, is used in main.
5. Symbol, protected3, defined in moda, is also used in main.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
@@ -40,10 +40,8 @@ extern int do_test (void);
int protected2 = -1;
-#define TEST_FUNCTION do_test ()
-
/* This defines the `main' function and some more. */
-#include <test-skeleton.c>
+#include <support/test-driver.c>
int
do_test (void)
diff --git a/elf/tst-protected1b.c b/elf/tst-protected1b.c
index 9dc8b87d95..b53345591c 100644
--- a/elf/tst-protected1b.c
+++ b/elf/tst-protected1b.c
@@ -7,7 +7,7 @@
4. Symbol, protected2, defined in main, is used in main.
5. Symbol, protected3, defined in modb, is also used in main.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
@@ -40,10 +40,8 @@ extern int do_test (void);
int protected2 = -1;
-#define TEST_FUNCTION do_test ()
-
/* This defines the `main' function and some more. */
-#include <test-skeleton.c>
+#include <support/test-driver.c>
int
do_test (void)
diff --git a/elf/tst-protected1mod.h b/elf/tst-protected1mod.h
index 71683ae86b..0639091074 100644
--- a/elf/tst-protected1mod.h
+++ b/elf/tst-protected1mod.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2015-2018 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
diff --git a/elf/tst-protected1moda.c b/elf/tst-protected1moda.c
index 915bb1f3ff..c6cf79f8ff 100644
--- a/elf/tst-protected1moda.c
+++ b/elf/tst-protected1moda.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2015-2018 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
diff --git a/elf/tst-protected1modb.c b/elf/tst-protected1modb.c
index c20e8606f3..7343410692 100644
--- a/elf/tst-protected1modb.c
+++ b/elf/tst-protected1modb.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2015-2018 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
diff --git a/elf/tst-ptrguard1.c b/elf/tst-ptrguard1.c
index c9d80df758..78b78b8523 100644
--- a/elf/tst-ptrguard1.c
+++ b/elf/tst-ptrguard1.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2013-2018 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
@@ -25,6 +25,12 @@
#include <tls.h>
#include <unistd.h>
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+/* Requires _GNU_SOURCE */
+#include <getopt.h>
+
#ifndef POINTER_CHK_GUARD
extern uintptr_t __pointer_chk_guard;
# define POINTER_CHK_GUARD __pointer_chk_guard
@@ -191,12 +197,21 @@ do_test (void)
#define CMDLINE_OPTIONS \
{ "command", required_argument, NULL, OPT_COMMAND }, \
{ "child", no_argument, NULL, OPT_CHILD },
-#define CMDLINE_PROCESS \
- case OPT_COMMAND: \
- command = optarg; \
- break; \
- case OPT_CHILD: \
- child = true; \
- break;
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+
+static void __attribute((used))
+cmdline_process_function (int c)
+{
+ switch (c)
+ {
+ case OPT_COMMAND:
+ command = optarg;
+ break;
+ case OPT_CHILD:
+ child = true;
+ break;
+ }
+}
+
+#define CMDLINE_PROCESS cmdline_process_function
+
+#include <support/test-driver.c>
diff --git a/elf/tst-relsort1.c b/elf/tst-relsort1.c
index a87b138280..775c968e1f 100644
--- a/elf/tst-relsort1.c
+++ b/elf/tst-relsort1.c
@@ -15,5 +15,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-rtld-load-self.sh b/elf/tst-rtld-load-self.sh
index aa97ee6ca9..b33f6fc441 100755
--- a/elf/tst-rtld-load-self.sh
+++ b/elf/tst-rtld-load-self.sh
@@ -1,6 +1,6 @@
#!/bin/sh
# Test how rtld loads itself.
-# Copyright (C) 2012-2016 Free Software Foundation, Inc.
+# Copyright (C) 2012-2018 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
#
diff --git a/elf/tst-stackguard1.c b/elf/tst-stackguard1.c
index cc95e227ea..8479d8c422 100644
--- a/elf/tst-stackguard1.c
+++ b/elf/tst-stackguard1.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2005-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
@@ -17,6 +17,7 @@
<http://www.gnu.org/licenses/>. */
#include <errno.h>
+#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -185,12 +186,20 @@ do_test (void)
#define CMDLINE_OPTIONS \
{ "command", required_argument, NULL, OPT_COMMAND }, \
{ "child", no_argument, NULL, OPT_CHILD },
-#define CMDLINE_PROCESS \
- case OPT_COMMAND: \
- command = optarg; \
- break; \
- case OPT_CHILD: \
- child = true; \
- break;
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+
+static void __attribute__((used))
+cmdline_process_function (int c)
+{
+ switch (c)
+ {
+ case OPT_COMMAND:
+ command = optarg;
+ break;
+ case OPT_CHILD:
+ child = true;
+ break;
+ }
+}
+#define CMDLINE_PROCESS cmdline_process_function
+
+#include <support/test-driver.c>
diff --git a/elf/tst-thrlock.c b/elf/tst-thrlock.c
index fe72eba141..1beffc3861 100644
--- a/elf/tst-thrlock.c
+++ b/elf/tst-thrlock.c
@@ -55,5 +55,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls-dlinfo.c b/elf/tst-tls-dlinfo.c
index 28661b19c2..7d2b42e2ab 100644
--- a/elf/tst-tls-dlinfo.c
+++ b/elf/tst-tls-dlinfo.c
@@ -3,7 +3,6 @@
#include <stdlib.h>
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -83,4 +82,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls-manydynamic.c b/elf/tst-tls-manydynamic.c
new file mode 100644
index 0000000000..185395c3cd
--- /dev/null
+++ b/elf/tst-tls-manydynamic.c
@@ -0,0 +1,151 @@
+/* Test with many dynamic TLS variables.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This test intends to exercise dynamic TLS variable allocation. It
+ achieves this by combining dlopen (to avoid static TLS allocation
+ after static TLS resizing), many DSOs with a large variable (to
+ exceed the static TLS reserve), and an already-running thread (to
+ force full dynamic TLS initialization). */
+
+#include "tst-tls-manydynamic.h"
+
+#include <errno.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int do_test (void);
+#include <support/xthread.h>
+#include <support/test-driver.c>
+
+void *handles[COUNT];
+set_value_func set_value_funcs[COUNT];
+get_value_func get_value_funcs[COUNT];
+
+static void
+init_functions (void)
+{
+ for (int i = 0; i < COUNT; ++i)
+ {
+ /* Open the module. */
+ {
+ char soname[100];
+ snprintf (soname, sizeof (soname), "tst-tls-manydynamic%02dmod.so", i);
+ handles[i] = dlopen (soname, RTLD_LAZY);
+ if (handles[i] == NULL)
+ {
+ printf ("error: dlopen failed: %s\n", dlerror ());
+ exit (1);
+ }
+ }
+
+ /* Obtain the setter function. */
+ {
+ char fname[100];
+ snprintf (fname, sizeof (fname), "set_value_%02d", i);
+ void *func = dlsym (handles[i], fname);
+ if (func == NULL)
+ {
+ printf ("error: dlsym: %s\n", dlerror ());
+ exit (1);
+ }
+ set_value_funcs[i] = func;
+ }
+
+ /* Obtain the getter function. */
+ {
+ char fname[100];
+ snprintf (fname, sizeof (fname), "get_value_%02d", i);
+ void *func = dlsym (handles[i], fname);
+ if (func == NULL)
+ {
+ printf ("error: dlsym: %s\n", dlerror ());
+ exit (1);
+ }
+ get_value_funcs[i] = func;
+ }
+ }
+}
+
+static pthread_barrier_t barrier;
+
+/* Running thread which forces real TLS initialization. */
+static void *
+blocked_thread_func (void *closure)
+{
+ xpthread_barrier_wait (&barrier);
+
+ /* TLS test runs here in the main thread. */
+
+ xpthread_barrier_wait (&barrier);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ {
+ int ret = pthread_barrier_init (&barrier, NULL, 2);
+ if (ret != 0)
+ {
+ errno = ret;
+ printf ("error: pthread_barrier_init: %m\n");
+ exit (1);
+ }
+ }
+
+ pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL);
+ xpthread_barrier_wait (&barrier);
+
+ init_functions ();
+
+ struct value values[COUNT];
+ /* Initialze the TLS variables. */
+ for (int i = 0; i < COUNT; ++i)
+ {
+ for (int j = 0; j < PER_VALUE_COUNT; ++j)
+ values[i].num[j] = rand ();
+ set_value_funcs[i] (&values[i]);
+ }
+
+ /* Read back their values to check that they do not overlap. */
+ for (int i = 0; i < COUNT; ++i)
+ {
+ struct value actual;
+ get_value_funcs[i] (&actual);
+
+ for (int j = 0; j < PER_VALUE_COUNT; ++j)
+ if (actual.num[j] != values[i].num[j])
+ {
+ printf ("error: mismatch at variable %d/%d: %d != %d\n",
+ i, j, actual.num[j], values[i].num[j]);
+ exit (1);
+ }
+ }
+
+ xpthread_barrier_wait (&barrier);
+ xpthread_join (blocked_thread);
+
+ /* Close the modules. */
+ for (int i = 0; i < COUNT; ++i)
+ dlclose (handles[i]);
+
+ return 0;
+}
diff --git a/elf/tst-tls-manydynamic.h b/elf/tst-tls-manydynamic.h
new file mode 100644
index 0000000000..fa211b6213
--- /dev/null
+++ b/elf/tst-tls-manydynamic.h
@@ -0,0 +1,44 @@
+/* Interfaces for test with many dynamic TLS variables.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef TST_TLS_MANYDYNAMIC_H
+#define TST_TLS_MANYDYNAMIC_H
+
+enum
+ {
+ /* This many TLS variables (and modules) are defined. */
+ COUNT = 100,
+
+ /* Number of elements in the TLS variable. */
+ PER_VALUE_COUNT = 1,
+ };
+
+/* The TLS variables are of this type. We use a larger type to ensure
+ that we can reach the static TLS limit with COUNT variables. */
+struct value
+{
+ int num[PER_VALUE_COUNT];
+};
+
+/* Set the TLS variable defined in the module. */
+typedef void (*set_value_func) (const struct value *);
+
+/* Read the TLS variable defined in the module. */
+typedef void (*get_value_func) (struct value *);
+
+#endif /* TST_TLS_MANYDYNAMICMOD_H */
diff --git a/elf/tst-tls-manydynamicmod.c b/elf/tst-tls-manydynamicmod.c
new file mode 100644
index 0000000000..94adbde4e5
--- /dev/null
+++ b/elf/tst-tls-manydynamicmod.c
@@ -0,0 +1,36 @@
+/* Module for test with many dynamic TLS variables.
+ Copyright (C) 2016-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is parameterized by macros NAME, SETTER, GETTER, which
+ are set form the Makefile. */
+
+#include "tst-tls-manydynamic.h"
+
+__thread struct value NAME;
+
+void
+SETTER (const struct value *value)
+{
+ NAME = *value;
+}
+
+void
+GETTER (struct value *value)
+{
+ *value = NAME;
+}
diff --git a/elf/tst-tls1-static-non-pie.c b/elf/tst-tls1-static-non-pie.c
new file mode 100644
index 0000000000..a01008073b
--- /dev/null
+++ b/elf/tst-tls1-static-non-pie.c
@@ -0,0 +1 @@
+#include "tst-tls1.c"
diff --git a/elf/tst-tls1.c b/elf/tst-tls1.c
index bec0a2ff26..c31da56ce9 100644
--- a/elf/tst-tls1.c
+++ b/elf/tst-tls1.c
@@ -9,7 +9,6 @@ COMMON_INT_DEF(foo);
COMMON_INT_DEF(bar);
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -80,4 +79,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls10.c b/elf/tst-tls10.c
index eb1ecb9216..d9611aac6d 100644
--- a/elf/tst-tls10.c
+++ b/elf/tst-tls10.c
@@ -36,5 +36,4 @@ do_test (void)
exit (0);
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls11.c b/elf/tst-tls11.c
index 8ceac14168..a5c3dd70b0 100644
--- a/elf/tst-tls11.c
+++ b/elf/tst-tls11.c
@@ -25,5 +25,4 @@ do_test (void)
exit (0);
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls12.c b/elf/tst-tls12.c
index 8093894b93..ccd5f8b43e 100644
--- a/elf/tst-tls12.c
+++ b/elf/tst-tls12.c
@@ -16,5 +16,4 @@ do_test (void)
exit (0);
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls13.c b/elf/tst-tls13.c
index 06bfbacb5c..b1d303310f 100644
--- a/elf/tst-tls13.c
+++ b/elf/tst-tls13.c
@@ -25,6 +25,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#define TIMEOUT 3
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls14.c b/elf/tst-tls14.c
index 6bacb599dd..a6a79ef24f 100644
--- a/elf/tst-tls14.c
+++ b/elf/tst-tls14.c
@@ -51,5 +51,4 @@ do_test (void)
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls15.c b/elf/tst-tls15.c
index 7ac963aa2d..db2a4f4b77 100644
--- a/elf/tst-tls15.c
+++ b/elf/tst-tls15.c
@@ -1,4 +1,5 @@
#include <dlfcn.h>
+#include <stdlib.h>
#include <stdio.h>
static int
@@ -28,5 +29,4 @@ do_test (void)
return fp ();
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls16.c b/elf/tst-tls16.c
index b3519858a0..f2830b8a4f 100644
--- a/elf/tst-tls16.c
+++ b/elf/tst-tls16.c
@@ -1,4 +1,5 @@
#include <dlfcn.h>
+#include <stdlib.h>
#include <stdio.h>
static int
@@ -48,5 +49,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls17.c b/elf/tst-tls17.c
index c768fb6a5b..c2a972d3c4 100644
--- a/elf/tst-tls17.c
+++ b/elf/tst-tls17.c
@@ -1,4 +1,5 @@
#include <dlfcn.h>
+#include <stdlib.h>
#include <stdio.h>
static int
@@ -24,5 +25,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls18.c b/elf/tst-tls18.c
index 96b8e6bf7b..b705b61d60 100644
--- a/elf/tst-tls18.c
+++ b/elf/tst-tls18.c
@@ -1,4 +1,5 @@
#include <dlfcn.h>
+#include <stdlib.h>
#include <stdio.h>
static int
@@ -33,5 +34,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls19.c b/elf/tst-tls19.c
index acbc1d6964..dd8ea42c3f 100644
--- a/elf/tst-tls19.c
+++ b/elf/tst-tls19.c
@@ -23,5 +23,4 @@ do_test (void)
return fn ();
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls2.c b/elf/tst-tls2.c
index d0b6d51402..963b8d6c88 100644
--- a/elf/tst-tls2.c
+++ b/elf/tst-tls2.c
@@ -9,7 +9,6 @@ VAR_INT_DEF(foo);
VAR_INT_DEF(bar);
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -80,4 +79,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls3.c b/elf/tst-tls3.c
index ca96c6a073..7e0abb4c58 100644
--- a/elf/tst-tls3.c
+++ b/elf/tst-tls3.c
@@ -13,7 +13,6 @@ VAR_INT_DEF(baz);
extern int in_dso (void);
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -65,4 +64,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls4.c b/elf/tst-tls4.c
index 63170c3478..6841f81386 100644
--- a/elf/tst-tls4.c
+++ b/elf/tst-tls4.c
@@ -3,7 +3,6 @@
#include <stdlib.h>
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -47,4 +46,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls5.c b/elf/tst-tls5.c
index 76905c56db..5f006fd645 100644
--- a/elf/tst-tls5.c
+++ b/elf/tst-tls5.c
@@ -3,7 +3,6 @@
#include <stdlib.h>
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -63,4 +62,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls6.c b/elf/tst-tls6.c
index 9e6235f1d3..df81c1f6b4 100644
--- a/elf/tst-tls6.c
+++ b/elf/tst-tls6.c
@@ -5,7 +5,6 @@
#include <link.h>
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -82,4 +81,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls7.c b/elf/tst-tls7.c
index 23a16e4489..fa46709600 100644
--- a/elf/tst-tls7.c
+++ b/elf/tst-tls7.c
@@ -5,7 +5,6 @@
#include <link.h>
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -53,4 +52,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls8.c b/elf/tst-tls8.c
index 4bf3e3ffb5..c779572617 100644
--- a/elf/tst-tls8.c
+++ b/elf/tst-tls8.c
@@ -5,7 +5,6 @@
#include <link.h>
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -165,5 +164,4 @@ do_test (void)
return result;
}
-
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tls9.c b/elf/tst-tls9.c
index 6306fb5658..ee21b47c70 100644
--- a/elf/tst-tls9.c
+++ b/elf/tst-tls9.c
@@ -4,7 +4,6 @@
#include <link.h>
-#define TEST_FUNCTION do_test ()
static int
do_test (void)
{
@@ -34,4 +33,4 @@ do_test (void)
}
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tlsalign-extern.c b/elf/tst-tlsalign-extern.c
index 5c09f8b99c..30dffbb598 100644
--- a/elf/tst-tlsalign-extern.c
+++ b/elf/tst-tlsalign-extern.c
@@ -1,5 +1,5 @@
/* Test for large alignment in TLS blocks (extern case), BZ#18383.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
@@ -70,5 +70,4 @@ do_test (void)
return fail ? EXIT_FAILURE : EXIT_SUCCESS;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-tlsalign.c b/elf/tst-tlsalign.c
index b8e64d258e..f16ab6080f 100644
--- a/elf/tst-tlsalign.c
+++ b/elf/tst-tlsalign.c
@@ -1,5 +1,5 @@
/* Test for large alignment in TLS blocks, BZ#18383.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2018 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
@@ -81,5 +81,4 @@ do_test (void)
return fail ? EXIT_FAILURE : EXIT_SUCCESS;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-unique1.c b/elf/tst-unique1.c
index 17af6f1b18..b5e53e49a0 100644
--- a/elf/tst-unique1.c
+++ b/elf/tst-unique1.c
@@ -70,5 +70,4 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/tst-unique2.c b/elf/tst-unique2.c
index 442675458b..e0173b7bcc 100644
--- a/elf/tst-unique2.c
+++ b/elf/tst-unique2.c
@@ -24,5 +24,4 @@ do_test (void)
return f (&var);
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/elf/vismain.c b/elf/vismain.c
index a2be34e2f3..e62118c5d4 100644
--- a/elf/vismain.c
+++ b/elf/vismain.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2000-2018 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
@@ -29,10 +29,9 @@
/* Prototype for our test function. */
extern int do_test (void);
-#define TEST_FUNCTION do_test ()
/* This defines the `main' function and some more. */
-#include <test-skeleton.c>
+#include <support/test-driver.c>
/* Prototypes for local functions. */
diff --git a/elf/vismod1.c b/elf/vismod1.c
index cf2d2b521c..7a62b54771 100644
--- a/elf/vismod1.c
+++ b/elf/vismod1.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2000-2018 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
diff --git a/elf/vismod2.c b/elf/vismod2.c
index 45e662e07f..962b7c95f6 100644
--- a/elf/vismod2.c
+++ b/elf/vismod2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2000-2018 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
diff --git a/elf/vismod3.c b/elf/vismod3.c
index 51f3cf877e..ba427ea9df 100644
--- a/elf/vismod3.c
+++ b/elf/vismod3.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2000-2018 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