Subject: non-executable stack, siginfo
To: None <port-alpha@netbsd.org, port-amd64@netbsd.org,>
From: Matthias Drochner <M.Drochner@fz-juelich.de>
List: port-i386
Date: 02/16/2004 18:21:54
This is a multipart MIME message.

--==_Exmh_53264324255100
Content-Type: text/plain; charset=us-ascii


Hi --
There is some inconsistency how an attempt to execute code on the stack
is reported to the user program, in particular if SA_SIGINFO is set.
The (my) regression test in regress/sys/uvm/stack_noexec treated
SIGBUS as the correct answer because i386 behaves that way, but looking
at manpages a SIGSEGV with si_code=SEGV_ACCERR seems correct to me now.
Does anyone know of a standards reference or a precedent for this?

I'll append patches implementing this for amd64 and correcting it for
alpha (which reported SIGSEGV/SEGV_MAPERR) and i386.
(The alpha patch contains some whitespace cleanup - sorry about that.
The only relevant change is around line 520.)

I'll be AFK for the next 2 days; if noone objects I'd commit this
stuff later this week.

best regards
Matthias



--==_Exmh_53264324255100
Content-Type: text/plain ; name="nox.txt"; charset=us-ascii
Content-Description: nox.txt
Content-Disposition: attachment; filename="nox.txt"

Index: sys/arch/alpha/alpha/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/alpha/alpha/trap.c,v
retrieving revision 1.89
diff -u -p -r1.89 trap.c
--- sys/arch/alpha/alpha/trap.c	13 Nov 2003 03:09:28 -0000	1.89
+++ sys/arch/alpha/alpha/trap.c	16 Feb 2004 16:56:02 -0000
@@ -72,17 +72,17 @@
  * All rights reserved.
  *
  * Author: Chris G. Demetriou
- * 
+ *
  * Permission to use, copy, modify and distribute this software and
  * its documentation is hereby granted, provided that both the copyright
  * notice and this permission notice appear in all copies of the
  * software, derivative works or modified versions, and any portions
  * thereof, and that both notices appear in supporting documentation.
- * 
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
- * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- * 
+ *
  * Carnegie Mellon requests users of this software to return to
  *
  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
@@ -142,18 +142,18 @@ trap_init(void)
 	/*
 	 * Point interrupt/exception vectors to our own.
 	 */
-	alpha_pal_wrent(XentInt, ALPHA_KENTRY_INT); 
+	alpha_pal_wrent(XentInt, ALPHA_KENTRY_INT);
 	alpha_pal_wrent(XentArith, ALPHA_KENTRY_ARITH);
 	alpha_pal_wrent(XentMM, ALPHA_KENTRY_MM);
 	alpha_pal_wrent(XentIF, ALPHA_KENTRY_IF);
-	alpha_pal_wrent(XentUna, ALPHA_KENTRY_UNA); 
+	alpha_pal_wrent(XentUna, ALPHA_KENTRY_UNA);
 	alpha_pal_wrent(XentSys, ALPHA_KENTRY_SYS);
 
 	/*
 	 * Clear pending machine checks and error reports, and enable
 	 * system- and processor-correctable error reporting.
 	 */
