From 9a9d1ec6f4536ffeb745f360ef010cefd125bfd0 Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Wed, 29 Dec 2021 17:47:12 -0800 Subject: [PATCH 1/6] Mark Huffman Decoder Assembly `noexecstack` on All Architectures Apparently, even when the assembly file is empty (because `ZSTD_ENABLE_ASM_X86_64_BMI2` is false), it still is marked as possibly needing an executable stack and so the whole library is marked as such. This commit applies a simple patch for this problem by moving the noexecstack indication outside the macro guard. This commit builds on #2857. This commit addresses #2963. --- lib/decompress/huf_decompress_amd64.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/decompress/huf_decompress_amd64.S b/lib/decompress/huf_decompress_amd64.S index 98173cce863..706786bb0db 100644 --- a/lib/decompress/huf_decompress_amd64.S +++ b/lib/decompress/huf_decompress_amd64.S @@ -1,7 +1,5 @@ #include "../common/portability_macros.h" -#if ZSTD_ENABLE_ASM_X86_64_BMI2 - /* Stack marking * ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */ @@ -9,6 +7,8 @@ .section .note.GNU-stack,"",%progbits #endif +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + /* Calling convention: * * %rdi contains the first argument: HUF_DecompressAsmArgs*. From 35208f702f0a5e4ebe70d651efd75770f176b2d0 Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Wed, 29 Dec 2021 18:42:32 -0800 Subject: [PATCH 2/6] Add Test Validating Stack is not Executable in playTests.sh --- tests/playTests.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/playTests.sh b/tests/playTests.sh index a772b61ff7c..e1da24a4b06 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -304,6 +304,15 @@ zstd -d -f tmp_corrupt.zst --no-check zstd -d -f tmp_corrupt.zst --check --no-check # final flag overrides zstd -d -f tmp.zst --no-check +if [ "$isWindows" = false ]; then + if [ -n "$(which readelf)" ]; then + println "test: check if binary has executable stack" + file "$ZSTD_BIN" + readelf -lW "$ZSTD_BIN" + readelf -lW "$ZSTD_BIN" | grep 'GNU_STACK .* RW ' || die "zstd binary has executable stack!" + fi +fi + println "\n===> zstdgrep tests" ln -sf "$ZSTD_BIN" zstdcat rm -f tmp_grep From 4620ce6a9abe7f2aad9ae0ecd4768cd38491edb8 Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Wed, 5 Jan 2022 14:53:22 -0500 Subject: [PATCH 3/6] Makefiles: Add `noexecstack` Options to Compilation and Linking Hopefully this marks the binary artifacts `noexecstack` even on platforms where binaries default to true. --- lib/libzstd.mk | 28 ++++++++++++++++++++++++++++ programs/Makefile | 2 -- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/libzstd.mk b/lib/libzstd.mk index c04957c6fae..e682e446ae9 100644 --- a/lib/libzstd.mk +++ b/lib/libzstd.mk @@ -34,6 +34,8 @@ ZSTD_NO_ASM ?= 0 # libzstd helpers ################################################################## +VOID ?= /dev/null + # Make 4.3 doesn't support '\#' anymore (https://lwn.net/Articles/810071/) NUM_SYMBOL := \# @@ -96,6 +98,32 @@ CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) LDFLAGS += $(MOREFLAGS) FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) +ifndef ALREADY_APPENDED_NOEXECSTACK +export ALREADY_APPENDED_NOEXECSTACK := 1 +ifeq ($(shell echo "int main(int argc, char* argv[]) { (void)argc; (void)argv; return 0; }" | $(CC) $(FLAGS) -z noexecstack -x c -Werror - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) +$(info Supports noexecstack linker flag!) +$(info $(LDFLAGS)) +LDFLAGS += -z noexecstack +$(info $(LDFLAGS)) +else +$(info Doesn't support noexecstack linker flag!) +endif +ifeq ($(shell echo | $(CC) $(FLAGS) -Wa,--noexecstack -x assembler -Werror -c - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) +$(info Supports noexecstack assembler flag!) +$(info $(CFLAGS)) +CFLAGS += -Wa,--noexecstack +$(info $(CFLAGS)) +else ifeq ($(shell echo | $(CC) $(FLAGS) -Qunused-arguments -Wa,--noexecstack -x assembler -Werror -c - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) +# See e.g.: https://github.com/android/ndk/issues/171 +$(info Supports noexecstack assembler flag with unused arg suppression!) +$(info $(CFLAGS)) +CFLAGS += -Qunused-arguments -Wa,--noexecstack +$(info $(CFLAGS)) +else +$(info Doesn't support noexecstack assembler flag!) +endif +endif + HAVE_COLORNEVER = $(shell echo a | grep --color=never a > /dev/null 2> /dev/null && echo 1 || echo 0) GREP_OPTIONS ?= ifeq ($HAVE_COLORNEVER, 1) diff --git a/programs/Makefile b/programs/Makefile index a54900cc1e9..da848eb66bc 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -62,8 +62,6 @@ else EXT = endif -VOID = /dev/null - # thread detection NO_THREAD_MSG := ==> no threads, building without multithreading support HAVE_PTHREAD := $(shell printf '$(NUM_SYMBOL)include \nint main(void) { return 0; }' > have_pthread.c && $(CC) $(FLAGS) -o have_pthread$(EXT) have_pthread.c -pthread 2> $(VOID) && rm have_pthread$(EXT) && echo 1 || echo 0; rm have_pthread.c) From b12edddb3784c59c459a40f6108027b0bcedaf2f Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Wed, 5 Jan 2022 15:42:58 -0500 Subject: [PATCH 4/6] Write `GNU-stack` Section on All ELF Architectures Previously we did this only on Linux, which missed other Unices. --- lib/decompress/huf_decompress_amd64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/decompress/huf_decompress_amd64.S b/lib/decompress/huf_decompress_amd64.S index 706786bb0db..d2fb90ca110 100644 --- a/lib/decompress/huf_decompress_amd64.S +++ b/lib/decompress/huf_decompress_amd64.S @@ -3,7 +3,7 @@ /* Stack marking * ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */ -#if defined(__linux__) && defined(__ELF__) +#if defined(__ELF__) .section .note.GNU-stack,"",%progbits #endif From ef1f9e80ffc62c5de06375bc62012373a5d0b77f Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Wed, 5 Jan 2022 16:03:32 -0500 Subject: [PATCH 5/6] Restrict `GNU-stack` Note to GNU Assemblers --- lib/decompress/huf_decompress_amd64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/decompress/huf_decompress_amd64.S b/lib/decompress/huf_decompress_amd64.S index d2fb90ca110..0b4cd38ee10 100644 --- a/lib/decompress/huf_decompress_amd64.S +++ b/lib/decompress/huf_decompress_amd64.S @@ -3,7 +3,7 @@ /* Stack marking * ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */ -#if defined(__ELF__) +#if defined(__ELF__) && defined(__GNUC__) .section .note.GNU-stack,"",%progbits #endif From ff5d1daf33abe71f95f2c90de877ac98cf01af83 Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Wed, 5 Jan 2022 15:21:48 -0500 Subject: [PATCH 6/6] Clean Up Debugging Statements --- lib/libzstd.mk | 13 ------------- tests/playTests.sh | 4 +--- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/libzstd.mk b/lib/libzstd.mk index e682e446ae9..73a8cd5d860 100644 --- a/lib/libzstd.mk +++ b/lib/libzstd.mk @@ -101,26 +101,13 @@ FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) ifndef ALREADY_APPENDED_NOEXECSTACK export ALREADY_APPENDED_NOEXECSTACK := 1 ifeq ($(shell echo "int main(int argc, char* argv[]) { (void)argc; (void)argv; return 0; }" | $(CC) $(FLAGS) -z noexecstack -x c -Werror - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) -$(info Supports noexecstack linker flag!) -$(info $(LDFLAGS)) LDFLAGS += -z noexecstack -$(info $(LDFLAGS)) -else -$(info Doesn't support noexecstack linker flag!) endif ifeq ($(shell echo | $(CC) $(FLAGS) -Wa,--noexecstack -x assembler -Werror -c - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) -$(info Supports noexecstack assembler flag!) -$(info $(CFLAGS)) CFLAGS += -Wa,--noexecstack -$(info $(CFLAGS)) else ifeq ($(shell echo | $(CC) $(FLAGS) -Qunused-arguments -Wa,--noexecstack -x assembler -Werror -c - -o $(VOID) 2>$(VOID) && echo 1 || echo 0),1) # See e.g.: https://github.com/android/ndk/issues/171 -$(info Supports noexecstack assembler flag with unused arg suppression!) -$(info $(CFLAGS)) CFLAGS += -Qunused-arguments -Wa,--noexecstack -$(info $(CFLAGS)) -else -$(info Doesn't support noexecstack assembler flag!) endif endif diff --git a/tests/playTests.sh b/tests/playTests.sh index e1da24a4b06..695d4333ba4 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -306,9 +306,7 @@ zstd -d -f tmp.zst --no-check if [ "$isWindows" = false ]; then if [ -n "$(which readelf)" ]; then - println "test: check if binary has executable stack" - file "$ZSTD_BIN" - readelf -lW "$ZSTD_BIN" + println "test: check if binary has executable stack (#2963)" readelf -lW "$ZSTD_BIN" | grep 'GNU_STACK .* RW ' || die "zstd binary has executable stack!" fi fi