[LTP] [PATCH] hugemmap/hugemmap37: migrated task-size-overrun.c from libhugetlbfs

Pavithra <[email protected]>
Newsgroups it.linux.lists.ltp
Message-ID <[email protected]>
This test verifies that the kernel correctly prevents mmap operations
from creating mappings that straddle the TASK_SIZE boundary when using
hugepages.

Signed-off-by: Pavithra <[email protected]>
---
 runtest/hugetlb                               |   1 +
 testcases/kernel/mem/.gitignore               |   1 +
 .../kernel/mem/hugetlb/hugemmap/hugemmap37.c  | 173 ++++++++++++++++++
 3 files changed, 175 insertions(+)
 create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap37.c

diff --git a/runtest/hugetlb b/runtest/hugetlb
index 8ee0e6f82..d54f5266d 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -37,6 +37,7 @@ hugemmap31 hugemmap31
 hugemmap32 hugemmap32
 hugemmap34 hugemmap34
 hugemmap35 hugemmap35
+hugemmap37 hugemmap37
 hugemmap05_1 hugemmap05 -m
 hugemmap05_2 hugemmap05 -s
 hugemmap05_3 hugemmap05 -s -m
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index 0e59035df..b2752aec9 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -37,6 +37,7 @@
 /hugetlb/hugemmap/hugemmap32
 /hugetlb/hugemmap/hugemmap34
 /hugetlb/hugemmap/hugemmap35
+/hugetlb/hugemmap/hugemmap37
 /hugetlb/hugeshmat/hugeshmat01
 /hugetlb/hugeshmat/hugeshmat02
 /hugetlb/hugeshmat/hugeshmat03
diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap37.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap37.c
new file mode 100644
index 000000000..c15b4ad33
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap37.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation.
+ * Copyright (c) 2026 Pavithra <[email protected]>
+ */
+
+/*
+ * Origin: https://github.com/libhugetlbfs/libhugetlbfs/blob/master/tests/task-size-overrun.c
+ */
+
+/*\
+ * Test that mmap correctly rejects hugepage mappings that straddle the
+ * TASK_SIZE boundary. Both MAP_FIXED (which must fail) and non-MAP_FIXED
+ * (which must either fail or relocate away from the boundary) cases are
+ * verified. A buggy kernel would allow such a mapping to succeed,
+ * violating address space limits.
+ *
+ * Requires root to mount hugetlbfs.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "hugetlb.h"
+#include "tst_test.h"
+#include "tst_safe_stdio.h"
+#include "tst_safe_macros.h"
+
+#define MAPS_BUF_SZ 4096
+#define MNTPOINT "hugetlbfs/"
+
+static long hpage_size;
+static int fd = -1;
+
+static unsigned long find_last_mapped(void)
+{
+	char line[MAPS_BUF_SZ];
+	char last[MAPS_BUF_SZ];
+	unsigned long start, end, off, ino;
+	FILE *f;
+	int found = 0;
+
+	f = SAFE_FOPEN("/proc/self/maps", "r");
+
+	/* Read all lines and save the last non-special mapping */
+	while (fgets(line, MAPS_BUF_SZ, f)) {
+		/* Skip special mappings like [vsyscall], [vdso], [vvar] */
+		if (strstr(line, "[vsyscall]") || strstr(line, "[vdso]") ||
+		    strstr(line, "[vvar]"))
+			continue;
+
+		strncpy(last, line, MAPS_BUF_SZ - 1);
+		last[MAPS_BUF_SZ - 1] = '\0';
+		found = 1;
+	}
+
+	SAFE_FCLOSE(f);
+
+	if (!found)
+		tst_brk(TBROK, "Could not find any valid mapping in /proc/self/maps");
+
+	tst_res(TINFO, "Last map: %s", last);
+	if (sscanf(last, "%lx-%lx %*s %lx %*s %ld", &start, &end, &off, &ino) != 4)
+		tst_brk(TBROK, "Failed to parse /proc/self/maps line");
+
+	tst_res(TINFO, "Last map: at 0x%lx-0x%lx", start, end);
+	return end;
+}
+
+static unsigned long find_task_size(void)
+{
+	unsigned long low, high;
+	void *p;
+	int page_size = getpagesize();
+
+	low = find_last_mapped();
+	if (!low || ((low % page_size) != 0))
+		tst_brk(TBROK, "Bogus stack end address, 0x%lx!?", low);
+
+	/* Convert to page frame number */
+	low = low / page_size;
+
+	/*
+	 * Set high to maximum possible address space
+	 * For 64-bit: (2^64 - 1) / page_size
+	 * We use -1UL which gives us the maximum unsigned long value
+	 */
+	high = (-1UL) / page_size;
+
+	tst_res(TINFO, "Binary searching for task size PFNs 0x%lx..0x%lx", low, high);
+
+	while (high > low + 1) {
+		unsigned long pfn = (low + high) / 2;
+		unsigned long addr = pfn * page_size;
+
+		p = mmap((void *)addr, page_size, PROT_READ,
+			   MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
+		if (p == MAP_FAILED) {
+			tst_res(TINFO | TERRNO, "Map failed at 0x%lx", addr);
+			high = pfn;
+		} else {
+			tst_res(TINFO, "Map succeeded at 0x%lx", addr);
+			SAFE_MUNMAP(p, page_size);
+			low = pfn;
+		}
+	}
+
+	return low * page_size;
+}
+
+static void run_test(void)
+{
+	void *p;
+	unsigned long task_size;
+	unsigned long straddle_addr;
+
+	task_size = find_task_size();
+	tst_res(TINFO, "TASK_SIZE = 0x%lx", task_size);
+
+	straddle_addr = task_size - hpage_size;
+	straddle_addr = LTP_ALIGN(straddle_addr, hpage_size);
+
+	tst_res(TINFO, "Mapping without MAP_FIXED at %lx...", straddle_addr);
+	errno = 0;
+	p = mmap((void *)straddle_addr, 2*hpage_size, PROT_READ|PROT_WRITE,
+		 MAP_SHARED, fd, 0);
+	if (p == (void *)straddle_addr) {
+		tst_res(TFAIL, "Apparently succeeded in mapping across TASK_SIZE boundary");
+		SAFE_MUNMAP(p, 2*hpage_size);
+	} else if (p != MAP_FAILED) {
+		tst_res(TPASS, "mmap without MAP_FIXED correctly avoided TASK_SIZE boundary");
+		SAFE_MUNMAP(p, 2*hpage_size);
+	} else {
+		tst_res(TPASS, "mmap without MAP_FIXED correctly failed");
+	}
+
+	tst_res(TINFO, "Mapping with MAP_FIXED at %lx...", straddle_addr);
+	errno = 0;
+	p = mmap((void *)straddle_addr, 2*hpage_size, PROT_READ|PROT_WRITE,
+		 MAP_SHARED|MAP_FIXED, fd, 0);
+	if (p != MAP_FAILED) {
+		tst_res(TFAIL, "Apparently succeeded in mapping across TASK_SIZE boundary");
+		SAFE_MUNMAP(p, 2*hpage_size);
+	} else {
+		tst_res(TPASS, "mmap with MAP_FIXED correctly failed");
+	}
+}
+
+static void setup(void)
+{
+	hpage_size = tst_get_hugepage_size();
+	fd = tst_creat_unlinked(MNTPOINT, 0, 0600);
+}
+
+static void cleanup(void)
+{
+	if (fd != -1)
+		SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.needs_root = 1,
+	.mntpoint = MNTPOINT,
+	.needs_hugetlbfs = 1,
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = run_test,
+	.hugepages = {3, TST_NEEDS},
+};
-- 
2.55.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.