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