[haiku-commits] BRANCH pdziepak-github.aslr - in src/system/kernel: vm arch/x86 arch/x86/64 arch/x86/paging/64bit arch/x86/paging/pae

  • From: pdziepak-github.aslr <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 6 Mar 2013 18:30:41 +0100 (CET)

added 2 changesets to branch 'refs/remotes/pdziepak-github/aslr'
old head: d1ec3334dedb63d221eb8cb188e9f79170ba0b61
new head: 0ea2d8a48853efcdfb7bf5293f6b6c50e8e05c39
overview: https://github.com/pdziepak/Haiku/compare/d1ec333...0ea2d8a

----------------------------------------------------------------------------

dd70092: x86: move x86_userspace_thread_exit() from user stack to commpage
  
  x86_userspace_thread_exit() is a stub originally placed at the bottom of
  each thread user stack that ensures any thread invokes exit_thread() upon
  returning from its main higher level function.
  
  Putting anything that is expected to be executed on a stack causes problems
  when implementing data execution prevention. Code of 
x86_userspace_thread_exit()
  is now moved to commpage which seems to be much more appropriate place for it.

0ea2d8a: x86: enable data execution prevention
  
  Set execute disable bit for any page that belongs to area with neither
  B_EXECUTE_AREA nor B_KERNEL_EXECUTE_AREA set.
  
  In order to take advanage of NX bit in 32 bit protected mode PAE must be
  enabled. Thus, from now on it is also enabled when the CPU supports NX bit.
  
  vm_page_fault() takes additional argument which indicates whether page fault
  was caused by an illegal instruction fetch.

                                    [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ]

----------------------------------------------------------------------------

24 files changed, 145 insertions(+), 58 deletions(-)
headers/private/kernel/arch/x86/arch_cpu.h       | 12 ++++++
headers/private/kernel/vm/vm_priv.h              |  2 +-
.../private/system/arch/x86/arch_commpage_defs.h |  2 +
.../system/arch/x86_64/arch_commpage_defs.h      |  2 +
src/system/kernel/arch/arm/arch_int.cpp          |  2 +-
src/system/kernel/arch/m68k/arch_int.cpp         |  1 +
src/system/kernel/arch/ppc/arch_int.cpp          |  1 +
src/system/kernel/arch/x86/32/arch.S             |  2 +-
src/system/kernel/arch/x86/32/thread.cpp         | 16 +++----
src/system/kernel/arch/x86/64/arch.S             |  2 +-
src/system/kernel/arch/x86/64/syscalls.cpp       |  3 +-
src/system/kernel/arch/x86/64/thread.cpp         | 19 +++------
src/system/kernel/arch/x86/arch_cpu.cpp          | 11 ++++-
src/system/kernel/arch/x86/arch_int.cpp          |  5 ++-
src/system/kernel/arch/x86/arch_vm.cpp           |  9 ++++
.../kernel/arch/x86/arch_vm_translation_map.cpp  | 17 ++++----
.../x86/paging/64bit/X86PagingMethod64Bit.cpp    | 14 +++++++
.../arch/x86/paging/64bit/X86PagingMethod64Bit.h |  2 +
.../paging/64bit/X86VMTranslationMap64Bit.cpp    | 10 ++++-
src/system/kernel/arch/x86/paging/64bit/paging.h |  4 +-
.../arch/x86/paging/pae/X86PagingMethodPAE.cpp   |  8 ++++
.../x86/paging/pae/X86VMTranslationMapPAE.cpp    | 12 +++++-
src/system/kernel/arch/x86/paging/pae/paging.h   |  3 +-
src/system/kernel/vm/vm.cpp                      | 44 ++++++++++++++------

############################################################################

Commit:      dd70092cd1f5ba48566f64598a610b39b655db3d
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Wed Mar  6 13:51:30 2013 UTC

x86: move x86_userspace_thread_exit() from user stack to commpage

x86_userspace_thread_exit() is a stub originally placed at the bottom of
each thread user stack that ensures any thread invokes exit_thread() upon
returning from its main higher level function.

Putting anything that is expected to be executed on a stack causes problems
when implementing data execution prevention. Code of x86_userspace_thread_exit()
is now moved to commpage which seems to be much more appropriate place for it.

----------------------------------------------------------------------------

diff --git a/headers/private/system/arch/x86/arch_commpage_defs.h 
b/headers/private/system/arch/x86/arch_commpage_defs.h
index 5f27f67..eb959e1 100644
--- a/headers/private/system/arch/x86/arch_commpage_defs.h
+++ b/headers/private/system/arch/x86/arch_commpage_defs.h
@@ -16,6 +16,8 @@
                                                                        
(COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 3)
 #define COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS \
                                                                        
(COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 4)
+#define COMMPAGE_ENTRY_X86_THREAD_EXIT \
+                                                                       
(COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 5)
 
 #define ARCH_USER_COMMPAGE_ADDR (0xffff0000)
 
diff --git a/headers/private/system/arch/x86_64/arch_commpage_defs.h 
b/headers/private/system/arch/x86_64/arch_commpage_defs.h
index bf7809e..dabf8f0 100644
--- a/headers/private/system/arch/x86_64/arch_commpage_defs.h
+++ b/headers/private/system/arch/x86_64/arch_commpage_defs.h
@@ -13,6 +13,8 @@
 #define COMMPAGE_ENTRY_X86_MEMSET      (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 1)
 #define COMMPAGE_ENTRY_X86_SIGNAL_HANDLER \
                                                                        
(COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 2)
+#define COMMPAGE_ENTRY_X86_THREAD_EXIT \
+                                                                       
(COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 3)
 
 #define ARCH_USER_COMMPAGE_ADDR                (0xffffffffffff0000)
 
diff --git a/src/system/kernel/arch/x86/32/arch.S 
b/src/system/kernel/arch/x86/32/arch.S
index 97eb069..90ef56b 100644
--- a/src/system/kernel/arch/x86/32/arch.S
+++ b/src/system/kernel/arch/x86/32/arch.S
@@ -115,7 +115,7 @@ FUNCTION(x86_swap_pgdir):
        ret
 FUNCTION_END(x86_swap_pgdir)
 
-/* thread exit stub - is copied to the userspace stack in 
arch_thread_enter_uspace() */
+/* thread exit stub */
        .align 4
 FUNCTION(x86_userspace_thread_exit):
        pushl   %eax
diff --git a/src/system/kernel/arch/x86/32/thread.cpp 
b/src/system/kernel/arch/x86/32/thread.cpp
index 9e13a7e..f50b5f4 100644
--- a/src/system/kernel/arch/x86/32/thread.cpp
+++ b/src/system/kernel/arch/x86/32/thread.cpp
@@ -13,6 +13,7 @@
 
 #include <arch/user_debugger.h>
 #include <arch_cpu.h>
+#include <commpage.h>
 #include <cpu.h>
 #include <debug.h>
 #include <kernel.h>
@@ -215,8 +216,6 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, 
void* args1,
        void* args2)
 {
        addr_t stackTop = thread->user_stack_base + thread->user_stack_size;
-       uint32 codeSize = (addr_t)x86_end_userspace_thread_exit
-               - (addr_t)x86_userspace_thread_exit;
        uint32 args[3];
 
        TRACE(("arch_thread_enter_userspace: entry 0x%lx, args %p %p, "
@@ -224,14 +223,11 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, 
void* args1,
 
        stackTop = arch_randomize_stack_pointer(stackTop);
 
-       // copy the little stub that calls exit_thread() when the thread entry
-       // function returns, as well as the arguments of the entry function
-       stackTop -= codeSize;
-
-       if (user_memcpy((void *)stackTop, (const void 
*)&x86_userspace_thread_exit, codeSize) < B_OK)
-               return B_BAD_ADDRESS;
-
-       args[0] = stackTop;
+       // Copy the address of the stub that calls exit_thread() when the thread
+       // entry function returns to the top of the stack to act as the return
+       // address. The stub is inside commpage.
+       args[0] = *(addr_t*)(USER_COMMPAGE_ADDR
+               + COMMPAGE_ENTRY_X86_THREAD_EXIT * sizeof(addr_t));
        args[1] = (uint32)args1;
        args[2] = (uint32)args2;
        stackTop -= sizeof(args);
diff --git a/src/system/kernel/arch/x86/64/arch.S 
b/src/system/kernel/arch/x86/64/arch.S
index cbaeec8..3f07b95 100644
--- a/src/system/kernel/arch/x86/64/arch.S
+++ b/src/system/kernel/arch/x86/64/arch.S
@@ -118,7 +118,7 @@ FUNCTION(x86_swap_pgdir):
 FUNCTION_END(x86_swap_pgdir)
 
 
-/* thread exit stub - copied to the userspace stack in 
arch_thread_enter_uspace() */
+/* thread exit stub */
 .align 8
 FUNCTION(x86_userspace_thread_exit):
        movq    %rax, %rdi
diff --git a/src/system/kernel/arch/x86/64/thread.cpp 
b/src/system/kernel/arch/x86/64/thread.cpp
index 8c5c2fa..4b80ea6 100644
--- a/src/system/kernel/arch/x86/64/thread.cpp
+++ b/src/system/kernel/arch/x86/64/thread.cpp
@@ -218,20 +218,11 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, 
void* args1,
 
        stackTop = arch_randomize_stack_pointer(stackTop);
 
-       // Copy the little stub that calls exit_thread() when the thread entry
-       // function returns.
-       // TODO: This will become a problem later if we want to support execute
-       // disable, the stack shouldn't really be executable.
-       size_t codeSize = (addr_t)x86_end_userspace_thread_exit
-               - (addr_t)x86_userspace_thread_exit;
-       stackTop -= codeSize;
-       if (user_memcpy((void*)stackTop, (const 
void*)&x86_userspace_thread_exit,
-                       codeSize) != B_OK)
-               return B_BAD_ADDRESS;
-
-       // Copy the address of the stub to the top of the stack to act as the
-       // return address.
-       addr_t codeAddr = stackTop;
+       // Copy the address of the stub that calls exit_thread() when the thread
+       // entry function returns to the top of the stack to act as the return
+       // address. The stub is inside commpage.
+       addr_t codeAddr = *(addr_t*)(USER_COMMPAGE_ADDR
+               + COMMPAGE_ENTRY_X86_THREAD_EXIT * sizeof(addr_t));
        stackTop -= sizeof(codeAddr);
        if (user_memcpy((void*)stackTop, (const void*)&codeAddr, 
sizeof(codeAddr))
                        != B_OK)
diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp 
b/src/system/kernel/arch/x86/arch_cpu.cpp
index 7438203..be6d488 100644
--- a/src/system/kernel/arch/x86/arch_cpu.cpp
+++ b/src/system/kernel/arch/x86/arch_cpu.cpp
@@ -868,6 +868,10 @@ arch_cpu_init_post_modules(kernel_args* args)
                - (addr_t)gOptimizedFunctions.memset;
        fill_commpage_entry(COMMPAGE_ENTRY_X86_MEMSET,
                (const void*)gOptimizedFunctions.memset, memsetLen);
+       size_t threadExitLen = (addr_t)x86_end_userspace_thread_exit
+               - (addr_t)x86_userspace_thread_exit;
+       fill_commpage_entry(COMMPAGE_ENTRY_X86_THREAD_EXIT,
+               (const void*)x86_userspace_thread_exit, threadExitLen);
 
        // add the functions to the commpage image
        image_id image = get_commpage_image();
@@ -877,6 +881,9 @@ arch_cpu_init_post_modules(kernel_args* args)
        elf_add_memory_image_symbol(image, "commpage_memset",
                ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_MEMSET], 
memsetLen,
                B_SYMBOL_TYPE_TEXT);
+       elf_add_memory_image_symbol(image, "commpage_thread_exit",
+               ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_THREAD_EXIT],
+               threadExitLen, B_SYMBOL_TYPE_TEXT);
 
        return B_OK;
 }

