<div dir="ltr"><div class="gmail_default" style="font-family:monospace,monospace">Add CC'ing <span class="gmail-gI"><span>Michael Ellerman <<a href="mailto:mpe@ellerman.id.au">mpe@ellerman.id.au</a>><br><br></span></span></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Mar 26, 2018 at 2:48 PM, Li Wang <span dir="ltr"><<a href="mailto:liwang@redhat.com" target="_blank">liwang@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On some big endian powerpc64 ABI, function ptrs are basically pointers<br>
to function descriptors. The testcase copies functions which results<br>
in function descriptors getting copied. So easily the access was<br>
denied by memory protection key in that address when performing it.<br>
<br>
10000000-10020000 r-xp 00000000 fd:00 167223           mprotect04<br>
10020000-10030000 r--p 00010000 fd:00 167223           mprotect04<br>
10030000-10040000 rw-p 00020000 fd:00 167223           mprotect04<br>
1001a380000-1001a3b0000 rw-p 00000000 00:00 0          [heap]<br>
7fffa6c60000-7fffa6c80000 --xp 00000000 00:00 0<br>
<br>
&exec_func = 0x10030170<br>
&func = 0x7fffa6c60170<br>
<br>
While perform the (*func)(); we get segmentation fault.<br>
<br>
strace log:<br>
-----------<br>
mprotect(0x7fffaed00000, 131072, PROT_EXEC) = 0<br>
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0<br>
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_PKUERR, si_addr=0x7fffaed00170} ---<br>
<br>
Reported-and-tested-by: Li Wang <<a href="mailto:liwang@redhat.com">liwang@redhat.com</a>><br>
Signed-off-by: Ram Pai <<a href="mailto:linuxram@us.ibm.com">linuxram@us.ibm.com</a>><br>
Suggested-by: Michael Ellerman <<a href="mailto:mpe@ellerman.id.au">mpe@ellerman.id.au</a>><br>
Signed-off-by: Li Wang <<a href="mailto:liwang@redhat.com">liwang@redhat.com</a>><br>
---<br>
 testcases/kernel/syscalls/<wbr>mprotect/mprotect04.c | 41 ++++++++++++++++++++++---<br>
 1 file changed, 37 insertions(+), 4 deletions(-)<br>
<br>
diff --git a/testcases/kernel/syscalls/<wbr>mprotect/mprotect04.c b/testcases/kernel/syscalls/<wbr>mprotect/mprotect04.c<br>
index 1173afd..60941a4 100644<br>
--- a/testcases/kernel/syscalls/<wbr>mprotect/mprotect04.c<br>
+++ b/testcases/kernel/syscalls/<wbr>mprotect/mprotect04.c<br>
@@ -56,6 +56,7 @@ int TST_TOTAL = ARRAY_SIZE(testfunc);<br>
 static volatile int sig_caught;<br>
 static sigjmp_buf env;<br>
 static unsigned int copy_sz;<br>
+typedef void (*func_ptr_t)(void);<br>
<br>
 int main(int ac, char **av)<br>
 {<br>
@@ -190,6 +191,22 @@ static void clear_cache(void *start, int len)<br>
 }<br>
<br>
 /*<br>
+ * To check for the ABI version, because ppc64le can technically use<br>
+ * function descriptors.<br>
+ */<br>
+#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF < 2)<br>
+#define USE_FUNCTION_DESCRIPTORS<br>
+#endif<br>
+<br>
+#ifdef USE_FUNCTION_DESCRIPTORS<br>
+typedef struct {<br>
+       uintptr_t entry;<br>
+       uintptr_t toc;<br>
+       uintptr_t env;<br>
+} func_descr_t;<br>
+#endif<br>
+<br>
+/*<br>
  * Copy page where &exec_func resides. Also try to copy subsequent page<br>
  * in case exec_func is close to page boundary.<br>
  */<br>
@@ -197,11 +214,21 @@ static void *get_func(void *mem)<br>
 {<br>
        uintptr_t page_sz = getpagesize();<br>
        uintptr_t page_mask = ~(page_sz - 1);<br>
-       uintptr_t func_page_offset = (uintptr_t)&exec_func & (page_sz - 1);<br>
-       void *func_copy_start = mem + func_page_offset;<br>
-       void *page_to_copy = (void *)((uintptr_t)&exec_func & page_mask);<br>
+       uintptr_t func_page_offset;<br>
+       void *func_copy_start, *page_to_copy;<br>
        void *mem_start = mem;<br>
<br>
+#ifdef USE_FUNCTION_DESCRIPTORS<br>
+       func_descr_t *opd =  (func_descr_t *)&exec_func;<br>
+       func_page_offset = (uintptr_t)opd->entry & (page_sz - 1);<br>
+       func_copy_start = mem + func_page_offset;<br>
+       page_to_copy = (void *)((uintptr_t)opd->entry & page_mask);<br>
+#else<br>
+       func_page_offset = (uintptr_t)&exec_func & (page_sz - 1);<br>
+       func_copy_start = mem + func_page_offset;<br>
+       page_to_copy = (void *)((uintptr_t)&exec_func & page_mask);<br>
+#endif<br>
+<br>
        /* copy 1st page, if it's not present something is wrong */<br>
        if (!page_present(page_to_copy)) {<br>
                tst_resm(TINFO, "exec_func: %p, page_to_copy: %p\n",<br>
@@ -228,7 +255,7 @@ static void *get_func(void *mem)<br>
<br>
 static void testfunc_protexec(void)<br>
 {<br>
-       void (*func)(void);<br>
+       func_ptr_t func;<br>
        void *p;<br>
<br>
        sig_caught = 0;<br>
@@ -236,7 +263,13 @@ static void testfunc_protexec(void)<br>
        p = SAFE_MMAP(cleanup, 0, copy_sz, PROT_READ | PROT_WRITE,<br>
                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);<br>
<br>
+#ifdef USE_FUNCTION_DESCRIPTORS<br>
+       func_descr_t opd;<br>
+       opd.entry = (uintptr_t)get_func(p);<br>
+       func = (func_ptr_t)&opd;<br>
+#else<br>
        func = get_func(p);<br>
+#endif<br>
<br>
        /* Change the protection to PROT_EXEC. */<br>
        TEST(mprotect(p, copy_sz, PROT_EXEC));<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.9.3<br>
<br>
<br>
--<br>
Mailing list info: <a href="https://lists.linux.it/listinfo/ltp" rel="noreferrer" target="_blank">https://lists.linux.it/<wbr>listinfo/ltp</a><br>
</font></span></blockquote></div><br><br clear="all"><br>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">Li Wang<br><a href="mailto:liwang@redhat.com" target="_blank">liwang@redhat.com</a></div>
</div></div>