From 2eac58aab3b67ed3d908892e95d0cfb0a2a205c4 Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Tue, 3 Mar 2015 19:25:05 +0900 Subject: [PATCH] add patch_process_vm(). (in progress) This function patches specified range of specified user space even if the range is not writable. refs #401 --- arch/x86/kernel/include/registers.h | 1 + arch/x86/kernel/memory.c | 61 ++++++++++++++++++++++++++++- kernel/process.c | 9 +++-- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/include/registers.h b/arch/x86/kernel/include/registers.h index 4a226ba7..507e1097 100644 --- a/arch/x86/kernel/include/registers.h +++ b/arch/x86/kernel/include/registers.h @@ -219,6 +219,7 @@ enum x86_pf_error_code { PF_RSVD = 1 << 3, PF_INSTR = 1 << 4, + PF_PATCH = 1 << 29, PF_POPULATE = 1 << 30, }; diff --git a/arch/x86/kernel/memory.c b/arch/x86/kernel/memory.c index 8fa5dedf..dcee9f25 100644 --- a/arch/x86/kernel/memory.c +++ b/arch/x86/kernel/memory.c @@ -1870,7 +1870,8 @@ enum ihk_mc_pt_attribute arch_vrflag_to_ptattr(unsigned long flag, uint64_t faul attr = common_vrflag_to_ptattr(flag, fault, ptep); if ((fault & PF_PROT) - || ((fault & PF_POPULATE) && (flag & VR_PRIVATE))) { + || ((fault & (PF_POPULATE | PF_PATCH)) + && (flag & VR_PRIVATE))) { attr |= PTATTR_DIRTY; } @@ -2282,3 +2283,61 @@ int write_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t return 0; } /* write_process_vm() */ + +int patch_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t siz) +{ + const uintptr_t ustart = (uintptr_t)udst; + const uintptr_t uend = ustart + siz; + uint64_t reason; + uintptr_t addr; + int error; + const void *from; + void *to; + size_t remain; + size_t cpsize; + unsigned long pa; + void *va; + + kprintf("patch_process_vm(%p,%p,%p,%lx)\n", vm, udst, ksrc, siz); + if ((ustart < vm->region.user_start) + || (vm->region.user_end <= ustart) + || ((vm->region.user_end - ustart) < siz)) { + kprintf("patch_process_vm(%p,%p,%p,%lx):not in user\n", vm, udst, ksrc, siz); + return -EFAULT; + } + + reason = PF_PATCH | PF_WRITE | PF_USER; + for (addr = ustart & PAGE_MASK; addr < uend; addr += PAGE_SIZE) { + error = page_fault_process_vm(vm, (void *)addr, reason); + if (error) { + kprintf("patch_process_vm(%p,%p,%p,%lx):pf(%lx):%d\n", vm, udst, ksrc, siz, addr, error); + return error; + } + } + + from = ksrc; + to = udst; + remain = siz; + while (remain > 0) { + cpsize = PAGE_SIZE - ((uintptr_t)to & (PAGE_SIZE - 1)); + if (cpsize > remain) { + cpsize = remain; + } + + error = ihk_mc_pt_virt_to_phys(vm->page_table, to, &pa); + if (error) { + kprintf("patch_process_vm(%p,%p,%p,%lx):v2p(%p):%d\n", vm, udst, ksrc, siz, to, error); + return error; + } + + va = phys_to_virt(pa); + memcpy(va, from, cpsize); + + from += cpsize; + to += cpsize; + remain -= cpsize; + } + + kprintf("patch_process_vm(%p,%p,%p,%lx):%d\n", vm, udst, ksrc, siz, 0); + return 0; +} /* patch_process_vm() */ diff --git a/kernel/process.c b/kernel/process.c index a7f309d0..53808c71 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -1378,7 +1378,7 @@ static int page_fault_process_memory_range(struct process_vm *vm, struct vm_rang ihk_mc_spinlock_lock_noirq(&vm->page_table_lock); /*****/ ptep = ihk_mc_pt_lookup_pte(vm->page_table, (void *)fault_addr, &pgaddr, &pgsize, &p2align); - if (!(reason & PF_PROT) && ptep && !pte_is_null(ptep) + if (!(reason & (PF_PROT | PF_PATCH)) && ptep && !pte_is_null(ptep) && !pte_is_fileoff(ptep, pgsize)) { if (!pte_is_present(ptep)) { error = -EFAULT; @@ -1439,7 +1439,10 @@ static int page_fault_process_memory_range(struct process_vm *vm, struct vm_rang } page = phys_to_page(phys); /*****/ - if ((range->flag & VR_PRIVATE) && (!page || page_is_in_memobj(page) || page_is_multi_mapped(page))) { + if (((range->flag & VR_PRIVATE) + || ((reason & PF_PATCH) + && !(range->flag & VR_PROT_WRITE))) + && (!page || page_is_in_memobj(page) || page_is_multi_mapped(page))) { if (!(attr & PTATTR_DIRTY)) { attr &= ~PTATTR_WRITABLE; } @@ -1513,7 +1516,7 @@ static int do_page_fault_process_vm(struct process_vm *vm, void *fault_addr0, ui } if (((range->flag & VR_PROT_MASK) == VR_PROT_NONE) - || ((reason & PF_WRITE) + || (((reason & PF_WRITE) && !(reason & PF_PATCH)) && !(range->flag & VR_PROT_WRITE)) || ((reason & PF_INSTR) && !(range->flag & VR_PROT_EXEC))) {