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-alpha
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--