From 063fa963c3ee5966ec6453db75dc2dc846692ba6 Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Tue, 3 Mar 2015 17:14:38 +0900 Subject: [PATCH] change copy-in routines - restrict copy_from_user() to only current process. - add read_process_vm() to read specified process space. --- arch/x86/kernel/memory.c | 58 +++++++++++++++++++++++++++++++++++++-- arch/x86/kernel/syscall.c | 8 +++--- kernel/syscall.c | 34 ++++++++++------------- 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/arch/x86/kernel/memory.c b/arch/x86/kernel/memory.c index 2d98355c..636ca5f5 100644 --- a/arch/x86/kernel/memory.c +++ b/arch/x86/kernel/memory.c @@ -20,6 +20,7 @@ #include #include #include +#include #define dkprintf(...) do { if (0) kprintf(__VA_ARGS__); } while (0) #define ekprintf(...) kprintf(__VA_ARGS__) @@ -2117,9 +2118,9 @@ void *phys_to_virt(unsigned long p) return (void *)(p + MAP_ST_START); } -int copy_from_user(struct process *proc, void *dst, const void *src, size_t siz) +int copy_from_user(void *dst, const void *src, size_t siz) { - struct process_vm *vm = proc->vm; + struct process_vm *vm = cpu_local_var(current)->vm; struct vm_range *range; size_t pos; size_t wsiz; @@ -2146,6 +2147,59 @@ int copy_from_user(struct process *proc, void *dst, const void *src, size_t siz) return 0; } +int read_process_vm(struct process_vm *vm, void *kdst, const void *usrc, size_t siz) +{ + const uintptr_t ustart = (uintptr_t)usrc; + 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; + + if ((ustart < vm->region.user_start) + || (vm->region.user_end <= ustart) + || ((vm->region.user_end - ustart) < siz)) { + return -EFAULT; + } + + reason = PF_USER; /* page not present */ + for (addr = ustart & PAGE_MASK; addr < uend; addr += PAGE_SIZE) { + error = page_fault_process_vm(vm, (void *)addr, reason); + if (error) { + return error; + } + } + + from = usrc; + to = kdst; + remain = siz; + while (remain > 0) { + cpsize = PAGE_SIZE - ((uintptr_t)from & (PAGE_SIZE - 1)); + if (cpsize > remain) { + cpsize = remain; + } + + error = ihk_mc_pt_virt_to_phys(vm->page_table, from, &pa); + if (error) { + return error; + } + + va = phys_to_virt(pa); + memcpy(to, va, cpsize); + + from += cpsize; + to += cpsize; + remain -= cpsize; + } + + return 0; +} /* read_process_vm() */ + int copy_to_user(struct process *proc, void *dst, const void *src, size_t siz) { struct process_vm *vm = proc->vm; diff --git a/arch/x86/kernel/syscall.c b/arch/x86/kernel/syscall.c index d4662f7e..f232cc7c 100644 --- a/arch/x86/kernel/syscall.c +++ b/arch/x86/kernel/syscall.c @@ -25,7 +25,7 @@ #include void terminate(int, int, ihk_mc_user_context_t *); -int copy_from_user(struct process *proc, void *dst, const void *src, size_t siz); +int copy_from_user(void *dst, const void *src, size_t siz); int copy_to_user(struct process *proc, void *dst, const void *src, size_t siz); long do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact); @@ -117,7 +117,7 @@ SYSCALL_DECLARE(rt_sigaction) return -EINVAL; if(act) - if(copy_from_user(proc, &new_sa.sa, act, sizeof new_sa.sa)){ + if(copy_from_user(&new_sa.sa, act, sizeof new_sa.sa)){ goto fault; } rc = do_sigaction(sig, act? &new_sa: NULL, oact? &old_sa: NULL); @@ -152,9 +152,9 @@ SYSCALL_DECLARE(rt_sigreturn) sigsp = (struct sigsp *)regs->gpr.rsp; proc->sigmask.__val[0] = sigsp->sigmask; proc->sigstack.ss_flags = sigsp->ssflags; - if(copy_from_user(proc, regs, &sigsp->regs, sizeof(struct x86_user_context))) + if(copy_from_user(regs, &sigsp->regs, sizeof(struct x86_user_context))) return rc; - copy_from_user(proc, &rc, &sigsp->sigrc, sizeof(long)); + copy_from_user(&rc, &sigsp->sigrc, sizeof(long)); return rc; } diff --git a/kernel/syscall.c b/kernel/syscall.c index 6d838c02..e6f8e82f 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -98,7 +98,8 @@ void check_signal(unsigned long rc, void *regs); void do_signal(long rc, void *regs, struct process *proc, struct sig_pending *pending); extern unsigned long do_kill(int pid, int tid, int sig, struct siginfo *info, int ptracecont); extern struct sigpending *hassigpending(struct process *proc); -int copy_from_user(struct process *, void *, const void *, size_t); +int copy_from_user(void *, const void *, size_t); +int read_process_vm(struct process_vm *, void *, const void *, size_t); int copy_to_user(struct process *, void *, const void *, size_t); void do_setpgid(int, int); extern long alloc_debugreg(struct process *proc); @@ -2096,7 +2097,7 @@ SYSCALL_DECLARE(rt_sigprocmask) goto fault; } if(set){ - if(copy_from_user(proc, &wsig, set->__val, sizeof wsig)) + if(copy_from_user(&wsig, set->__val, sizeof wsig)) goto fault; switch(how){ case SIG_BLOCK: @@ -2184,10 +2185,10 @@ SYSCALL_DECLARE(rt_sigtimedwait) if(set == NULL) return -EFAULT; memset(&winfo, '\0', sizeof winfo); - if(copy_from_user(proc, &wset, set, sizeof wset)) + if(copy_from_user(&wset, set, sizeof wset)) return -EFAULT; if(timeout) - if(copy_from_user(proc, wtimeout, timeout, sizeof wtimeout)) + if(copy_from_user(wtimeout, timeout, sizeof wtimeout)) return -EFAULT; @@ -2203,13 +2204,12 @@ SYSCALL_DECLARE(rt_sigqueueinfo) int pid = (int)ihk_mc_syscall_arg0(ctx); int sig = (int)ihk_mc_syscall_arg1(ctx); void *winfo = (void *)ihk_mc_syscall_arg2(ctx); - struct process *proc = cpu_local_var(current); struct siginfo info; if(pid <= 0) return -ESRCH; - if(copy_from_user(proc, &info, winfo, sizeof info)) + if(copy_from_user(&info, winfo, sizeof info)) return -EFAULT; return do_kill(pid, -1, sig, &info, 0); @@ -2285,7 +2285,7 @@ SYSCALL_DECLARE(rt_sigsuspend) if (sigsetsize > sizeof(sigset_t)) return -EINVAL; - if(copy_from_user(proc, &wset, set, sizeof wset)) + if(copy_from_user(&wset, set, sizeof wset)) return -EFAULT; return do_sigsuspend(proc, &wset); @@ -2302,7 +2302,7 @@ SYSCALL_DECLARE(sigaltstack) if(copy_to_user(proc, oss, &proc->sigstack, sizeof wss)) return -EFAULT; if(ss){ - if(copy_from_user(proc, &wss, ss, sizeof wss)) + if(copy_from_user(&wss, ss, sizeof wss)) return -EFAULT; if(wss.ss_flags != 0 && wss.ss_flags != SS_DISABLE) return -EINVAL; @@ -2636,7 +2636,7 @@ SYSCALL_DECLARE(setrlimit) if(i >= sizeof(rlimits) / sizeof(int)) return -EINVAL; - if(copy_from_user(proc, proc->rlimit + mcresource, rlm, sizeof(struct rlimit))) + if(copy_from_user(proc->rlimit + mcresource, rlm, sizeof(struct rlimit))) return -EFAULT; return 0; @@ -2828,7 +2828,6 @@ static long ptrace_setregs(int pid, long data) struct user_regs_struct *regs = (struct user_regs_struct *)data; long rc = -EIO; struct process *child; - struct process *proc = cpu_local_var(current); ihk_spinlock_t *savelock; unsigned long irqstate; @@ -2837,7 +2836,7 @@ static long ptrace_setregs(int pid, long data) return -ESRCH; if(child->ftn->status == PS_TRACED){ struct user_regs_struct user_regs; - rc = copy_from_user(proc, &user_regs, regs, sizeof(struct user_regs_struct)); + rc = copy_from_user(&user_regs, regs, sizeof(struct user_regs_struct)); if (rc == 0) { long addr; unsigned long *p; @@ -2926,9 +2925,7 @@ static long ptrace_peektext(int pid, long addr, long data) return -ESRCH; if(child->ftn->status == PS_TRACED){ unsigned long value; - ihk_mc_load_page_table(child->vm->page_table); - rc = copy_from_user(child, &value, (void *)addr, sizeof(value)); - ihk_mc_load_page_table(proc->vm->page_table); + rc = read_process_vm(child->vm, &value, (void *)addr, sizeof(value)); if (rc != 0) { dkprintf("ptrace_peektext: bad area addr=0x%llx\n", addr); } else { @@ -3283,7 +3280,6 @@ ptrace_setsiginfo(int pid, siginfo_t *data) ihk_spinlock_t *savelock; unsigned long irqstate; struct process *child; - struct process *proc = cpu_local_var(current); int rc = 0; kprintf("ptrace_setsiginfo: sig=%d errno=%d code=%d\n", data->si_signo, data->si_errno, data->si_code); @@ -3304,7 +3300,7 @@ kprintf("ptrace_setsiginfo: sig=%d errno=%d code=%d\n", data->si_signo, data->si } if (!rc && - copy_from_user(proc, &child->ptrace_sendsig->info, data, sizeof(siginfo_t))) { + copy_from_user(&child->ptrace_sendsig->info, data, sizeof(siginfo_t))) { rc = -EFAULT; } } @@ -3491,7 +3487,7 @@ SYSCALL_DECLARE(sched_setparam) } } - retval = copy_from_user(proc, ¶m, uparam, sizeof(param)); + retval = copy_from_user(¶m, uparam, sizeof(param)); if (retval < 0) { return -EFAULT; } @@ -3564,7 +3560,7 @@ SYSCALL_DECLARE(sched_setscheduler) } } - retval = copy_from_user(proc, ¶m, uparam, sizeof(param)); + retval = copy_from_user(¶m, uparam, sizeof(param)); if (retval < 0) { return -EFAULT; } @@ -3711,7 +3707,7 @@ SYSCALL_DECLARE(sched_setaffinity) } len = MIN2(len, sizeof(k_cpu_set)); - if (copy_from_user(cpu_local_var(current), &k_cpu_set, u_cpu_set, len)) { + if (copy_from_user(&k_cpu_set, u_cpu_set, len)) { kprintf("%s:%d copy_from_user failed.\n", __FILE__, __LINE__); return -EFAULT; }