Add 2 test cases to validate the fix for issue #3179, where the linux-user
ELF Loader incorrectly rejected binaries with .bss sections in R_X PT_LOAD
segments.
test-zerobss-1.c: defines a minimal _start routine that exists immediately
without accessing the .bss region. Although a .bss region is present in ELF,
it is never referenced at runtime. This test validates that the loader can
correctly handle and zero the fractional .bss region in an R_X segment
without triggering permission violations.
test-zerobss-2.c: explicitly reads from multiple .bss variables to verify
they are zeroed properly. If the .bss was correctly zeroed, the exit code will
be 0.
rx_anonymous_bss.ld: tests require a custom linker script to create the specific ELF
layout that triggers the bug. The linker script:
- creates a single PT_LOAD segment with FLAGS(5) = PF_R | PF_X (read-execute)
- places .text and .bss in this same segment
- sets .bss to ALIGN(1) to force it into the tail of the R_X segment
- results in p_filesz < p_memsz, where the gap is anonymous .bss
Expected behavior:
- Without the fix: Both tests fail with "PT_LOAD with non-writable bss"
- With the fix: Both tests pass (exit code 0)
Signed-off-by: Razvan Ghiorghe <razvanghiorghe16@gmail.com>
---
tests/tcg/x86_64/Makefile.target | 15 ++++++++++++
tests/tcg/x86_64/rx_anonymous_bss.ld | 27 +++++++++++++++++++++
tests/tcg/x86_64/test-zerobss-1.c | 20 ++++++++++++++++
tests/tcg/x86_64/test-zerobss-2.c | 36 ++++++++++++++++++++++++++++
4 files changed, 98 insertions(+)
create mode 100644 tests/tcg/x86_64/rx_anonymous_bss.ld
create mode 100644 tests/tcg/x86_64/test-zerobss-1.c
create mode 100644 tests/tcg/x86_64/test-zerobss-2.c
diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
index be20fc64e8..ca375a4318 100644
--- a/tests/tcg/x86_64/Makefile.target
+++ b/tests/tcg/x86_64/Makefile.target
@@ -19,6 +19,9 @@ X86_64_TESTS += test-1648
X86_64_TESTS += test-2175
X86_64_TESTS += cross-modifying-code
X86_64_TESTS += fma
+
+X86_64_TESTS += test-zerobss-1
+X86_64_TESTS += test-zerobss-2
TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
else
TESTS=$(MULTIARCH_TESTS)
@@ -36,5 +39,17 @@ test-x86_64: LDFLAGS+=-lm -lc
test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
+test-zerobss-1: $(SRC_PATH)/tests/tcg/x86_64/test-zerobss-1.c
+ $(CC) -nostdlib -static -fno-stack-protector -fno-pie -no-pie \
+ -Wl,-T,$(SRC_PATH)/tests/tcg/x86_64/rx_anonymous_bss.ld \
+ -Wl,--build-id=none \
+ $< -o $@
+
+test-zerobss-2: $(SRC_PATH)/tests/tcg/x86_64/test-zerobss-2.c
+ $(CC) -nostdlib -static -fno-stack-protector -fno-pie -no-pie \
+ -Wl,-T,$(SRC_PATH)/tests/tcg/x86_64/rx_anonymous_bss.ld \
+ -Wl,--build-id=none \
+ $< -o $@
+
%: $(SRC_PATH)/tests/tcg/x86_64/%.c
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
diff --git a/tests/tcg/x86_64/rx_anonymous_bss.ld b/tests/tcg/x86_64/rx_anonymous_bss.ld
new file mode 100644
index 0000000000..3ec72fde6c
--- /dev/null
+++ b/tests/tcg/x86_64/rx_anonymous_bss.ld
@@ -0,0 +1,27 @@
+/* Linker script to create RX PT_LOAD with anonymous .bss tail
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+PHDRS
+{
+ text PT_LOAD FLAGS(5);
+}
+SECTIONS
+{
+ . = 0x400000;
+ .text : {
+ *(.text .text.*)
+ _etext = .;
+ } :text
+ .bss ALIGN(1) : {
+ _bss_start = .;
+ *(.bss .bss.* COMMON)
+ _bss_end = .;
+ } :text
+ /DISCARD/ : {
+ *(.note.GNU-stack)
+ *(.note.gnu.property)
+ *(.comment)
+ *(.eh_frame)
+ }
+}
+ENTRY(_start)
diff --git a/tests/tcg/x86_64/test-zerobss-1.c b/tests/tcg/x86_64/test-zerobss-1.c
new file mode 100644
index 0000000000..809ea3cb52
--- /dev/null
+++ b/tests/tcg/x86_64/test-zerobss-1.c
@@ -0,0 +1,20 @@
+ /*
+ * .bss region exists but unused
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+int x;
+void _start(void)
+{
+ /*
+ * Exit immediately & never touched x
+ */
+ __asm__ volatile(
+ "mov $60, %%rax\n"
+ "xor %%rdi, %%rdi\n"
+ "syscall\n"
+ : /* no out */
+ : /* no in */
+ : "rax", "rdi"
+ );
+ __builtin_unreachable();
+}
diff --git a/tests/tcg/x86_64/test-zerobss-2.c b/tests/tcg/x86_64/test-zerobss-2.c
new file mode 100644
index 0000000000..1f4f0d9704
--- /dev/null
+++ b/tests/tcg/x86_64/test-zerobss-2.c
@@ -0,0 +1,36 @@
+/*
+ * Test case for zero_bss() with anonymous BSS in RX PT_LOAD
+ *
+ * This binary has .bss in the same PT_LOAD as .text (R_X permissions),
+ * but the BSS is anonymous (beyond p_filesz), not file-backed.
+ * Actual behavior:
+ * old code: Fails with "PT_LOAD with non-writable bss"
+ * new code: Succeeds, zeros BSS, exits with code 0
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/* These will be included in .bss (uninitialized anonymous memory) */
+int bss_value;
+int bss_array[64];
+
+void _start(void)
+{
+ int sum = bss_value;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ sum += bss_array[i];
+ }
+ /* If BSS was properly zeroed, sum should be 0 */
+ /* Exit with sum as exit code */
+ __asm__ volatile (
+ "movl %0, %%edi\n\t"
+ "movl $60, %%eax\n\t"
+ "syscall\n\t"
+ : /* no out*/
+ : "r" (sum)
+ : "rdi", "rax"
+ );
+
+ __builtin_unreachable();
+}
--
2.43.0