From ccfd26ef14ea213320f0b49db3fb347785b38f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 14 Dec 2020 07:59:40 +0100 Subject: [PATCH] bintools-wrapper: skip dynamic linker for static binaries Currently we set dynamic-linker unconditionally. This breaks however some static binaries i.e. rust binaries linked against musl. There is no reason we should set an elf interpreter for static binaries hence this is skipped if `-static` or `-static-pie` is either passed to our cc or ld wrapper. --- .../bintools-wrapper/add-flags.sh | 5 +++++ .../bintools-wrapper/default.nix | 8 +------- .../bintools-wrapper/ld-wrapper.sh | 13 +++++++++++- pkgs/build-support/cc-wrapper/cc-wrapper.sh | 6 ++++++ pkgs/test/cc-wrapper/default.nix | 20 +++++++++++++++---- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/pkgs/build-support/bintools-wrapper/add-flags.sh b/pkgs/build-support/bintools-wrapper/add-flags.sh index e99beb38158..83d47027104 100644 --- a/pkgs/build-support/bintools-wrapper/add-flags.sh +++ b/pkgs/build-support/bintools-wrapper/add-flags.sh @@ -3,6 +3,7 @@ var_templates_list=( NIX_IGNORE_LD_THROUGH_GCC NIX_LDFLAGS NIX_LDFLAGS_BEFORE + NIX_DYNAMIC_LINKER NIX_LDFLAGS_AFTER NIX_LDFLAGS_HARDEN NIX_HARDENING_ENABLE @@ -25,6 +26,10 @@ if [ -e @out@/nix-support/libc-ldflags ]; then NIX_LDFLAGS_@suffixSalt@+=" $(< @out@/nix-support/libc-ldflags)" fi +if [ -z "$NIX_DYNAMIC_LINKER_@suffixSalt@" ] && [ -e @out@/nix-support/dynamic-linker ]; then + NIX_DYNAMIC_LINKER_@suffixSalt@="$(< @out@/nix-support/dynamic-linker)" +fi + if [ -e @out@/nix-support/libc-ldflags-before ]; then NIX_LDFLAGS_BEFORE_@suffixSalt@="$(< @out@/nix-support/libc-ldflags-before) $NIX_LDFLAGS_BEFORE_@suffixSalt@" fi diff --git a/pkgs/build-support/bintools-wrapper/default.nix b/pkgs/build-support/bintools-wrapper/default.nix index 6da0e58436d..21c66521fb2 100644 --- a/pkgs/build-support/bintools-wrapper/default.nix +++ b/pkgs/build-support/bintools-wrapper/default.nix @@ -243,13 +243,7 @@ stdenv.mkDerivation { if [ -e ${libc_lib}/lib/32/ld-linux.so.2 ]; then echo ${libc_lib}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32 fi - '' - # The dynamic linker is passed in `ldflagsBefore' to allow - # explicit overrides of the dynamic linker by callers to ld - # (the *last* value counts, so ours should come first). - + '' - echo -dynamic-linker "$dynamicLinker" >> $out/nix-support/libc-ldflags-before - '') + '' + '') + '' fi '') diff --git a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh index 81b5a90edd5..abecf6a8e5d 100644 --- a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh +++ b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh @@ -20,6 +20,7 @@ if [ -z "${NIX_BINTOOLS_WRAPPER_FLAGS_SET_@suffixSalt@:-}" ]; then source @out@/nix-support/add-flags.sh fi +setDynamicLinker=1 # Optionally filter out paths not refering to the store. expandResponseParams "$@" @@ -47,6 +48,11 @@ if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "${NIX_STORE:-}" # Our ld is not built with sysroot support (Can we fix that?) : else + if [[ "$p" = -static || "$p" = -static-pie ]]; then + # Using a dynamic linker for static binaries can lead to crashes. + # This was observed for rust binaries. + setDynamicLinker=0 + fi rest+=("$p") fi n+=1 @@ -63,6 +69,11 @@ extraBefore=(${hardeningLDFlags[@]+"${hardeningLDFlags[@]}"}) if [ -z "${NIX_LDFLAGS_SET_@suffixSalt@:-}" ]; then extraAfter+=($NIX_LDFLAGS_@suffixSalt@) extraBefore+=($NIX_LDFLAGS_BEFORE_@suffixSalt@) + # By adding dynamic linker to extraBefore we allow the users set their + # own dynamic linker as NIX_LD_FLAGS will override earlier set flags + if [ "$setDynamicLinker" = 1 ]; then + extraBefore+=("-dynamic-linker" "$NIX_DYNAMIC_LINKER_@suffixSalt@") + fi fi extraAfter+=($NIX_LDFLAGS_AFTER_@suffixSalt@) @@ -134,7 +145,7 @@ then done fi -if [ -e "@out@/nix-support/dynamic-linker-m32" ] && (( "$link32" )); then +if [[ "$link32" = "0" && "$setDynamicLinker" = 1 && -e "@out@/nix-support/dynamic-linker-m32" ]]; then # We have an alternate 32-bit linker and we're producing a 32-bit ELF, let's # use it. extraAfter+=( diff --git a/pkgs/build-support/cc-wrapper/cc-wrapper.sh b/pkgs/build-support/cc-wrapper/cc-wrapper.sh index 7e734f57773..1c60beb9bf5 100644 --- a/pkgs/build-support/cc-wrapper/cc-wrapper.sh +++ b/pkgs/build-support/cc-wrapper/cc-wrapper.sh @@ -28,6 +28,7 @@ cc1=0 [[ "@prog@" = *++ ]] && isCpp=1 || isCpp=0 cppInclude=1 cInclude=1 +setDynamicLinker=1 expandResponseParams "$@" declare -i n=0 @@ -58,6 +59,8 @@ while (( "$n" < "$nParams" )); do cppInclude=0 elif [ "$p" = -nostdinc++ ]; then cppInclude=0 + elif [[ "$p" = -static || "$p" = -static-pie ]]; then + setDynamicLinker=0 elif [[ "$p" != -?* ]]; then # A dash alone signifies standard input; it is not a flag nonFlagArgs=1 @@ -152,6 +155,9 @@ if [ "$dontLink" != 1 ]; then for i in $NIX_LDFLAGS_BEFORE_@suffixSalt@; do extraBefore+=("-Wl,$i") done + if [ "$setDynamicLinker" = 1 ]; then + extraBefore+=("-Wl,-dynamic-linker=$NIX_DYNAMIC_LINKER_@suffixSalt@") + fi for i in $NIX_LDFLAGS_@suffixSalt@; do if [ "${i:0:3}" = -L/ ]; then extraAfter+=("$i") diff --git a/pkgs/test/cc-wrapper/default.nix b/pkgs/test/cc-wrapper/default.nix index c0c89d63fff..141a5320ef5 100644 --- a/pkgs/test/cc-wrapper/default.nix +++ b/pkgs/test/cc-wrapper/default.nix @@ -1,11 +1,13 @@ -{ stdenv }: +{ stdenv, glibc }: with stdenv.lib; let # Sanitizers are not supported on Darwin. # Sanitizer headers aren't available in older libc++ stdenvs due to a bug - sanitizersWorking = - (stdenv.cc.isClang && versionAtLeast (getVersion stdenv.cc.name) "5.0.0") - || (stdenv.cc.isGNU && stdenv.isLinux); + sanitizersWorking = !stdenv.hostPlatform.isMusl && ( + (stdenv.cc.isClang && versionAtLeast (getVersion stdenv.cc.name) "5.0.0") + || (stdenv.cc.isGNU && stdenv.isLinux) + ); + staticLibc = optionalString (stdenv.hostPlatform.libc == "glibc") "-L ${glibc.static}/lib"; in stdenv.mkDerivation { name = "cc-wrapper-test"; @@ -28,6 +30,16 @@ in stdenv.mkDerivation { ./core-foundation-check ''} + printf "checking whether compiler builds valid static C binaries... " >&2 + $CC ${staticLibc} -static -o cc-static ${./cc-main.c} + ./cc-static + # our glibc does not have pie enabled yet. + ${optionalString (stdenv.hostPlatform.isMusl && stdenv.cc.isGNU) '' + printf "checking whether compiler builds valid static pie C binaries... " >&2 + $CC ${staticLibc} -static-pie -o cc-static-pie ${./cc-main.c} + ./cc-static-pie + ''} + printf "checking whether compiler uses NIX_CFLAGS_COMPILE... " >&2 mkdir -p foo/include cp ${./foo.c} foo/include/foo.h