aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2009-12-07 14:58:40 +1100
committerEric B Munson <ebmunson@us.ibm.com>2009-12-09 11:03:18 +0000
commit495a57a6dcf82d9a64643068197f2157a0c739f5 (patch)
tree0820a2662a0267fb7665dc4d32ad4b0e750074be /tests
parent70cadbe3e3f8e8f9035675909e01838115e40a0a (diff)
downloadlibhugetlbfs-495a57a6dcf82d9a64643068197f2157a0c739f5.tar.gz
Add testcases for buggy mremap() behaviours
Al Viro recently discovered several bugs in the behaviour of mremap() that can cause crashes on architectures with holes in the address space (like ia64) and on powerpc with it's distinct page size "slices". This patch adds three new testcases to tickle some of these bugs (aimed chiefly at the powerpc manifestation, it may or may not also trip on other archs). Since these testcases will crash current kernels, we probably don't want to merge this until we can protect them with a kernel version test, like other dangerous testcases. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Eric B Munson <ebmunson@us.ibm.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile2
-rw-r--r--tests/mremap-expand-slice-collision.c188
-rw-r--r--tests/mremap-fixed-huge-near-normal.c145
-rw-r--r--tests/mremap-fixed-normal-near-huge.c124
-rwxr-xr-xtests/run_tests.py4
5 files changed, 463 insertions, 0 deletions
diff --git a/tests/Makefile b/tests/Makefile
index 0e01237..2a284c5 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -7,6 +7,8 @@ LIB_TESTS = gethugepagesize test_root find_path unlinked_fd misalign \
truncate_reserve_wraparound truncate_sigbus_versus_oom \
map_high_truncate_2 truncate_above_4GB direct \
misaligned_offset brk_near_huge task-size-overrun stack_grow_into_huge \
+ mremap-expand-slice-collision \
+ mremap-fixed-normal-near-huge mremap-fixed-huge-near-normal \
counters quota heap-overflow get_huge_pages get_hugepage_region \
shmoverride_linked gethugepagesizes \
madvise_reserve fadvise_reserve readahead_reserve \
diff --git a/tests/mremap-expand-slice-collision.c b/tests/mremap-expand-slice-collision.c
new file mode 100644
index 0000000..0cbff15
--- /dev/null
+++ b/tests/mremap-expand-slice-collision.c
@@ -0,0 +1,188 @@
+/*
+ * libhugetlbfs - Easy use of Linux hugepages
+ * Copyright (C) 2009 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include <hugetlbfs.h>
+
+#include "hugetests.h"
+
+#define RANDOM_CONSTANT 0x1234ABCD
+
+#ifdef __LP64__
+#define SLICE_BOUNDARY 0x20000000000
+#else
+#define SLICE_BOUNDARY 0xe0000000
+#endif
+
+long hpage_size, page_size;
+
+void do_readback(void *p, size_t size, const char *stage)
+{
+ unsigned int *q = p;
+ int i;
+
+ verbose_printf("do_readback(%p, 0x%lx, \"%s\")\n", p,
+ (unsigned long)size, stage);
+
+ for (i = 0; i < (size / sizeof(*q)); i++) {
+ q[i] = RANDOM_CONSTANT ^ i;
+ }
+
+ for (i = 0; i < (size / sizeof(*q)); i++) {
+ if (q[i] != (RANDOM_CONSTANT ^ i))
+ FAIL("Stage \"%s\": Mismatch at offset 0x%x: 0x%x instead of 0x%x",
+ stage, i, q[i], RANDOM_CONSTANT ^ i);
+ }
+}
+
+void do_remap(int fd, void *target)
+{
+ void *a, *b;
+ int rc;
+
+ a = mmap(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (a == MAP_FAILED)
+ FAIL("mmap(huge page): %s", strerror(errno));
+
+ verbose_printf("Huge base mapping at %p\n", a);
+
+ do_readback(a, hpage_size, "base huge");
+
+ verbose_printf("Attempting mremap(MAYMOVE|FIXED) to %p...", target);
+
+ b = mremap(a, hpage_size, hpage_size, MREMAP_MAYMOVE | MREMAP_FIXED,
+ target);
+
+ if (b != MAP_FAILED) {
+ verbose_printf("testing...");
+ do_readback(b, hpage_size, "remapped");
+ verbose_printf("ok\n");
+ } else {
+ verbose_printf("disallowed (%s)\n", strerror(errno));
+ }
+
+ rc = munmap(b, hpage_size);
+ if (rc != 0)
+ FAIL("munmap(after remap): %s", strerror(errno));
+}
+
+int main(int argc, char *argv[])
+{
+ int fd, rc;
+ void *p, *q, *r;
+
+ test_init(argc, argv);
+
+ hpage_size = check_hugepagesize();
+ page_size = getpagesize();
+
+
+ fd = hugetlbfs_unlinked_fd();
+ if (fd < 0)
+ FAIL("hugetlbfs_unlinked_fd()");
+
+ /* First, hugepages above, normal below */
+ p = mmap((void *)(SLICE_BOUNDARY + hpage_size), hpage_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, fd, 0);
+ if (p == MAP_FAILED)
+ FAIL("mmap(huge above): %s", strerror(errno));
+
+ do_readback(p, hpage_size, "huge above");
+
+ q = mmap((void *)(SLICE_BOUNDARY - page_size), page_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if (q == MAP_FAILED)
+ FAIL("mmap(normal below): %s", strerror(errno));
+
+ do_readback(q, page_size, "normal below");
+
+ verbose_printf("Attempting to remap...");
+
+ r = mremap(q, page_size, 2*page_size, 0);
+ if (r == MAP_FAILED) {
+ verbose_printf("disallowed\n");
+ rc = munmap(q, page_size);
+ if (rc != 0)
+ FAIL("munmap(normal below): %s", strerror(errno));
+ } else {
+ if (r != q)
+ FAIL("mremap() moved without MREMAP_MAYMOVE!?");
+
+ verbose_printf("testing...");
+ do_readback(q, 2*page_size, "normal below expanded");
+ rc = munmap(q, 2*page_size);
+ if (rc != 0)
+ FAIL("munmap(normal below expanded): %s", strerror(errno));
+ }
+
+ rc = munmap(p, hpage_size);
+ if (rc != 0)
+ FAIL("munmap(huge above)");
+
+ /* Next, normal pages above, huge below */
+ p = mmap((void *)(SLICE_BOUNDARY + hpage_size), page_size,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
+ if (p == MAP_FAILED)
+ FAIL("mmap(normal above): %s", strerror(errno));
+
+ do_readback(p, page_size, "normal above");
+
+ q = mmap((void *)(SLICE_BOUNDARY - hpage_size),
+ hpage_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, fd, 0);
+ if (q == MAP_FAILED)
+ FAIL("mmap(huge below): %s", strerror(errno));
+
+ do_readback(q, hpage_size, "huge below");
+
+ verbose_printf("Attempting to remap...");
+
+ r = mremap(q, hpage_size, 2*hpage_size, 0);
+ if (r == MAP_FAILED) {
+ verbose_printf("disallowed\n");
+ rc = munmap(q, hpage_size);
+ if (rc != 0)
+ FAIL("munmap(huge below): %s", strerror(errno));
+ } else {
+ if (r != q)
+ FAIL("mremap() moved without MREMAP_MAYMOVE!?");
+
+ verbose_printf("testing...");
+ do_readback(q, 2*hpage_size, "huge below expanded");
+ rc = munmap(q, 2*hpage_size);
+ if (rc != 0)
+ FAIL("munmap(huge below expanded): %s", strerror(errno));
+ }
+
+ rc = munmap(p, page_size);
+ if (rc != 0)
+ FAIL("munmap(normal above)");
+
+
+ PASS();
+}
diff --git a/tests/mremap-fixed-huge-near-normal.c b/tests/mremap-fixed-huge-near-normal.c
new file mode 100644
index 0000000..2c41813
--- /dev/null
+++ b/tests/mremap-fixed-huge-near-normal.c
@@ -0,0 +1,145 @@
+/*
+ * libhugetlbfs - Easy use of Linux hugepages
+ * Copyright (C) 2009 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include <hugetlbfs.h>
+
+#include "hugetests.h"
+
+#define RANDOM_CONSTANT 0x1234ABCD
+
+long hpage_size;
+
+void do_readback(void *p, size_t size, const char *stage)
+{
+ unsigned int *q = p;
+ int i;
+
+ verbose_printf("do_readback(%p, 0x%lx, \"%s\")\n", p,
+ (unsigned long)size, stage);
+
+ for (i = 0; i < (size / sizeof(*q)); i++) {
+ q[i] = RANDOM_CONSTANT ^ i;
+ }
+
+ for (i = 0; i < (size / sizeof(*q)); i++) {
+ if (q[i] != (RANDOM_CONSTANT ^ i))
+ FAIL("Stage \"%s\": Mismatch at offset 0x%x: 0x%x instead of 0x%x",
+ stage, i, q[i], RANDOM_CONSTANT ^ i);
+ }
+}
+
+void do_remap(int fd, void *target)
+{
+ void *a, *b;
+ int rc;
+
+ a = mmap(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (a == MAP_FAILED)
+ FAIL("mmap(huge page): %s", strerror(errno));
+
+ verbose_printf("Huge base mapping at %p\n", a);
+
+ do_readback(a, hpage_size, "base huge");
+
+ verbose_printf("Attempting mremap(MAYMOVE|FIXED) to %p...", target);
+
+ b = mremap(a, hpage_size, hpage_size, MREMAP_MAYMOVE | MREMAP_FIXED,
+ target);
+
+ if (b != MAP_FAILED) {
+ verbose_printf("testing...");
+ do_readback(b, hpage_size, "remapped");
+ verbose_printf("ok\n");
+
+ } else {
+ verbose_printf("disallowed (%s)\n", strerror(errno));
+ b = a;
+ }
+
+ rc = munmap(b, hpage_size);
+ if (rc != 0)
+ FAIL("munmap(after remap): %s", strerror(errno));
+}
+
+void *map_align(size_t size, size_t align)
+{
+ unsigned long xsize = size + align - getpagesize();
+ void *p, *q;
+ int rc;
+
+ p = mmap(NULL, xsize, PROT_READ|PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (p == MAP_FAILED)
+ FAIL("mmap(): %s", strerror(errno));
+
+ q = PALIGN(p, align);
+
+ rc = munmap(p, q-p);
+ if (rc != 0)
+ FAIL("munmap(lower aligning): %s", strerror(errno));
+
+ rc = munmap(q + size, p + xsize - (q + size));
+ if (rc != 0)
+ FAIL("munmap(upper aligning): %s", strerror(errno));
+
+
+ return q;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd, rc;
+ void *p;
+
+ test_init(argc, argv);
+
+ hpage_size = check_hugepagesize();
+
+ fd = hugetlbfs_unlinked_fd();
+ if (fd < 0)
+ FAIL("hugetlbfs_unlinked_fd()");
+
+ p = map_align(3*hpage_size, hpage_size);
+
+ rc = munmap(p, hpage_size);
+ if (rc != 0)
+ FAIL("munmap() low portion: %s", strerror(errno));
+
+ rc = munmap(p + 2*hpage_size, hpage_size);
+ if (rc != 0)
+ FAIL("munmap() high portion: %s", strerror(errno));
+
+ p = p + hpage_size;
+
+ verbose_printf("Normal mapping at %p\n", p);
+
+ do_readback(p, hpage_size, "base normal page");
+
+ do_remap(fd, p - hpage_size);
+ do_remap(fd, p + hpage_size);
+
+ PASS();
+}
diff --git a/tests/mremap-fixed-normal-near-huge.c b/tests/mremap-fixed-normal-near-huge.c
new file mode 100644
index 0000000..1be5f8f
--- /dev/null
+++ b/tests/mremap-fixed-normal-near-huge.c
@@ -0,0 +1,124 @@
+/*
+ * libhugetlbfs - Easy use of Linux hugepages
+ * Copyright (C) 2009 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include <hugetlbfs.h>
+
+#include "hugetests.h"
+
+#define RANDOM_CONSTANT 0x1234ABCD
+
+long page_size, hpage_size;
+
+void do_readback(void *p, size_t size, const char *stage)
+{
+ unsigned int *q = p;
+ int i;
+
+ verbose_printf("do_readback(%p, 0x%lx, \"%s\")\n", p,
+ (unsigned long)size, stage);
+
+ for (i = 0; i < (size / sizeof(*q)); i++) {
+ q[i] = RANDOM_CONSTANT ^ i;
+ }
+
+ for (i = 0; i < (size / sizeof(*q)); i++) {
+ if (q[i] != (RANDOM_CONSTANT ^ i))
+ FAIL("Stage \"%s\": Mismatch at offset 0x%x: 0x%x instead of 0x%x",
+ stage, i, q[i], RANDOM_CONSTANT ^ i);
+ }
+}
+
+void do_remap(void *target)
+{
+ void *a, *b;
+ int rc;
+
+ a = mmap(NULL, page_size, PROT_READ|PROT_WRITE,
+ MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+ if (a == MAP_FAILED)
+ FAIL("mmap(normal page): %s", strerror(errno));
+
+ verbose_printf("Normal base mapping at %p\n", a);
+
+ do_readback(a, page_size, "base normal");
+
+ verbose_printf("Attempting mremap(MAYMOVE|FIXED) to %p...", target);
+
+ b = mremap(a, page_size, page_size, MREMAP_MAYMOVE | MREMAP_FIXED,
+ target);
+
+ if (b != MAP_FAILED) {
+ verbose_printf("testing...");
+ do_readback(b, page_size, "remapped");
+ verbose_printf("ok\n");
+ } else {
+ verbose_printf("disallowed (%s)\n", strerror(errno));
+ b = a;
+ }
+
+ rc = munmap(b, page_size);
+ if (rc != 0)
+ FAIL("munmap(after remap): %s", strerror(errno));
+}
+
+int main(int argc, char *argv[])
+{
+ int fd, rc;
+ void *p;
+
+ test_init(argc, argv);
+
+ hpage_size = check_hugepagesize();
+ page_size = getpagesize();
+
+ fd = hugetlbfs_unlinked_fd();
+ if (fd < 0)
+ FAIL("hugetlbfs_unlinked_fd()");
+
+ p = mmap(NULL, 3*hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+ fd, 0);
+ if (p == MAP_FAILED)
+ FAIL("mmap(): %s", strerror(errno));
+
+ rc = munmap(p, hpage_size);
+ if (rc != 0)
+ FAIL("munmap() low hpage: %s", strerror(errno));
+
+ rc = munmap(p + 2*hpage_size, hpage_size);
+ if (rc != 0)
+ FAIL("munmap() high hpage: %s", strerror(errno));
+
+ p = p + hpage_size;
+
+ verbose_printf("Hugepage mapping at %p\n", p);
+
+ do_readback(p, hpage_size, "base hugepage");
+
+ do_remap(p - page_size);
+ do_remap(p + hpage_size);
+
+ PASS();
+}
diff --git a/tests/run_tests.py b/tests/run_tests.py
index e53b71c..ff7257a 100755
--- a/tests/run_tests.py
+++ b/tests/run_tests.py
@@ -504,6 +504,9 @@ def functional_tests():
do_test("misalign")
# Specific kernel bug tests
+ do_test("mremap-expand-slice-collision")
+ do_test("mremap-fixed-huge-near-normal")
+ do_test("mremap-fixed-normal-near-huge")
do_test("ptrace-write-hugepage")
do_test("icache-hygiene")
do_test("slbpacaflush")
@@ -516,6 +519,7 @@ def functional_tests():
do_test("brk_near_huge")
do_test("task-size-overrun")
do_test_with_rlimit(resource.RLIMIT_STACK, -1, "stack_grow_into_huge")
+
if dangerous == 1:
do_test("readahead_reserve")
do_test("madvise_reserve")