From e4f898c4a6b9900553c64b9804889b5fdae3e55f Mon Sep 17 00:00:00 2001 From: bitflash-maintainer Date: Wed, 2 Sep 2026 05:16:33 +0000 Subject: build: keep the stack non-executable, whoever links this RandomX links jit_compiler_x86_static.S, a hand-written assembly stub with no .note.GNU-stack marker. binutils reads a missing marker as a request for an executable stack, and older linkers grant it for the whole binary: NX off, process-wide, for a node that parses attacker-supplied blocks and messages. The same source therefore produced different security properties depending on where it was built. Ubuntu 26.04 gave GNU_STACK RW; Debian 12 -- the build target for the deploy image, because it is the oldest glibc we ship to and the last Debian that still packages the Berkeley DB C++ binding -- gave RWE. The only announcement was a linker warning in the middle of an otherwise clean build. -z noexecstack settles it in the tree instead of in the toolchain. RandomX's JIT maps its own W^X pages and never executes from the stack, so nothing that works today stops working. Both link lines take it, GUI and headless. Verify: readelf -lW bitflash-node | grep -A1 GNU_STACK # expect RW --- src/Makefile | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/Makefile') diff --git a/src/Makefile b/src/Makefile index b068376..1bc3ae8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -100,7 +100,7 @@ obj/imgui_impl_opengl3.o: $(IMGUI_DIR)/imgui_impl_opengl3.cpp $(CXX) -c $(CXXFLAGS) -o $@ $< bitflash: $(IMGUI_OBJS) $(NODE_OBJS) $(GUI_OBJS) - $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS) + $(CXX) $(CXXFLAGS) $(LDHARDFLAGS) -o $@ $^ $(LIBS) @echo "Built: bitflash" # ---- headless node --------------------------------------------------------- @@ -114,6 +114,20 @@ bitflash: $(IMGUI_OBJS) $(NODE_OBJS) $(GUI_OBJS) # Objects go to obj-node/ because main_gui.cpp is compiled twice, with and # without -DBITFLASH_NO_GUI, and the two must not overwrite each other. +# RandomX links a hand-written assembly JIT stub, jit_compiler_x86_static.S, +# which carries no .note.GNU-stack marker. Older binutils -- Debian 12's, which +# is what builds against the oldest glibc we ship to -- reads a missing marker +# as "this object wants an executable stack" and marks the whole binary RWE, +# switching NX off for the process. Newer toolchains default the other way, so +# identical source produced GNU_STACK RW on Ubuntu 26.04 and RWE on bookworm, +# announced by nothing louder than a linker warning in the middle of the build. +# +# Assert it here rather than inherit whichever default the build host happens +# to carry. The JIT maps its own W^X pages and never executes from the stack, +# so nothing needs the permission this takes away. Check with: +# readelf -lW bitflash-node | grep -A1 GNU_STACK # expect RW, not RWE +LDHARDFLAGS = -Wl,-z,noexecstack + NODE_LIBS = -L$(SECP_LIB) -lsecp256k1 \ -L$(RANDOMX_DIR)/build -lrandomx \ -lsodium -lssl -lcrypto -ldb_cxx -lpthread @@ -134,7 +148,7 @@ obj-node/sha.o: sha.cpp sha.h $(CXX) -c $(CXXFLAGS) -DBITFLASH_NO_GUI -O3 -o $@ $< bitflash-node: $(NODE_ONLY_OBJS) - $(CXX) $(CXXFLAGS) -o $@ $^ $(NODE_LIBS) + $(CXX) $(CXXFLAGS) $(LDHARDFLAGS) -o $@ $^ $(NODE_LIBS) @echo "Built: bitflash-node (headless, no libGL needed)" obj-fuzz/%.o: %.cpp $(HEADERS) -- cgit v1.2.3