diff options
Diffstat (limited to 'elf')
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) @@ -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 @@ -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 |