[PATCH] selftests/x86: Skip sysret_rip fall-through probes that hit the stack

From: Guixiong Wei

Date: Fri Aug 21 2026 - 06:43:40 EST


test_syscall_fallthrough_to() relocates the syscall trampoline page to a
target high address with mremap(MREMAP_MAYMOVE | MREMAP_FIXED). Like
MAP_FIXED, MREMAP_FIXED silently unmaps whatever already occupies the
destination.

The extra self-test at (1<<47) - 2*PAGE_SIZE remaps to 0x7fffffffd000,
and the i==47 interesting case at (1<<47) - PAGE_SIZE remaps to
0x7fffffffe000. Both sit just below STACK_TOP_MAX (0x7ffffffff000).
With ASLR enabled the stack is randomized elsewhere and these addresses
are free, so the remap is harmless. With ASLR disabled the stack lives
at its fixed default location and overlaps them, so the remap unmaps the
stack and the process dies with SIGSEGV (exit 139) before the test can
observe anything.

Probe the trampoline and fall-through pages with mincore() and skip any
target whose destination is already in use. With ASLR enabled -- the
default -- the stack sits elsewhere, so every case still runs. With
ASLR disabled only the two cases that collide with the stack are
skipped; the noncanonical cases that actually exercise the kernel's
SYSRET handling live far above the stack and always run.

Fixes: 660602140103 ("selftests/x86: Add a selftest for SYSRET to noncanonical addresses")
Signed-off-by: Guixiong Wei <weiguixiong@xxxxxxxxxxxxx>
---
tools/testing/selftests/x86/sysret_rip.c | 28 ++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/tools/testing/selftests/x86/sysret_rip.c b/tools/testing/selftests/x86/sysret_rip.c
index 2e423a335e1c..e4bd3ed881f4 100644
--- a/tools/testing/selftests/x86/sysret_rip.c
+++ b/tools/testing/selftests/x86/sysret_rip.c
@@ -94,6 +94,17 @@ static void sigsegv_for_fallthrough(int sig, siginfo_t *info, void *ctx_void)
siglongjmp(jmpbuf, 1);
}

+static bool address_is_mapped(unsigned long addr)
+{
+ unsigned char vec;
+
+ /*
+ * mincore() succeeds only when the whole range is mapped and fails
+ * with ENOMEM when the page is not mapped.
+ */
+ return mincore((void *)addr, 4096, &vec) == 0;
+}
+
static void test_syscall_fallthrough_to(unsigned long ip)
{
void *new_address = (void *)(ip - 4096);
@@ -101,6 +112,23 @@ static void test_syscall_fallthrough_to(unsigned long ip)

printf("[RUN]\tTrying a SYSCALL that falls through to 0x%lx\n", ip);

+ /*
+ * MREMAP_FIXED, like MAP_FIXED, silently unmaps whatever already
+ * occupies the destination. With ASLR disabled the stack lives at
+ * the top of the address space and overlaps the high addresses
+ * exercised here, so a blind remap would clobber the stack and take
+ * the test down with a SIGSEGV. Skip any target whose trampoline or
+ * landing page is already in use; the noncanonical cases that
+ * actually probe the kernel sit far above the stack and are
+ * unaffected.
+ */
+ if (address_is_mapped((unsigned long)new_address) ||
+ address_is_mapped(ip)) {
+ printf("[SKIP]\t0x%lx: address space near the stack is in use (ASLR off?)\n",
+ ip);
+ return;
+ }
+
ret = mremap((void *)current_test_page_addr, 4096, 4096,
MREMAP_MAYMOVE | MREMAP_FIXED, new_address);
if (ret == MAP_FAILED) {

base-commit: f5bbbfec59b4e2fb7520a91de3df8a6174325d6a
--
2.50.1 (Apple Git-155)