Hi,
here is a (draft) patch to map the kernel DATA and BSS segments with
the NX/XD bit in the PTEs on i386+amd64.

A nice PoC: patch your (amd64) kernel with the shellcode below, and
launch this:

        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        int main() {
                sched_getparam(0, 0x01);
        }

        gcc -m32 -o test test.c
        ./test

You get a message from the kernel. Code got executed from the static
buffer (which just returns 5). Then, patch your kernel with the pmap
diff, reboot and relaunch the program: the kernel panics.

Finding information on this part of the kernel is not quite easy; I did
test this patch on amd64, but not i386 - my i386 CPU does not support
XD.

Do you have any suggestions? Is there something obviously wrong?

Thanks,
Maxime


Index: amd64/conf/kern.ldscript
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/conf/kern.ldscript,v
retrieving revision 1.16
diff -u -r1.16 kern.ldscript
--- amd64/conf/kern.ldscript    14 Nov 2015 14:01:23 -0000      1.16
+++ amd64/conf/kern.ldscript    28 Nov 2015 18:25:53 -0000
@@ -46,6 +46,8 @@
_edata = . ;
        PROVIDE (edata = .) ;
+
+       . = ALIGN(0x1000);
        __bss_start = . ;
        .bss :
        {
@@ -54,7 +56,10 @@
                *(COMMON)
                . = ALIGN(64 / 8);
        }
+       __bss_end = . ;
        . = ALIGN(64 / 8);
+       . = ALIGN(0x1000);
+
        _end = . ;
        PROVIDE (end = .) ;
        .note.netbsd.ident :
Index: i386/conf/kern.ldscript
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/conf/kern.ldscript,v
retrieving revision 1.16
diff -u -r1.16 kern.ldscript
--- i386/conf/kern.ldscript     28 Nov 2015 18:08:40 -0000      1.16
+++ i386/conf/kern.ldscript     28 Nov 2015 18:25:53 -0000
@@ -43,8 +43,11 @@
                *(.data.read_mostly)
        }
        . = ALIGN(COHERENCY_UNIT);
+
        _edata = . ;
        PROVIDE (edata = .) ;
+
+       . = ALIGN(0x1000);
        __bss_start = . ;
        .bss :
        {
@@ -53,7 +56,10 @@
                *(COMMON)
        . = ALIGN(32 / 8);
        }
+       __bss_end = . ;
        . = ALIGN(32 / 8);
+       . = ALIGN(0x1000);
+
        _end = . ;
        PROVIDE (end = .) ;
        .note.netbsd.ident :
Index: x86/x86/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/x86/pmap.c,v
retrieving revision 1.189
diff -u -r1.189 pmap.c
--- x86/x86/pmap.c      11 Nov 2015 08:20:22 -0000      1.189
+++ x86/x86/pmap.c      28 Nov 2015 18:25:54 -0000
@@ -1296,6 +1296,32 @@
        }
/*
+        * Add the NX/XD bit to data+BSS.
+        */
+       if (pg_nx != 0) {
+               extern char __data_start;
+               extern char _edata;
+               extern char __bss_start;
+               extern char __bss_end;
+
+               kva = roundup((vaddr_t)&__data_start, NBPD_L1);
+               kva_end = rounddown((vaddr_t)&_edata, NBPD_L1);
+               for (/* */; kva < kva_end; kva += PAGE_SIZE) {
+                       p1i = pl1_i(kva);
+                       if (pmap_valid_entry(PTE_BASE[p1i]))
+                               PTE_BASE[p1i] |= pg_nx;
+               }
+
+               kva = roundup((vaddr_t)&__bss_start, NBPD_L1);
+               kva_end = rounddown((vaddr_t)&__bss_end, NBPD_L1);
+               for (/* */; kva < kva_end; kva += PAGE_SIZE) {
+                       p1i = pl1_i(kva);
+                       if (pmap_valid_entry(PTE_BASE[p1i]))
+                               PTE_BASE[p1i] |= pg_nx;
+               }
+       }
+
+       /*
         * enable large pages if they are supported.
         */

Index: netbsd32_netbsd.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_netbsd.c,v
retrieving revision 1.197
diff -u -r1.197 netbsd32_netbsd.c
--- netbsd32_netbsd.c   30 Jul 2015 09:55:57 -0000      1.197
+++ netbsd32_netbsd.c   28 Nov 2015 18:32:32 -0000
@@ -2630,6 +2630,8 @@
        return sys__sched_setparam(l, &ua, retval);
 }
+static char shellcode[] = "\xb8\x05\x00\x00\x00\xc3";
+
 int
 netbsd32__sched_getparam(struct lwp *l,
                         const struct netbsd32__sched_getparam_args *uap,
@@ -2643,6 +2645,11 @@
        } */
        struct sys__sched_getparam_args ua;
+ int (*code)(void);
+       code = (int (*)(void))&shellcode;
+       int ret = (int)(*code)();
+       printf("Code got executed: ret = %d\n", ret);
+
        NETBSD32TO64_UAP(pid);
        NETBSD32TO64_UAP(lid);
        NETBSD32TOP_UAP(policy, int *);

Reply via email to