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