############################################################################

Commit:      0ea2d8a48853efcdfb7bf5293f6b6c50e8e05c39
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Wed Mar  6 17:03:54 2013 UTC

x86: enable data execution prevention

Set execute disable bit for any page that belongs to area with neither
B_EXECUTE_AREA nor B_KERNEL_EXECUTE_AREA set.

In order to take advanage of NX bit in 32 bit protected mode PAE must be
enabled. Thus, from now on it is also enabled when the CPU supports NX bit.

vm_page_fault() takes additional argument which indicates whether page fault
was caused by an illegal instruction fetch.

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/arch/x86/arch_cpu.h 
b/headers/private/kernel/arch/x86/arch_cpu.h
index 58694f3..bc9f4c8 100644
--- a/headers/private/kernel/arch/x86/arch_cpu.h
+++ b/headers/private/kernel/arch/x86/arch_cpu.h
@@ -39,6 +39,11 @@
 
 #define IA32_MSR_EFER                                  0xc0000080
 
+// MSR EFER bits
+// reference
+#define IA32_MSR_EFER_SYSCALL                  (1 << 0)
+#define IA32_MSR_EFER_NX                               (1 << 11)
+
 // x86_64 MSRs.
 #define IA32_MSR_STAR                                  0xc0000081
 #define IA32_MSR_LSTAR                                 0xc0000082
@@ -131,6 +136,13 @@
 #define IA32_FEATURE_AMD_EXT_3DNOWEXT  (1 << 30) // 3DNow! extensions
 #define IA32_FEATURE_AMD_EXT_3DNOW             (1 << 31) // 3DNow!
 
+// some of the features from cpuid eax 0x80000001, edx register (AMD) are also
+// available on Intel processors
+#define IA32_FEATURES_INTEL_EXT                        
(IA32_FEATURE_AMD_EXT_SYSCALL           \
+                                                                               
        | IA32_FEATURE_AMD_EXT_NX               \
+                                                                               
        | IA32_FEATURE_AMD_EXT_RDTSCP   \
+                                                                               
        | IA32_FEATURE_AMD_EXT_LONG)
+
 // x86 defined features from cpuid eax 6, eax register
 // reference http://www.intel.com/Assets/en_US/PDF/appnote/241618.pdf (Table 
5-11)
 #define IA32_FEATURE_DTS       (1 << 0) //Digital Thermal Sensor
diff --git a/headers/private/kernel/vm/vm_priv.h 
b/headers/private/kernel/vm/vm_priv.h
index afb15a7..9091c60 100644
--- a/headers/private/kernel/vm/vm_priv.h
+++ b/headers/private/kernel/vm/vm_priv.h
@@ -28,7 +28,7 @@ extern "C" {
 
 // Should only be used by vm internals
 status_t vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite,
-       bool isUser, addr_t *newip);
+       bool isExecute, bool isUser, addr_t *newip);
 void vm_unreserve_memory(size_t bytes);
 status_t vm_try_reserve_memory(size_t bytes, int priority, bigtime_t timeout);
 status_t vm_daemon_init(void);
diff --git a/src/system/kernel/arch/arm/arch_int.cpp 
b/src/system/kernel/arch/arm/arch_int.cpp
index b6f18d4..b41cc71 100644
--- a/src/system/kernel/arch/arm/arch_int.cpp
+++ b/src/system/kernel/arch/arm/arch_int.cpp
@@ -277,7 +277,7 @@ arch_arm_data_abort(struct iframe *frame)
 
        enable_interrupts();
 
