tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
x86: map kernel DATA+BSS with NX/XD bit
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 *);
Home |
Main Index |
Thread Index |
Old Index