|
From: Jan S. <jst...@re...> - 2015-09-09 11:39:29
|
Testcase tried to copy page size area starting at &exec_func.
This results in crash on powerpc, because &exec_func is too close
to end of page and subsequent page is not mapped:
10000000-10010000 r-xp 00000000 fd:00 402855 mprotect04
10010000-10020000 rw-p 00000000 fd:00 402855 mprotect04
806a410000-806a440000 r-xp 00000000 fd:00 2097827 /lib64/ld-2.12.so
where &exec_func == 0x100199c0, and page_size == 65536.
It's also worth noting, that function ptr does not reside in .text,
but in .opd section. That shouldn't matter for this testcase as long
as it doesn't try to copy non-existent pages.
This patch is changing copy function to try copy 2 whole aligned pages.
Both pages are checked to be present in memory before memcpy is
attempted. First is the page which contains &exec_func, and 2nd is the
subsequent page - for the case &exec_func is too close to page boundary.
Signed-off-by: Jan Stancek <jst...@re...>
---
testcases/kernel/syscalls/mprotect/mprotect04.c | 61 +++++++++++++++++++++----
1 file changed, 52 insertions(+), 9 deletions(-)
diff --git a/testcases/kernel/syscalls/mprotect/mprotect04.c b/testcases/kernel/syscalls/mprotect/mprotect04.c
index 8a4a72ad69f2..23aecbd856f4 100644
--- a/testcases/kernel/syscalls/mprotect/mprotect04.c
+++ b/testcases/kernel/syscalls/mprotect/mprotect04.c
@@ -54,6 +54,7 @@ int TST_TOTAL = ARRAY_SIZE(testfunc);
static volatile int sig_caught;
static sigjmp_buf env;
+static int copy_sz;
int main(int ac, char **av)
{
@@ -83,7 +84,9 @@ static void sighandler(int sig)
static void setup(void)
{
+ tst_tmpdir();
tst_sig(NOFORK, sighandler, cleanup);
+ copy_sz = getpagesize() * 2;
TEST_PAUSE;
}
@@ -158,32 +161,71 @@ static void exec_func(void)
return;
}
-static void *get_func(void *mem)
+static int page_present(void *p)
{
- memcpy(mem, exec_func, getpagesize());
+ int fd;
+
+ fd = SAFE_OPEN(cleanup, "page_present", O_WRONLY|O_CREAT, 0644);
+ TEST(write(fd, p, 1));
+ SAFE_CLOSE(cleanup, fd);
+
+ if (TEST_RETURN >= 0)
+ return 1;
+
+ if (TEST_ERRNO != EFAULT)
+ tst_brkm(TBROK | TTERRNO, cleanup, "page_present write");
- return mem;
+ return 0;
+}
+
+/*
+ * Copy page where &exec_func resides. Also try to copy subsequent page
+ * in case exec_func is close to page boundary.
+ */
+static void *get_func(void *mem)
+{
+ uintptr_t page_sz = getpagesize();
+ uintptr_t page_mask = ~(page_sz - 1);
+ uintptr_t func_page_offset = (uintptr_t)&exec_func & (page_sz - 1);
+ void *func_copy_start = mem + func_page_offset;
+ void *page_to_copy = (void *)((uintptr_t)&exec_func & page_mask);
+
+ /* copy 1st page, if it's not present something is wrong */
+ if (!page_present(page_to_copy)) {
+ tst_resm(TINFO, "exec_func: %p, page_to_copy: %p\n",
+ &exec_func, page_to_copy);
+ tst_brkm(TBROK, cleanup, "page_to_copy not present\n");
+ }
+ memcpy(mem, page_to_copy, page_sz);
+
+ /* copy 2nd page if possible */
+ mem += page_sz;
+ page_to_copy += page_sz;
+ if (page_present(page_to_copy))
+ memcpy(mem, page_to_copy, page_sz);
+ else
+ memset(mem, 0, page_sz);
+
+ /* return pointer to area where copy of exec_func resides */
+ return func_copy_start;
}
#endif
static void testfunc_protexec(void)
{
- int page_sz;
void (*func)(void);
void *p;
sig_caught = 0;
- page_sz = getpagesize();
-
- p = SAFE_MMAP(cleanup, 0, page_sz, PROT_READ | PROT_WRITE,
+ p = SAFE_MMAP(cleanup, 0, copy_sz, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
func = get_func(p);
/* Change the protection to PROT_EXEC. */
- TEST(mprotect(p, page_sz, PROT_EXEC));
+ TEST(mprotect(p, copy_sz, PROT_EXEC));
if (TEST_RETURN == -1) {
tst_resm(TFAIL | TTERRNO, "mprotect failed");
@@ -205,9 +247,10 @@ static void testfunc_protexec(void)
}
}
- SAFE_MUNMAP(cleanup, p, page_sz);
+ SAFE_MUNMAP(cleanup, p, copy_sz);
}
static void cleanup(void)
{
+ tst_rmdir();
}
--
1.8.3.1
|