From f60b37ea1bf026787ab8d6643aa24597340c5bb7 Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Tue, 8 Apr 2014 17:36:03 +0900 Subject: [PATCH 1/4] use 'enum ihk_mc_pt_attribute' instead of 'int' --- arch/x86/kernel/include/arch-memory.h | 4 ++-- arch/x86/kernel/memory.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/include/arch-memory.h b/arch/x86/kernel/include/arch-memory.h index aea5691d..fb523be6 100644 --- a/arch/x86/kernel/include/arch-memory.h +++ b/arch/x86/kernel/include/arch-memory.h @@ -142,8 +142,8 @@ static inline uintptr_t pte_get_phys(pte_t *ptep) } struct page_table; -void set_pte(pte_t *ppte, unsigned long phys, int attr); -pte_t *get_pte(struct page_table *pt, void *virt, int attr); +void set_pte(pte_t *ppte, unsigned long phys, enum ihk_mc_pt_attribute attr); +pte_t *get_pte(struct page_table *pt, void *virt, enum ihk_mc_pt_attribute attr); void *early_alloc_page(void); void *get_last_early_heap(void); diff --git a/arch/x86/kernel/memory.c b/arch/x86/kernel/memory.c index d9150724..e7659c40 100644 --- a/arch/x86/kernel/memory.c +++ b/arch/x86/kernel/memory.c @@ -266,7 +266,7 @@ static unsigned long attr_to_l1attr(enum ihk_mc_pt_attribute attr) | ((uint64_t)(l1i) << PTL1_SHIFT) \ ) -void set_pte(pte_t *ppte, unsigned long phys, int attr) +void set_pte(pte_t *ppte, unsigned long phys, enum ihk_mc_pt_attribute attr) { if (attr & PTATTR_LARGEPAGE) { *ppte = phys | attr_to_l2attr(attr) | PFL2_SIZE; @@ -285,7 +285,7 @@ void set_pte(pte_t *ppte, unsigned long phys, int attr) * and returns a pointer to the PTE corresponding to the * virtual address. */ -pte_t *get_pte(struct page_table *pt, void *virt, int attr, enum ihk_mc_ap_flag ap_flag) +pte_t *get_pte(struct page_table *pt, void *virt, enum ihk_mc_pt_attribute attr, enum ihk_mc_ap_flag ap_flag) { int l4idx, l3idx, l2idx, l1idx; unsigned long v = (unsigned long)virt; @@ -341,7 +341,7 @@ pte_t *get_pte(struct page_table *pt, void *virt, int attr, enum ihk_mc_ap_flag #endif static int __set_pt_page(struct page_table *pt, void *virt, unsigned long phys, - int attr) + enum ihk_mc_pt_attribute attr) { int l4idx, l3idx, l2idx, l1idx; unsigned long v = (unsigned long)virt; From b31a1b6db28c03fa80b5e44f9294c4f4baa7499a Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Tue, 8 Apr 2014 19:17:42 +0900 Subject: [PATCH 2/4] add PTATTR_NO_EXECUTE --- arch/x86/kernel/include/arch-memory.h | 3 ++- arch/x86/kernel/memory.c | 12 ++++++++---- kernel/host.c | 18 ++++++++++++------ kernel/process.c | 9 ++++++++- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/include/arch-memory.h b/arch/x86/kernel/include/arch-memory.h index fb523be6..035ea621 100644 --- a/arch/x86/kernel/include/arch-memory.h +++ b/arch/x86/kernel/include/arch-memory.h @@ -114,6 +114,7 @@ enum ihk_mc_pt_attribute { PTATTR_WRITABLE = 0x02, PTATTR_USER = 0x04, PTATTR_LARGEPAGE = 0x80, + PTATTR_NO_EXECUTE = 0x8000000000000000, PTATTR_UNCACHABLE = 0x10000, PTATTR_FOR_USER = 0x20000, }; @@ -156,5 +157,5 @@ void *map_fixed_area(unsigned long phys, unsigned long size, int uncachable); #define AP_TRAMPOLINE_SIZE 0x4000 /* Local is cachable */ -#define IHK_IKC_QUEUE_PT_ATTR (PTATTR_WRITABLE | PTATTR_UNCACHABLE) +#define IHK_IKC_QUEUE_PT_ATTR (PTATTR_NO_EXECUTE | PTATTR_WRITABLE | PTATTR_UNCACHABLE) #endif diff --git a/arch/x86/kernel/memory.c b/arch/x86/kernel/memory.c index e7659c40..32181fd2 100644 --- a/arch/x86/kernel/memory.c +++ b/arch/x86/kernel/memory.c @@ -1666,21 +1666,25 @@ void *map_fixed_area(unsigned long phys, unsigned long size, int uncachable) { unsigned long poffset, paligned; int i, npages; - int flag = PTATTR_WRITABLE | PTATTR_ACTIVE; void *v = (void *)fixed_virt; + enum ihk_mc_pt_attribute attr; poffset = phys & (PAGE_SIZE - 1); paligned = phys & PAGE_MASK; npages = (poffset + size + PAGE_SIZE - 1) >> PAGE_SHIFT; + attr = PTATTR_WRITABLE | PTATTR_ACTIVE; +#if 0 /* In the case of LAPIC MMIO, something will happen */ + attr |= PTATTR_NO_EXECUTE; +#endif if (uncachable) { - flag |= PTATTR_UNCACHABLE; + attr |= PTATTR_UNCACHABLE; } kprintf("map_fixed: %lx => %p (%d pages)\n", paligned, v, npages); for (i = 0; i < npages; i++) { - if(__set_pt_page(init_pt, (void *)fixed_virt, paligned, flag)){ + if(__set_pt_page(init_pt, (void *)fixed_virt, paligned, attr)){ return NULL; } @@ -1695,7 +1699,7 @@ void *map_fixed_area(unsigned long phys, unsigned long size, int uncachable) void init_low_area(struct page_table *pt) { - set_pt_large_page(pt, 0, 0, PTATTR_WRITABLE); + set_pt_large_page(pt, 0, 0, PTATTR_NO_EXECUTE|PTATTR_WRITABLE); } static void init_vsyscall_area(struct page_table *pt) diff --git a/kernel/host.c b/kernel/host.c index a130e17b..c357cb3d 100644 --- a/kernel/host.c +++ b/kernel/host.c @@ -69,13 +69,16 @@ static int process_msg_prepare_process(unsigned long rphys) unsigned long flags; uintptr_t interp_obase = -1; uintptr_t interp_nbase = -1; + enum ihk_mc_pt_attribute attr; + + attr = PTATTR_NO_EXECUTE | PTATTR_WRITABLE | PTATTR_FOR_USER; sz = sizeof(struct program_load_desc) + sizeof(struct program_image_section) * 16; npages = ((rphys + sz - 1) >> PAGE_SHIFT) - (rphys >> PAGE_SHIFT) + 1; phys = ihk_mc_map_memory(NULL, rphys, sz); - if((p = ihk_mc_map_virtual(phys, npages, PTATTR_WRITABLE | PTATTR_FOR_USER)) == NULL){ + if((p = ihk_mc_map_virtual(phys, npages, attr)) == NULL){ ihk_mc_unmap_memory(NULL, phys, sz); return -ENOMEM; } @@ -264,7 +267,7 @@ static int process_msg_prepare_process(unsigned long rphys) args_envs_rp = ihk_mc_map_memory(NULL, (unsigned long)p->args, p->args_len); dkprintf("args_envs_rp: 0x%lX\n", args_envs_rp); if((args_envs_r = (char *)ihk_mc_map_virtual(args_envs_rp, args_envs_npages, - PTATTR_WRITABLE | PTATTR_FOR_USER)) == NULL){ + attr)) == NULL){ goto err; } dkprintf("args_envs_r: 0x%lX\n", args_envs_r); @@ -285,7 +288,7 @@ static int process_msg_prepare_process(unsigned long rphys) args_envs_rp = ihk_mc_map_memory(NULL, (unsigned long)p->envs, p->envs_len); dkprintf("args_envs_rp: 0x%lX\n", args_envs_rp); if((args_envs_r = (char *)ihk_mc_map_virtual(args_envs_rp, args_envs_npages, - PTATTR_WRITABLE | PTATTR_FOR_USER)) == NULL){ + attr)) == NULL){ goto err; } dkprintf("args_envs_r: 0x%lX\n", args_envs_r); @@ -363,6 +366,9 @@ static void process_msg_init_acked(struct ihk_ikc_channel_desc *c, unsigned long { struct ikc_scd_init_param *param = (void *)pphys; struct syscall_params *lparam; + enum ihk_mc_pt_attribute attr; + + attr = PTATTR_NO_EXECUTE | PTATTR_WRITABLE | PTATTR_FOR_USER; lparam = &cpu_local_var(scp); if(cpu_local_var(syscall_channel2) == c) @@ -372,7 +378,7 @@ static void process_msg_init_acked(struct ihk_ikc_channel_desc *c, unsigned long REQUEST_PAGE_COUNT * PAGE_SIZE); if((lparam->request_va = ihk_mc_map_virtual(lparam->request_pa, REQUEST_PAGE_COUNT, - PTATTR_WRITABLE | PTATTR_FOR_USER)) == NULL){ + attr)) == NULL){ // TODO: panic("ENOMEM"); } @@ -383,7 +389,7 @@ static void process_msg_init_acked(struct ihk_ikc_channel_desc *c, unsigned long PAGE_SIZE); if((lparam->doorbell_va = ihk_mc_map_virtual(lparam->doorbell_pa, DOORBELL_PAGE_COUNT, - PTATTR_WRITABLE | PTATTR_FOR_USER)) == NULL){ + attr)) == NULL){ // TODO: panic("ENOMEM"); } @@ -392,7 +398,7 @@ static void process_msg_init_acked(struct ihk_ikc_channel_desc *c, unsigned long lparam->post_pa = ihk_mc_map_memory(NULL, param->post_page, PAGE_SIZE); if((lparam->post_va = ihk_mc_map_virtual(lparam->post_pa, 1, - PTATTR_WRITABLE | PTATTR_FOR_USER)) == NULL){ + attr)) == NULL){ // TODO: panic("ENOMEM"); } diff --git a/kernel/process.c b/kernel/process.c index c128d4da..d0b194d0 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -348,6 +348,7 @@ int update_process_page_table(struct process *process, attr = flag | PTATTR_USER | PTATTR_FOR_USER; attr |= (range->flag & VR_PROT_WRITE)? PTATTR_WRITABLE: 0; + attr |= (range->flag & VR_PROT_EXEC)? 0: PTATTR_NO_EXECUTE; p = range->start; while (p < range->end) { @@ -690,6 +691,10 @@ enum ihk_mc_pt_attribute vrflag_to_ptattr(unsigned long flag) attr |= PTATTR_WRITABLE; } + if (!(flag & VR_PROT_EXEC)) { + attr |= PTATTR_NO_EXECUTE; + } + return attr; } @@ -1198,7 +1203,9 @@ static int do_page_fault_process(struct process *proc, void *fault_addr0, uint64 if (((range->flag & VR_PROT_MASK) == VR_PROT_NONE) || ((reason & PF_WRITE) - && !(range->flag & VR_PROT_WRITE))) { + && !(range->flag & VR_PROT_WRITE)) + || ((reason & PF_INSTR) + && !(range->flag & VR_PROT_EXEC))) { error = -EFAULT; kprintf("[%d]do_page_fault_process(%p,%lx,%lx):" "access denied. %d\n", From 39a86fad18fd1b8bec5e19b4ee62689084a56172 Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Tue, 8 Apr 2014 20:22:55 +0900 Subject: [PATCH 3/4] support execute disabled stack --- executer/include/uprotocol.h | 1 + executer/user/mcexec.c | 7 +++++++ kernel/include/syscall.h | 1 + kernel/process.c | 4 ++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/executer/include/uprotocol.h b/executer/include/uprotocol.h index bcb2681f..88a19316 100644 --- a/executer/include/uprotocol.h +++ b/executer/include/uprotocol.h @@ -65,6 +65,7 @@ struct program_load_desc { int cpu; int pid; int err; + int stack_prot; unsigned long entry; unsigned long user_start; unsigned long user_end; diff --git a/executer/user/mcexec.c b/executer/user/mcexec.c index 1d809cff..c9d64a3a 100644 --- a/executer/user/mcexec.c +++ b/executer/user/mcexec.c @@ -159,6 +159,7 @@ struct program_load_desc *load_elf(FILE *fp, char **interp_pathp) fseek(fp, hdr.e_phoff, SEEK_SET); j = 0; desc->num_sections = nhdrs; + desc->stack_prot = PROT_READ | PROT_WRITE | PROT_EXEC; /* default */ for (i = 0; i < hdr.e_phnum; i++) { if (fread(&phdr, sizeof(phdr), 1, fp) < 1) { __eprintf("Loading phdr failed (%d)\n", i); @@ -205,6 +206,12 @@ struct program_load_desc *load_elf(FILE *fp, char **interp_pathp) load_addr = phdr.p_vaddr - phdr.p_offset; } } + if (phdr.p_type == PT_GNU_STACK) { + desc->stack_prot = PROT_NONE; + desc->stack_prot |= (phdr.p_flags & PF_R)? PROT_READ: 0; + desc->stack_prot |= (phdr.p_flags & PF_W)? PROT_WRITE: 0; + desc->stack_prot |= (phdr.p_flags & PF_X)? PROT_EXEC: 0; + } } desc->pid = getpid(); desc->entry = hdr.e_entry; diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index bb945e1c..1eea16fb 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -109,6 +109,7 @@ struct program_load_desc { int cpu; int pid; int err; + int stack_prot; unsigned long entry; unsigned long user_start; unsigned long user_end; diff --git a/kernel/process.c b/kernel/process.c index d0b194d0..60cfa649 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -1333,8 +1333,8 @@ int init_process_stack(struct process *process, struct program_load_desc *pn, start = end - size; vrflag = VR_STACK | VR_DEMAND_PAGING; - vrflag |= VR_PROT_READ | VR_PROT_WRITE | VR_PROT_EXEC; - vrflag |= VRFLAG_PROT_TO_MAXPROT(vrflag); + vrflag |= PROT_TO_VR_FLAG(pn->stack_prot); + vrflag |= VR_MAXPROT_READ | VR_MAXPROT_WRITE | VR_MAXPROT_EXEC; #define NOPHYS ((uintptr_t)-1) if ((rc = add_process_memory_range(process, start, end, NOPHYS, vrflag, NULL, 0)) != 0) { From 56f0d3b29f328c35ff57c171648dea786d009179 Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Tue, 8 Apr 2014 19:20:02 +0900 Subject: [PATCH 4/4] support IA-32e's "execute disable bit" --- arch/x86/kernel/cpu.c | 38 ++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/memory.c | 10 +++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu.c b/arch/x86/kernel/cpu.c index 82c59e93..4432ddd5 100644 --- a/arch/x86/kernel/cpu.c +++ b/arch/x86/kernel/cpu.c @@ -311,9 +311,45 @@ static void enable_page_protection_fault(void) return; } +static int no_execute_available = 0; + +static void enable_no_execute(void) +{ + unsigned long efer; + + if (!no_execute_available) { + return; + } + + efer = rdmsr(MSR_EFER); +#define IA32_EFER_NXE (1UL << 11) + efer |= IA32_EFER_NXE; + wrmsr(MSR_EFER, efer); + + return; +} + +static void check_no_execute(void) +{ + uint32_t edx; + extern void enable_ptattr_no_execute(void); + + /* check Execute Disable Bit available bit */ + asm ("cpuid" : "=d" (edx) : "a" (0x80000001) : "%rbx", "%rcx"); + no_execute_available = (edx & (1 << 20))? 1: 0; + kprintf("no_execute_available: %d\n", no_execute_available); + + if (no_execute_available) { + enable_ptattr_no_execute(); + } + + return; +} + void init_cpu(void) { enable_page_protection_fault(); + enable_no_execute(); init_fpu(); init_lapic(); init_syscall(); @@ -330,6 +366,8 @@ void setup_x86(void) init_page_table(); + check_no_execute(); + init_cpu(); kprintf("setup_x86 done.\n"); diff --git a/arch/x86/kernel/memory.c b/arch/x86/kernel/memory.c index 32181fd2..c765cb49 100644 --- a/arch/x86/kernel/memory.c +++ b/arch/x86/kernel/memory.c @@ -219,7 +219,15 @@ static struct page_table *__alloc_new_pt(enum ihk_mc_ap_flag ap_flag) * but L2 and L1 do not! */ -#define ATTR_MASK (PTATTR_WRITABLE | PTATTR_USER | PTATTR_ACTIVE) +static enum ihk_mc_pt_attribute attr_mask = PTATTR_WRITABLE | PTATTR_USER | PTATTR_ACTIVE; +#define ATTR_MASK attr_mask + +void enable_ptattr_no_execute(void) +{ + attr_mask |= PTATTR_NO_EXECUTE; + return; +} + #if 0 static unsigned long attr_to_l4attr(enum ihk_mc_pt_attribute attr) {