-	alpha_pal_wrmces(alpha_pal_rdmces() & 
+	alpha_pal_wrmces(alpha_pal_rdmces() &
 	    ~(ALPHA_MCES_DSC|ALPHA_MCES_DPC));
 
 	/*
@@ -305,7 +305,7 @@ trap(const u_long a0, const u_long a1, c
 				ksi.ksi_code = SEGV_MAPERR; /* just pick one */
 			else {
 				ksi.ksi_code = alpha_ucode_to_ksiginfo(ucode);
-				ksi.ksi_addr = 
+				ksi.ksi_addr =
 					(void *)l->l_md.md_tf->tf_regs[FRAME_PC];
 				ksi.ksi_trap = (int)ucode;
 			}
@@ -344,7 +344,7 @@ trap(const u_long a0, const u_long a1, c
 				KSI_INIT_TRAP(&ksi);
 				ksi.ksi_signo = SIGFPE;
 				ksi.ksi_code =  alpha_ucode_to_ksiginfo(ucode);
-				ksi.ksi_addr = 
+				ksi.ksi_addr =
 					(void *)l->l_md.md_tf->tf_regs[FRAME_PC];
 				ksi.ksi_trap =  a0;	/* exception summary */
 				break;
@@ -371,7 +371,7 @@ trap(const u_long a0, const u_long a1, c
 			else if (i == SIGILL)
 				ksi.ksi_code = ILL_ILLOPC;
 			ksi.ksi_signo = i;
-			ksi.ksi_addr = 
+			ksi.ksi_addr =
 				(void *)l->l_md.md_tf->tf_regs[FRAME_PC];
 			ksi.ksi_trap = (int)ucode;
 			break;
@@ -434,7 +434,7 @@ trap(const u_long a0, const u_long a1, c
 				break;
 #endif
 			}
-	
+
 			if (user) {
 				KERNEL_PROC_LOCK(l);
 				if (l->l_flag & L_SA) {
@@ -497,7 +497,7 @@ do_fault:
 				vm = l->l_proc->p_vmspace;
 				map = &vm->vm_map;
 			}
-	
+
 			va = trunc_page((vaddr_t)a0);
 			rv = uvm_fault(map, va,
 			    (a1 == ALPHA_MMCSR_INVALTRANS) ?
@@ -515,12 +515,13 @@ do_fault:
 			    va < USRSTACK) {
 				if (rv == 0) {
 					unsigned nss;
-	
+
 					nss = btoc(USRSTACK -
 					    (unsigned long)va);
 					if (nss > vm->vm_ssize)
 						vm->vm_ssize = nss;
-				} else if (rv == EACCES)
+				} else if (rv == EACCES &&
+					   ftype != VM_PROT_EXECUTE)
 					rv = EFAULT;
 			}
 			if (rv == 0) {
@@ -550,7 +551,7 @@ do_fault:
 			ksi.ksi_trap = a1; /* MMCSR VALUE */
 			if (rv == ENOMEM) {
 				printf("UVM: pid %d (%s), uid %d killed: "
-				       "out of swap\n", l->l_proc->p_pid, 
+				       "out of swap\n", l->l_proc->p_pid,
 				       l->l_proc->p_comm,
 				       l->l_proc->p_cred && l->l_proc->p_ucred ?
 				       l->l_proc->p_ucred->cr_uid : -1);
@@ -965,7 +966,7 @@ unaligned_fixup(u_long va, u_long opcode
 	 * without warning.
 	 *
 	 * If we're trying to do a fixup, we assume that things
-	 * will be botched.  If everything works out OK, 
+	 * will be botched.  If everything works out OK,
 	 * unaligned_{load,store}_* clears the signal flag.
 	 */
 	signal = SIGSEGV;
@@ -1038,7 +1039,7 @@ unaligned_fixup(u_long va, u_long opcode
 			panic("unaligned_fixup: can't get here");
 #endif
 		}
-	} 
+	}
 
 	/*
 	 * Force SIGBUS if requested.
@@ -1236,7 +1237,7 @@ alpha_ucode_to_ksiginfo(u_long ucode)
 	return (0);
 }
 
-/* 
+/*
  * Start a new LWP
  */
 void
Index: sys/arch/amd64/amd64/cpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/cpu.c,v
retrieving revision 1.3
diff -u -p -r1.3 cpu.c
--- sys/arch/amd64/amd64/cpu.c	13 Feb 2004 11:36:20 -0000	1.3
+++ sys/arch/amd64/amd64/cpu.c	16 Feb 2004 16:56:02 -0000
@@ -699,4 +699,7 @@ cpu_init_msrs(struct cpu_info *ci)
 	wrmsr(MSR_FSBASE, 0);
 	wrmsr(MSR_GSBASE, (u_int64_t)ci);
 	wrmsr(MSR_KERNELGSBASE, 0);
+
+	if (cpu_feature & CPUID_NOX)
+		wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NXE);
 }
Index: sys/arch/amd64/amd64/locore.S
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/locore.S,v
retrieving revision 1.9
diff -u -p -r1.9 locore.S
--- sys/arch/amd64/amd64/locore.S	30 Nov 2003 23:58:51 -0000	1.9
+++ sys/arch/amd64/amd64/locore.S	16 Feb 2004 16:56:02 -0000
@@ -352,6 +352,10 @@ start:	movw	$0x1234,0x472			# warm boot
 	movl	%eax,RELOC(cpu_id)
 	movl	%edx,RELOC(cpu_feature)
 
+	movl	$0x80000001,%eax
+	cpuid
+	orl	%edx,RELOC(cpu_feature)
+
 	/* Brand ID is bits 0-7 of %ebx */
 	andl	$255,%ebx
 	movl	%ebx,RELOC(cpu_brand_id)
Index: sys/arch/amd64/amd64/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/pmap.c,v
retrieving revision 1.8
diff -u -p -r1.8 pmap.c
--- sys/arch/amd64/amd64/pmap.c	13 Feb 2004 11:36:20 -0000	1.8
+++ sys/arch/amd64/amd64/pmap.c	16 Feb 2004 16:56:02 -0000
@@ -899,6 +899,7 @@ pmap_bootstrap(kva_start)
 	pt_entry_t *pte;
 	int i;
 	unsigned long p1i;
+	pt_entry_t pg_nx = (cpu_feature & CPUID_NOX ? PG_NX : 0);
 
 	/*
 	 * set up our local static global vars that keep track of the
@@ -914,13 +915,14 @@ pmap_bootstrap(kva_start)
 	 * we can jam into a i386 PTE.
 	 */
 
-	protection_codes[VM_PROT_NONE] = 0;  			/* --- */
+	protection_codes[VM_PROT_NONE] = pg_nx;			/* --- */
 	protection_codes[VM_PROT_EXECUTE] = PG_RO;		/* --x */
-	protection_codes[VM_PROT_READ] = PG_RO;			/* -r- */
+	protection_codes[VM_PROT_READ] = PG_RO | pg_nx;		/* -r- */
 	protection_codes[VM_PROT_READ|VM_PROT_EXECUTE] = PG_RO;	/* -rx */
-	protection_codes[VM_PROT_WRITE] = PG_RW;		/* w-- */
+	protection_codes[VM_PROT_WRITE] = PG_RW | pg_nx;	/* w-- */
 	protection_codes[VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW;/* w-x */
-	protection_codes[VM_PROT_WRITE|VM_PROT_READ] = PG_RW;	/* wr- */
+	protection_codes[VM_PROT_WRITE|VM_PROT_READ] = PG_RW | pg_nx;
+								/* wr- */
 	protection_codes[VM_PROT_ALL] = PG_RW;			/* wrx */
 
 	/*
@@ -2226,7 +2228,7 @@ pmap_extract(pmap, va, pap)
 #ifdef LARGEPAGES
 	if (pde & PG_PS) {
 		if (pap != NULL)
-			*pap = (pde & PG_LGFRAME) | (va & ~PG_LGFRAME);
+			*pap = (pde & PG_LGFRAME) | (va & 0x1fffff);
 		return (TRUE);
 	}
 #endif
@@ -2234,7 +2236,7 @@ pmap_extract(pmap, va, pap)
 
 	if (__predict_true((pte & PG_V) != 0)) {
 		if (pap != NULL)
-			*pap = (pte & PG_FRAME) | (va & ~PG_FRAME);
+			*pap = (pte & PG_FRAME) | (va & 0xfff);
 		return (TRUE);
 	}
 
Index: sys/arch/amd64/amd64/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/trap.c,v
retrieving revision 1.15
diff -u -p -r1.15 trap.c
--- sys/arch/amd64/amd64/trap.c	5 Nov 2003 13:58:00 -0000	1.15
+++ sys/arch/amd64/amd64/trap.c	16 Feb 2004 16:56:02 -0000
@@ -460,6 +460,8 @@ faultcommon:
 			map = &vm->vm_map;
 		if (frame->tf_err & PGEX_W)
 			ftype = VM_PROT_WRITE;
+		else if (frame->tf_err & PGEX_X)
+			ftype = VM_PROT_EXECUTE;
 		else
 			ftype = VM_PROT_READ;
 
Index: sys/arch/amd64/include/pte.h
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/include/pte.h,v
retrieving revision 1.1
diff -u -p -r1.1 pte.h
--- sys/arch/amd64/include/pte.h	26 Apr 2003 18:39:47 -0000	1.1
+++ sys/arch/amd64/include/pte.h	16 Feb 2004 16:56:02 -0000
@@ -113,9 +113,10 @@ typedef u_int64_t pt_entry_t;		/* PTE */
 #define PG_AVAIL1	0x0000000000000200
 #define PG_AVAIL2	0x0000000000000400
 #define PG_AVAIL3	0x0000000000000800
-#define	PG_FRAME	0xfffffffffffff000
+#define	PG_FRAME	0x000ffffffffff000
+#define	PG_NX		0x8000000000000000
 
-#define	PG_LGFRAME	0xffffffffffc00000	/* large (2M) page frame mask */
+#define	PG_LGFRAME	0x000fffffffe00000	/* large (2M) page frame mask */
 
 /*
  * short forms of protection codes
@@ -131,5 +132,6 @@ typedef u_int64_t pt_entry_t;		/* PTE */
 #define PGEX_P		0x01	/* protection violation (vs. no mapping) */
 #define PGEX_W		0x02	/* exception during a write cycle */
 #define PGEX_U		0x04	/* exception while in user mode (upl) */
+#define PGEX_X		0x10	/* exception during instruction fetch */
 
 #endif /* _AMD64_PTE_H_ */
Index: sys/arch/amd64/include/specialreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/include/specialreg.h,v
retrieving revision 1.1
diff -u -p -r1.1 specialreg.h
--- sys/arch/amd64/include/specialreg.h	26 Apr 2003 18:39:48 -0000	1.1
+++ sys/arch/amd64/include/specialreg.h	16 Feb 2004 16:56:02 -0000
@@ -11,6 +11,7 @@
 #define EFER_SCE	0x00000001	/* SYSCALL extension */
 #define EFER_LME	0x00000100	/* Long Mode Active */
 #define EFER_LMA	0x00000400	/* Long Mode Enabled */
+#define EFER_NXE	0x00000800	/* No-Execute Enabled */
 
 #define MSR_STAR	0xc0000081		/* 32 bit syscall gate addr */
 #define MSR_LSTAR	0xc0000082		/* 64 bit syscall gate addr */
Index: sys/arch/i386/i386/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/trap.c,v
retrieving revision 1.194
diff -u -p -r1.194 trap.c
--- sys/arch/i386/i386/trap.c	4 Nov 2003 10:33:15 -0000	1.194
+++ sys/arch/i386/i386/trap.c	16 Feb 2004 16:56:03 -0000
@@ -401,6 +401,12 @@ copyfault:
 		    &l->l_addr->u_pcb)) {
 			goto out;
 		}
+		KSI_INIT_TRAP(&ksi);
+		ksi.ksi_signo = SIGSEGV;
+		ksi.ksi_trap = type & ~T_USER;
+		ksi.ksi_addr = (void *)rcr2();
+		ksi.ksi_code = SEGV_ACCERR;
+		goto trapsignal;
 
 	case T_TSSFLT|T_USER:
 	case T_SEGNPFLT|T_USER:
Index: sys/arch/x86/include/specialreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/specialreg.h,v
retrieving revision 1.4
diff -u -p -r1.4 specialreg.h
--- sys/arch/x86/include/specialreg.h	2 Feb 2004 08:28:00 -0000	1.4
+++ sys/arch/x86/include/specialreg.h	16 Feb 2004 16:56:03 -0000
@@ -134,6 +134,7 @@
  */
 
 #define CPUID_MPC	0x00080000	/* Multiprocessing Capable */
+#define CPUID_NOX	0x00100000	/* No Execute Page Protection */
 #define CPUID_MMXX	0x00400000	/* AMD MMX Extensions */
 #define CPUID_3DNOW2	0x40000000	/* 3DNow! Instruction Extension */
 #define CPUID_3DNOW	0x80000000	/* 3DNow! Instructions */
Index: regress/sys/uvm/stack_noexec/tramptest.c
===================================================================
RCS file: /cvsroot/src/regress/sys/uvm/stack_noexec/tramptest.c,v
retrieving revision 1.1
diff -u -p -r1.1 tramptest.c
--- regress/sys/uvm/stack_noexec/tramptest.c	10 Dec 2003 13:24:59 -0000	1.1
+++ regress/sys/uvm/stack_noexec/tramptest.c	16 Feb 2004 16:56:03 -0000
@@ -21,9 +21,12 @@ __enable_execute_stack()
 }
 
 void
-buserr(int s)
+buserr(int s, siginfo_t *si, void *ctx)
 {
 
+	if (s != SIGSEGV || si->si_code != SEGV_ACCERR)
+		exit(2);
+
 	exit(0);
 }
 
@@ -38,6 +41,7 @@ void do_f()
 int
 main()
 {
+	struct sigaction sa;
 
 	void mist()
 	{
@@ -45,7 +49,10 @@ main()
 		return;
 	}
 
-	signal(SIGBUS, buserr);
+	sa.sa_sigaction = buserr;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_SIGINFO;
+	sigaction(SIGSEGV, &sa, 0);
 
 	f = mist;
 	do_f();

--==_Exmh_53264324255100--