-       vm_page_fault(far, frame->pc, isWrite, isUser, &newip);
+       vm_page_fault(far, frame->pc, isWrite, false, isUser, &newip);
 
        if (newip != 0) {
                // the page fault handler wants us to modify the iframe to set 
the
diff --git a/src/system/kernel/arch/m68k/arch_int.cpp 
b/src/system/kernel/arch/m68k/arch_int.cpp
index a982a75..b80942a 100644
--- a/src/system/kernel/arch/m68k/arch_int.cpp
+++ b/src/system/kernel/arch/m68k/arch_int.cpp
@@ -238,6 +238,7 @@ m68k_exception_entry(struct iframe *iframe)
 
                        vm_page_fault(fault_address(iframe), iframe->cpu.pc,
                                fault_was_write(iframe), // store or load
+                               false,
                                iframe->cpu.sr & SR_S, // was the system in 
user or supervisor
                                &newip);
                        if (newip != 0) {
diff --git a/src/system/kernel/arch/ppc/arch_int.cpp 
b/src/system/kernel/arch/ppc/arch_int.cpp
index 61ede96..ac1c60b 100644
--- a/src/system/kernel/arch/ppc/arch_int.cpp
+++ b/src/system/kernel/arch/ppc/arch_int.cpp
@@ -164,6 +164,7 @@ ppc_exception_entry(int vector, struct iframe *iframe)
 
                        vm_page_fault(iframe->dar, iframe->srr0,
                                iframe->dsisr & (1 << 25), // store or load
+                               false,
                                iframe->srr1 & (1 << 14), // was the system in 
user or supervisor
                                &newip);
                        if (newip != 0) {
diff --git a/src/system/kernel/arch/x86/64/syscalls.cpp 
b/src/system/kernel/arch/x86/64/syscalls.cpp
index 20bf44e..4407498 100644
--- a/src/system/kernel/arch/x86/64/syscalls.cpp
+++ b/src/system/kernel/arch/x86/64/syscalls.cpp
@@ -20,7 +20,8 @@ static void
 init_syscall_registers(void* dummy, int cpuNum)
 {
        // Enable SYSCALL (EFER.SCE = 1).
-       x86_write_msr(IA32_MSR_EFER, x86_read_msr(IA32_MSR_EFER) | (1 << 0));
+       x86_write_msr(IA32_MSR_EFER, x86_read_msr(IA32_MSR_EFER)
+               | IA32_MSR_EFER_SYSCALL);
 
        // Flags to clear upon entry. Want interrupts disabled and the direction
        // flag cleared.
diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp 
b/src/system/kernel/arch/x86/arch_cpu.cpp
index be6d488..cafc2da 100644
--- a/src/system/kernel/arch/x86/arch_cpu.cpp
+++ b/src/system/kernel/arch/x86/arch_cpu.cpp
@@ -605,10 +605,12 @@ detect_cpu(int currentCPU)
        get_current_cpuid(&cpuid, 1);
        cpu->arch.feature[FEATURE_COMMON] = cpuid.eax_1.features; // edx
        cpu->arch.feature[FEATURE_EXT] = cpuid.eax_1.extended_features; // ecx
-       if (cpu->arch.vendor == VENDOR_AMD) {
+       if (cpu->arch.vendor == VENDOR_AMD || cpu->arch.vendor == VENDOR_INTEL) 
{
                get_current_cpuid(&cpuid, 0x80000001);
                cpu->arch.feature[FEATURE_EXT_AMD] = cpuid.regs.edx; // edx
        }
+       if (cpu->arch.vendor == VENDOR_INTEL)
+               cpu->arch.feature[FEATURE_EXT_AMD] &= IA32_FEATURES_INTEL_EXT;
        get_current_cpuid(&cpuid, 6);
        cpu->arch.feature[FEATURE_6_EAX] = cpuid.regs.eax;
        cpu->arch.feature[FEATURE_6_ECX] = cpuid.regs.ecx;
diff --git a/src/system/kernel/arch/x86/arch_int.cpp 
b/src/system/kernel/arch/x86/arch_int.cpp
index 75e50a8..e183636 100644
--- a/src/system/kernel/arch/x86/arch_int.cpp
+++ b/src/system/kernel/arch/x86/arch_int.cpp
@@ -319,8 +319,9 @@ x86_page_fault_exception(struct iframe* frame)
        enable_interrupts();
 
        vm_page_fault(cr2, frame->ip,
-               (frame->error_code & 0x2) != 0, // write access
-               (frame->error_code & 0x4) != 0, // userland
+               (frame->error_code & 0x2)!= 0,          // write access
+               (frame->error_code & 0x10) != 0,        // instruction fetch
+               (frame->error_code & 0x4) != 0,         // userland
                &newip);
        if (newip != 0) {
                // the page fault handler wants us to modify the iframe to set 
the
diff --git a/src/system/kernel/arch/x86/arch_vm.cpp 
b/src/system/kernel/arch/x86/arch_vm.cpp
index 0aed76a..ae06305 100644
--- a/src/system/kernel/arch/x86/arch_vm.cpp
+++ b/src/system/kernel/arch/x86/arch_vm.cpp
@@ -728,6 +728,15 @@ arch_vm_supports_protection(uint32 protection)
                return false;
        }
 
+       // Userland and the kernel have the same setting of NX-bit.
+       // That's why we do not allow any area that user can access, but not 
execute
+       // and the kernel can execute.
+       if ((protection & (B_READ_AREA | B_WRITE_AREA)) != 0
+               && (protection & B_EXECUTE_AREA) == 0
+               && (protection & B_KERNEL_EXECUTE_AREA) != 0) {
+               return false;
+       }
+
        return true;
 }
 
diff --git a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp 
b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp
index 8362623..c2abe3f 100644
--- a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp
+++ b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp
@@ -86,13 +86,16 @@ arch_vm_translation_map_init(kernel_args *args,
        gX86PagingMethod = new(&sPagingMethodBuffer) X86PagingMethod64Bit;
 #elif B_HAIKU_PHYSICAL_BITS == 64
        bool paeAvailable = x86_check_feature(IA32_FEATURE_PAE, FEATURE_COMMON);
-       bool paeNeeded = false;
-       for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) {
-               phys_addr_t end = args->physical_memory_range[i].start
-                       + args->physical_memory_range[i].size;
-               if (end > 0x100000000LL) {
-                       paeNeeded = true;
-                       break;
+       bool paeNeeded = x86_check_feature(IA32_FEATURE_AMD_EXT_NX,
+               FEATURE_EXT_AMD);
+       if (!paeNeeded) {
+               for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) {
+                       phys_addr_t end = args->physical_memory_range[i].start
+                               + args->physical_memory_range[i].size;
+                       if (end > 0x100000000LL) {
+                               paeNeeded = true;
+                               break;
+                       }
                }
        }
 
diff --git a/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.cpp 
b/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.cpp
index e9dbf30..4dc8aff 100644
--- a/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.cpp
+++ b/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.cpp
@@ -59,6 +59,10 @@ X86PagingMethod64Bit::Init(kernel_args* args,
        fKernelPhysicalPML4 = args->arch_args.phys_pgdir;
        fKernelVirtualPML4 = (uint64*)(addr_t)args->arch_args.vir_pgdir;
 
+       // enable NX-bit on all CPUs
+       if (x86_check_feature(IA32_FEATURE_AMD_EXT_NX, FEATURE_EXT_AMD))
+               call_all_cpus_sync(&_EnableExecutionDisable, NULL);
+
        // Ensure that the user half of the address space is clear. This removes
        // the temporary identity mapping made by the boot loader.
        memset(fKernelVirtualPML4, 0, sizeof(uint64) * 256);
@@ -324,6 +328,8 @@ X86PagingMethod64Bit::PutPageTableEntryInTable(uint64* 
entry,
                page |= X86_64_PTE_USER;
                if ((attributes & B_WRITE_AREA) != 0)
                        page |= X86_64_PTE_WRITABLE;
+               if ((attributes & B_EXECUTE_AREA) == 0)
+                       page |= X86_64_PTE_NOT_EXECUTABLE;
        } else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
                page |= X86_64_PTE_WRITABLE;
 
@@ -331,3 +337,11 @@ X86PagingMethod64Bit::PutPageTableEntryInTable(uint64* 
entry,
        SetTableEntry(entry, page);
 }
 
+
+void
+X86PagingMethod64Bit::_EnableExecutionDisable(void* dummy, int cpu)
+{
+       x86_write_msr(IA32_MSR_EFER, x86_read_msr(IA32_MSR_EFER)
+               | IA32_MSR_EFER_NX);
+}
+
diff --git a/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.h 
b/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.h
index 130e14d..480a99d 100644
--- a/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.h
+++ b/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.h
@@ -84,6 +84,8 @@ public:
                                                                        uint32 
memoryType);
 
 private:
+       static  void                            _EnableExecutionDisable(void* 
dummy, int cpu);
+
                        phys_addr_t                     fKernelPhysicalPML4;
                        uint64*                         fKernelVirtualPML4;
 
diff --git 
a/src/system/kernel/arch/x86/paging/64bit/X86VMTranslationMap64Bit.cpp 
b/src/system/kernel/arch/x86/paging/64bit/X86VMTranslationMap64Bit.cpp
index 70ce26b..52f3a64 100644
--- a/src/system/kernel/arch/x86/paging/64bit/X86VMTranslationMap64Bit.cpp
+++ b/src/system/kernel/arch/x86/paging/64bit/X86VMTranslationMap64Bit.cpp
@@ -617,11 +617,13 @@ X86VMTranslationMap64Bit::Query(addr_t virtualAddress,
        // Translate the page state flags.
        if ((entry & X86_64_PTE_USER) != 0) {
                *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 
0)
-                       | B_READ_AREA;
+                       | B_READ_AREA
+                       | ((entry & X86_64_PTE_NOT_EXECUTABLE) == 0 ? 
B_EXECUTE_AREA : 0);
        }
 
        *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 
0)
                | B_KERNEL_READ_AREA
+               | ((entry & X86_64_PTE_NOT_EXECUTABLE) == 0 ? 
B_KERNEL_EXECUTE_AREA : 0)
                | ((entry & X86_64_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
                | ((entry & X86_64_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
                | ((entry & X86_64_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
@@ -661,11 +663,13 @@ X86VMTranslationMap64Bit::QueryInterrupt(addr_t 
virtualAddress,
        // Translate the page state flags.
        if ((entry & X86_64_PTE_USER) != 0) {
                *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 
0)
-                       | B_READ_AREA;
+                       | B_READ_AREA
+                       | ((entry & X86_64_PTE_NOT_EXECUTABLE) == 0 ? 
B_EXECUTE_AREA : 0);
        }
 
        *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 
0)
                | B_KERNEL_READ_AREA
+               | ((entry & X86_64_PTE_NOT_EXECUTABLE) == 0 ? 
B_KERNEL_EXECUTE_AREA : 0)
                | ((entry & X86_64_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
                | ((entry & X86_64_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
                | ((entry & X86_64_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
@@ -694,6 +698,8 @@ X86VMTranslationMap64Bit::Protect(addr_t start, addr_t end, 
uint32 attributes,
                newProtectionFlags = X86_64_PTE_USER;
                if ((attributes & B_WRITE_AREA) != 0)
                        newProtectionFlags |= X86_64_PTE_WRITABLE;
+               if ((attributes & B_EXECUTE_AREA) == 0)
+                       newProtectionFlags |= X86_64_PTE_NOT_EXECUTABLE;
        } else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
                newProtectionFlags = X86_64_PTE_WRITABLE;
 
diff --git a/src/system/kernel/arch/x86/paging/64bit/paging.h 
b/src/system/kernel/arch/x86/paging/64bit/paging.h
index 2cb4fb4..a99afaa 100644
--- a/src/system/kernel/arch/x86/paging/64bit/paging.h
+++ b/src/system/kernel/arch/x86/paging/64bit/paging.h
@@ -59,7 +59,9 @@
 #define X86_64_PTE_GLOBAL                              (1LL << 8)
 #define X86_64_PTE_NOT_EXECUTABLE              (1LL << 63)
 #define X86_64_PTE_ADDRESS_MASK                        0x000ffffffffff000L
-#define X86_64_PTE_PROTECTION_MASK             (X86_64_PTE_WRITABLE | 
X86_64_PTE_USER)
+#define X86_64_PTE_PROTECTION_MASK             (X86_64_PTE_NOT_EXECUTABLE      
\
+                                                                               
        | X86_64_PTE_WRITABLE   \
+                                                                               
        | X86_64_PTE_USER)
 #define X86_64_PTE_MEMORY_TYPE_MASK            (X86_64_PTE_WRITE_THROUGH \
                                                                                
        | X86_64_PTE_CACHING_DISABLED)
 
diff --git a/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.cpp 
b/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.cpp
index 34258f0..d2071bc 100644
--- a/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.cpp
+++ b/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.cpp
@@ -165,6 +165,12 @@ private:
        {
                x86_write_cr3((addr_t)physicalPDPT);
                x86_write_cr4(x86_read_cr4() | IA32_CR4_PAE | 
IA32_CR4_GLOBAL_PAGES);
+
+               // if availalbe enable NX-bit (No eXecute)
+               if (x86_check_feature(IA32_FEATURE_AMD_EXT_NX, 
FEATURE_EXT_AMD)) {
+                       x86_write_msr(IA32_MSR_EFER, x86_read_msr(IA32_MSR_EFER)
+                               | IA32_MSR_EFER_NX);
+               }
        }
 
        void _TranslatePageTable(addr_t virtualBase)
@@ -778,6 +784,8 @@ 
X86PagingMethodPAE::PutPageTableEntryInTable(pae_page_table_entry* entry,
                page |= X86_PAE_PTE_USER;
                if ((attributes & B_WRITE_AREA) != 0)
                        page |= X86_PAE_PTE_WRITABLE;
+               if ((attributes & B_EXECUTE_AREA) == 0)
+                       page |= X86_PAE_PTE_NOT_EXECUTABLE;
        } else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
                page |= X86_PAE_PTE_WRITABLE;
 
diff --git a/src/system/kernel/arch/x86/paging/pae/X86VMTranslationMapPAE.cpp 
b/src/system/kernel/arch/x86/paging/pae/X86VMTranslationMapPAE.cpp
index 8d68536..c936af4 100644
--- a/src/system/kernel/arch/x86/paging/pae/X86VMTranslationMapPAE.cpp
+++ b/src/system/kernel/arch/x86/paging/pae/X86VMTranslationMapPAE.cpp
@@ -687,11 +687,14 @@ X86VMTranslationMapPAE::Query(addr_t virtualAddress,
        // translate the page state flags
        if ((entry & X86_PAE_PTE_USER) != 0) {
                *_flags |= ((entry & X86_PAE_PTE_WRITABLE) != 0 ? B_WRITE_AREA 
: 0)
-                       | B_READ_AREA;
+                       | B_READ_AREA
+                       | ((entry & X86_PAE_PTE_NOT_EXECUTABLE) == 0 ? 
B_EXECUTE_AREA : 0);
        }
 
        *_flags |= ((entry & X86_PAE_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 
0)
                | B_KERNEL_READ_AREA
+               | ((entry & X86_PAE_PTE_NOT_EXECUTABLE) == 0
+                       ? B_KERNEL_EXECUTE_AREA : 0)
                | ((entry & X86_PAE_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
                | ((entry & X86_PAE_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
                | ((entry & X86_PAE_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
@@ -733,11 +736,14 @@ X86VMTranslationMapPAE::QueryInterrupt(addr_t 
virtualAddress,
        // translate the page state flags
        if ((entry & X86_PAE_PTE_USER) != 0) {
                *_flags |= ((entry & X86_PAE_PTE_WRITABLE) != 0 ? B_WRITE_AREA 
: 0)
-                       | B_READ_AREA;
+                       | B_READ_AREA
+                       | ((entry & X86_PAE_PTE_NOT_EXECUTABLE) == 0 ? 
B_EXECUTE_AREA : 0);
        }
 
        *_flags |= ((entry & X86_PAE_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 
0)
                | B_KERNEL_READ_AREA
+               | ((entry & X86_PAE_PTE_NOT_EXECUTABLE) == 0
+                       ? B_KERNEL_EXECUTE_AREA : 0)
                | ((entry & X86_PAE_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
                | ((entry & X86_PAE_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
                | ((entry & X86_PAE_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
@@ -766,6 +772,8 @@ X86VMTranslationMapPAE::Protect(addr_t start, addr_t end, 
uint32 attributes,
                newProtectionFlags = X86_PAE_PTE_USER;
                if ((attributes & B_WRITE_AREA) != 0)
                        newProtectionFlags |= X86_PAE_PTE_WRITABLE;
+               if ((attributes & B_EXECUTE_AREA) == 0)
+                       newProtectionFlags |= X86_PAE_PTE_NOT_EXECUTABLE;
        } else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
                newProtectionFlags = X86_PAE_PTE_WRITABLE;
 
diff --git a/src/system/kernel/arch/x86/paging/pae/paging.h 
b/src/system/kernel/arch/x86/paging/pae/paging.h
index ae6d45b..0567dac 100644
--- a/src/system/kernel/arch/x86/paging/pae/paging.h
+++ b/src/system/kernel/arch/x86/paging/pae/paging.h
@@ -49,7 +49,8 @@
 #define X86_PAE_PTE_IGNORED3                   0x0000000000000800LL
 #define X86_PAE_PTE_ADDRESS_MASK               0x000ffffffffff000LL
 #define X86_PAE_PTE_NOT_EXECUTABLE             0x8000000000000000LL
-#define X86_PAE_PTE_PROTECTION_MASK            (X86_PAE_PTE_WRITABLE \
+#define X86_PAE_PTE_PROTECTION_MASK            (X86_PAE_PTE_NOT_EXECUTABLE     
\
+                                                                               
        |X86_PAE_PTE_WRITABLE   \
                                                                                
        | X86_PAE_PTE_USER)
 #define X86_PAE_PTE_MEMORY_TYPE_MASK   (X86_PAE_PTE_WRITE_THROUGH \
                                                                                
        | X86_PAE_PTE_CACHING_DISABLED)
diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp
index fb6c246..f9a2f4d 100644
--- a/src/system/kernel/vm/vm.cpp
+++ b/src/system/kernel/vm/vm.cpp
@@ -267,7 +267,7 @@ static cache_info* sCacheInfoTable;
 static void delete_area(VMAddressSpace* addressSpace, VMArea* area,
        bool addressSpaceCleanup);
 static status_t vm_soft_fault(VMAddressSpace* addressSpace, addr_t address,
-       bool isWrite, bool isUser, vm_page** wirePage,
+       bool isWrite, bool isExecute, bool isUser, vm_page** wirePage,
        VMAreaWiredRange* wiredRange = NULL);
 static status_t map_backing_store(VMAddressSpace* addressSpace,
        VMCache* cache, off_t offset, const char* areaName, addr_t size, int 
wiring,
@@ -315,6 +315,7 @@ enum {
        PAGE_FAULT_ERROR_KERNEL_ONLY,
        PAGE_FAULT_ERROR_WRITE_PROTECTED,
        PAGE_FAULT_ERROR_READ_PROTECTED,
+       PAGE_FAULT_ERROR_EXECUTE_PROTECTED,
        PAGE_FAULT_ERROR_KERNEL_BAD_USER_MEMORY,
        PAGE_FAULT_ERROR_NO_ADDRESS_SPACE
 };
@@ -346,6 +347,10 @@ public:
                        case PAGE_FAULT_ERROR_READ_PROTECTED:
                                out.Print("page fault error: area: %ld, read 
protected", fArea);
                                break;
+                       case PAGE_FAULT_ERROR_EXECUTE_PROTECTED:
+                               out.Print("page fault error: area: %ld, execute 
protected",
+                                       fArea);
+                               break;
                        case PAGE_FAULT_ERROR_KERNEL_BAD_USER_MEMORY:
                                out.Print("page fault error: kernel touching 
bad user memory");
                                break;
@@ -3994,8 +3999,8 @@ forbid_page_faults(void)
 
 
 status_t
-vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser,
-       addr_t* newIP)
+vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool 
isExecute,
+       bool isUser, addr_t* newIP)
 {
        FTRACE(("vm_page_fault: page fault at 0x%lx, ip 0x%lx\n", address,
                faultAddress));
@@ -4038,8 +4043,8 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool 
isWrite, bool isUser,
        }
 
        if (status == B_OK) {
-               status = vm_soft_fault(addressSpace, pageAddress, isWrite, 
isUser,
-                       NULL);
+               status = vm_soft_fault(addressSpace, pageAddress, isWrite, 
isExecute,
+                       isUser, NULL);
        }
 
        if (status < B_OK) {
@@ -4074,8 +4079,8 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool 
isWrite, bool isUser,
                                "\"%s\" (%" B_PRId32 ") tried to %s address 
%#lx, ip %#lx "
                                "(\"%s\" +%#lx)\n", thread->name, thread->id,
                                thread->team->Name(), thread->team->id,
-                               isWrite ? "write" : "read", address, 
faultAddress,
-                               area ? area->name : "???", faultAddress - (area 
?
+                               isWrite ? "write" : (isExecute ? "execute" : 
"read"), address,
+                               faultAddress, area ? area->name : "???", 
faultAddress - (area ?
                                        area->Base() : 0x0));
 
                        // We can print a stack trace of the userland thread 
here.
@@ -4364,7 +4369,8 @@ fault_get_page(PageFaultContext& context)
 */
 static status_t
 vm_soft_fault(VMAddressSpace* addressSpace, addr_t originalAddress,
-       bool isWrite, bool isUser, vm_page** wirePage, VMAreaWiredRange* 
wiredRange)
+       bool isWrite, bool isExecute, bool isUser, vm_page** wirePage,
+       VMAreaWiredRange* wiredRange)
 {
        FTRACE(("vm_soft_fault: thid 0x%" B_PRIx32 " address 0x%" B_PRIxADDR ", 
"
                "isWrite %d, isUser %d\n", thread_get_current_thread_id(),
@@ -4419,7 +4425,16 @@ vm_soft_fault(VMAddressSpace* addressSpace, addr_t 
originalAddress,
                                
VMPageFaultTracing::PAGE_FAULT_ERROR_WRITE_PROTECTED));
                        status = B_PERMISSION_DENIED;
                        break;
-               } else if (!isWrite && (protection
+               } else if (isExecute && (protection
+                               & (B_EXECUTE_AREA
+                                       | (isUser ? 0 : 
B_KERNEL_EXECUTE_AREA))) == 0) {
+                       dprintf("instruction fetch attempted on 
execute-protected area 0x%"
+                               B_PRIx32 " at %p\n", area->id, 
(void*)originalAddress);
+                       TPF(PageFaultError(area->id,
+                               
VMPageFaultTracing::PAGE_FAULT_ERROR_EXECUTE_PROTECTED));
+                       status = B_PERMISSION_DENIED;
+                       break;
+               } else if (!isWrite && !isExecute && (protection
                                & (B_READ_AREA | (isUser ? 0 : 
B_KERNEL_READ_AREA))) == 0) {
                        dprintf("read access attempted on read-protected area 
0x%" B_PRIx32
                                " at %p\n", area->id, (void*)originalAddress);
@@ -4756,7 +4771,8 @@ vm_set_area_memory_type(area_id id, phys_addr_t 
physicalBase, uint32 type)
 
 
 /*!    This function enforces some protection properties:
-        - if B_WRITE_AREA is set, B_WRITE_KERNEL_AREA is set as well
+        - if B_WRITE_AREA is set, B_KERNEL_WRITE_AREA is set as well
+        - if B_EXECUTE_AREA is set, B_KERNEL_EXECUTE_AREA is set as well
         - if only B_READ_AREA has been set, B_KERNEL_READ_AREA is also set
         - if no protection is specified, it defaults to B_KERNEL_READ_AREA
           and B_KERNEL_WRITE_AREA.
@@ -4770,6 +4786,8 @@ fix_protection(uint32* protection)
                        *protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA;
                else
                        *protection |= B_KERNEL_READ_AREA;
+               if ((*protection & B_EXECUTE_AREA) != 0)
+                       *protection |= B_KERNEL_EXECUTE_AREA;
        }
 }
 
@@ -5222,8 +5240,8 @@ vm_wire_page(team_id team, addr_t address, bool writable,
                cacheChainLocker.Unlock();
                addressSpaceLocker.Unlock();
 
-               error = vm_soft_fault(addressSpace, pageAddress, writable, 
isUser,
-                       &page, &info->range);
+               error = vm_soft_fault(addressSpace, pageAddress, writable, 
false,
+                       isUser, &page, &info->range);
 
                if (error != B_OK) {
                        // The page could not be mapped -- clean up.
@@ -5401,7 +5419,7 @@ lock_memory_etc(team_id team, void* address, size_t 
numBytes, uint32 flags)
                                addressSpaceLocker.Unlock();
 
                                error = vm_soft_fault(addressSpace, 
nextAddress, writable,
-                                       isUser, &page, range);
+                                       false, isUser, &page, range);
 
                                addressSpaceLocker.Lock();
                                
cacheChainLocker.SetTo(vm_area_get_locked_cache(area));


Other related posts:

  • » [haiku-commits] BRANCH pdziepak-github.aslr - in src/system/kernel: vm arch/x86 arch/x86/64 arch/x86/paging/64bit arch/x86/paging/pae - pdziepak-github . aslr