change copy-out routines

- restrict copy_to_user() to only current process.
- add write_process_vm() to write specified process space.
This commit is contained in:
NAKAMURA Gou
2015-03-03 18:12:55 +09:00
parent 8db54c2637
commit 22d8d169b6
3 changed files with 81 additions and 37 deletions

View File

@@ -2200,9 +2200,9 @@ int read_process_vm(struct process_vm *vm, void *kdst, const void *usrc, size_t
return 0; return 0;
} /* read_process_vm() */ } /* read_process_vm() */
int copy_to_user(struct process *proc, void *dst, const void *src, size_t siz) int copy_to_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; struct vm_range *range;
size_t pos; size_t pos;
size_t wsiz; size_t wsiz;
@@ -2229,3 +2229,56 @@ int copy_to_user(struct process *proc, void *dst, const void *src, size_t siz)
memcpy(dst, src, siz); memcpy(dst, src, siz);
return 0; return 0;
} }
int write_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;
if ((ustart < vm->region.user_start)
|| (vm->region.user_end <= ustart)
|| ((vm->region.user_end - ustart) < siz)) {
return -EFAULT;
}
reason = PF_POPULATE | 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) {
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) {
return error;
}
va = phys_to_virt(pa);
memcpy(va, from, cpsize);
from += cpsize;
to += cpsize;
remain -= cpsize;
}
return 0;
} /* write_process_vm() */

View File

@@ -26,7 +26,8 @@
void terminate(int, int, ihk_mc_user_context_t *); void terminate(int, int, ihk_mc_user_context_t *);
int copy_from_user(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); int copy_to_user(void *dst, const void *src, size_t siz);
int write_process_vm(struct process_vm *vm, void *dst, const void *src, size_t siz);
long do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact); long do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact);
//#define DEBUG_PRINT_SC //#define DEBUG_PRINT_SC
@@ -103,7 +104,6 @@ int obtain_clone_cpuid() {
SYSCALL_DECLARE(rt_sigaction) SYSCALL_DECLARE(rt_sigaction)
{ {
struct process *proc = cpu_local_var(current);
int sig = ihk_mc_syscall_arg0(ctx); int sig = ihk_mc_syscall_arg0(ctx);
const struct sigaction *act = (const struct sigaction *)ihk_mc_syscall_arg1(ctx); const struct sigaction *act = (const struct sigaction *)ihk_mc_syscall_arg1(ctx);
struct sigaction *oact = (struct sigaction *)ihk_mc_syscall_arg2(ctx); struct sigaction *oact = (struct sigaction *)ihk_mc_syscall_arg2(ctx);
@@ -122,7 +122,7 @@ SYSCALL_DECLARE(rt_sigaction)
} }
rc = do_sigaction(sig, act? &new_sa: NULL, oact? &old_sa: NULL); rc = do_sigaction(sig, act? &new_sa: NULL, oact? &old_sa: NULL);
if(rc == 0 && oact) if(rc == 0 && oact)
if(copy_to_user(proc, oact, &old_sa.sa, sizeof old_sa.sa)){ if(copy_to_user(oact, &old_sa.sa, sizeof old_sa.sa)){
goto fault; goto fault;
} }
@@ -474,11 +474,11 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
} }
sigsp = ((struct sigsp *)usp) - 1; sigsp = ((struct sigsp *)usp) - 1;
sigsp = (struct sigsp *)((unsigned long)sigsp & 0xfffffffffffffff0UL); sigsp = (struct sigsp *)((unsigned long)sigsp & 0xfffffffffffffff0UL);
if(copy_to_user(proc, &sigsp->regs, regs, sizeof(struct x86_user_context)) || if(write_process_vm(proc->vm, &sigsp->regs, regs, sizeof(struct x86_user_context)) ||
copy_to_user(proc, &sigsp->sigrc, &rc, sizeof(long))){ write_process_vm(proc->vm, &sigsp->sigrc, &rc, sizeof(long))){
kfree(pending); kfree(pending);
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate); ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
kprintf("do_signal,copy_to_user failed\n"); kprintf("do_signal,write_process_vm failed\n");
terminate(0, sig, (ihk_mc_user_context_t *)regs->gpr.rsp); terminate(0, sig, (ihk_mc_user_context_t *)regs->gpr.rsp);
return; return;
} }

View File

@@ -100,7 +100,7 @@ extern unsigned long do_kill(int pid, int tid, int sig, struct siginfo *info, in
extern struct sigpending *hassigpending(struct process *proc); extern struct sigpending *hassigpending(struct process *proc);
int copy_from_user(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 read_process_vm(struct process_vm *, void *, const void *, size_t);
int copy_to_user(struct process *, void *, const void *, size_t); int copy_to_user(void *, const void *, size_t);
void do_setpgid(int, int); void do_setpgid(int, int);
extern long alloc_debugreg(struct process *proc); extern long alloc_debugreg(struct process *proc);
@@ -567,7 +567,7 @@ SYSCALL_DECLARE(wait4)
} }
rc = do_wait(pid, &st, WEXITED | options, rusage); rc = do_wait(pid, &st, WEXITED | options, rusage);
if(rc >= 0 && status) if(rc >= 0 && status)
copy_to_user(cpu_local_var(current), status, &st, sizeof(int)); copy_to_user(status, &st, sizeof(int));
return rc; return rc;
} }
@@ -614,7 +614,7 @@ SYSCALL_DECLARE(waitid)
info.si_code = CLD_KILLED; info.si_code = CLD_KILLED;
else else
info.si_code = CLD_EXITED; info.si_code = CLD_EXITED;
copy_to_user(cpu_local_var(current), infop, &info, sizeof info); copy_to_user(infop, &info, sizeof info);
} }
return 0; return 0;
} }
@@ -2093,7 +2093,7 @@ SYSCALL_DECLARE(rt_sigprocmask)
flag = ihk_mc_spinlock_lock(&proc->sighandler->lock); flag = ihk_mc_spinlock_lock(&proc->sighandler->lock);
if(oldset){ if(oldset){
wsig = proc->sigmask.__val[0]; wsig = proc->sigmask.__val[0];
if(copy_to_user(proc, oldset->__val, &wsig, sizeof wsig)) if(copy_to_user(oldset->__val, &wsig, sizeof wsig))
goto fault; goto fault;
} }
if(set){ if(set){
@@ -2152,7 +2152,7 @@ SYSCALL_DECLARE(rt_sigpending)
} }
ihk_mc_spinlock_unlock(lock, flag); ihk_mc_spinlock_unlock(lock, flag);
if(copy_to_user(proc, set->__val, &w, sizeof w)) if(copy_to_user(set->__val, &w, sizeof w))
return -EFAULT; return -EFAULT;
return 0; return 0;
@@ -2170,7 +2170,6 @@ SYSCALL_DECLARE(signalfd4)
SYSCALL_DECLARE(rt_sigtimedwait) SYSCALL_DECLARE(rt_sigtimedwait)
{ {
struct process *proc = cpu_local_var(current);
const sigset_t *set = (const sigset_t *)ihk_mc_syscall_arg0(ctx); const sigset_t *set = (const sigset_t *)ihk_mc_syscall_arg0(ctx);
siginfo_t *info = (siginfo_t *)ihk_mc_syscall_arg1(ctx); siginfo_t *info = (siginfo_t *)ihk_mc_syscall_arg1(ctx);
void *timeout = (void *)ihk_mc_syscall_arg2(ctx); void *timeout = (void *)ihk_mc_syscall_arg2(ctx);
@@ -2193,7 +2192,7 @@ SYSCALL_DECLARE(rt_sigtimedwait)
if(info) if(info)
if(copy_to_user(proc, info, &winfo, sizeof winfo)) if(copy_to_user(info, &winfo, sizeof winfo))
return -EFAULT; return -EFAULT;
return -EOPNOTSUPP; return -EOPNOTSUPP;
@@ -2299,7 +2298,7 @@ SYSCALL_DECLARE(sigaltstack)
stack_t wss; stack_t wss;
if(oss) if(oss)
if(copy_to_user(proc, oss, &proc->sigstack, sizeof wss)) if(copy_to_user(oss, &proc->sigstack, sizeof wss))
return -EFAULT; return -EFAULT;
if(ss){ if(ss){
if(copy_from_user(&wss, ss, sizeof wss)) if(copy_from_user(&wss, ss, sizeof wss))
@@ -2659,7 +2658,7 @@ SYSCALL_DECLARE(getrlimit)
return -EINVAL; return -EINVAL;
// TODO: check limit // TODO: check limit
if(copy_to_user(proc, rlm, proc->rlimit + mcresource, sizeof(struct rlimit))) if(copy_to_user(rlm, proc->rlimit + mcresource, sizeof(struct rlimit)))
return -EFAULT; return -EFAULT;
return 0; return 0;
@@ -2769,7 +2768,6 @@ static long ptrace_peekuser(int pid, long addr, long data)
{ {
long rc = -EIO; long rc = -EIO;
struct process *child; struct process *child;
struct process *proc = cpu_local_var(current);
ihk_spinlock_t *savelock; ihk_spinlock_t *savelock;
unsigned long irqstate; unsigned long irqstate;
unsigned long *p = (unsigned long *)data; unsigned long *p = (unsigned long *)data;
@@ -2783,7 +2781,7 @@ static long ptrace_peekuser(int pid, long addr, long data)
unsigned long value; unsigned long value;
rc = ptrace_read_user(child, addr, &value); rc = ptrace_read_user(child, addr, &value);
if (rc == 0) { if (rc == 0) {
rc = copy_to_user(proc, p, (char *)&value, sizeof(value)); rc = copy_to_user(p, (char *)&value, sizeof(value));
} }
} }
ihk_mc_spinlock_unlock(savelock, irqstate); ihk_mc_spinlock_unlock(savelock, irqstate);
@@ -2796,7 +2794,6 @@ static long ptrace_getregs(int pid, long data)
struct user_regs_struct *regs = (struct user_regs_struct *)data; struct user_regs_struct *regs = (struct user_regs_struct *)data;
long rc = -EIO; long rc = -EIO;
struct process *child; struct process *child;
struct process *proc = cpu_local_var(current);
ihk_spinlock_t *savelock; ihk_spinlock_t *savelock;
unsigned long irqstate; unsigned long irqstate;
@@ -2815,7 +2812,7 @@ static long ptrace_getregs(int pid, long data)
if (rc) break; if (rc) break;
} }
if (rc == 0) { if (rc == 0) {
rc = copy_to_user(proc, regs, &user_regs, sizeof(struct user_regs_struct)); rc = copy_to_user(regs, &user_regs, sizeof(struct user_regs_struct));
} }
} }
ihk_mc_spinlock_unlock(savelock, irqstate); ihk_mc_spinlock_unlock(savelock, irqstate);
@@ -2868,26 +2865,24 @@ static long ptrace_arch_prctl(int pid, long code, long addr)
if (child->ftn->status == PS_TRACED) { if (child->ftn->status == PS_TRACED) {
switch (code) { switch (code) {
case ARCH_GET_FS: { case ARCH_GET_FS: {
struct process *proc = cpu_local_var(current);
unsigned long value; unsigned long value;
unsigned long *p = (unsigned long *)addr; unsigned long *p = (unsigned long *)addr;
rc = ptrace_read_user(child, rc = ptrace_read_user(child,
offsetof(struct user_regs_struct, fs_base), offsetof(struct user_regs_struct, fs_base),
&value); &value);
if (rc == 0) { if (rc == 0) {
rc = copy_to_user(proc, p, (char *)&value, sizeof(value)); rc = copy_to_user(p, (char *)&value, sizeof(value));
} }
break; break;
} }
case ARCH_GET_GS: { case ARCH_GET_GS: {
struct process *proc = cpu_local_var(current);
unsigned long value; unsigned long value;
unsigned long *p = (unsigned long *)addr; unsigned long *p = (unsigned long *)addr;
rc = ptrace_read_user(child, rc = ptrace_read_user(child,
offsetof(struct user_regs_struct, gs_base), offsetof(struct user_regs_struct, gs_base),
&value); &value);
if (rc == 0) { if (rc == 0) {
rc = copy_to_user(proc, p, (char *)&value, sizeof(value)); rc = copy_to_user(p, (char *)&value, sizeof(value));
} }
break; break;
} }
@@ -2915,7 +2910,6 @@ static long ptrace_peektext(int pid, long addr, long data)
{ {
long rc = -EIO; long rc = -EIO;
struct process *child; struct process *child;
struct process *proc = cpu_local_var(current);
ihk_spinlock_t *savelock; ihk_spinlock_t *savelock;
unsigned long irqstate; unsigned long irqstate;
unsigned long *p = (unsigned long *)data; unsigned long *p = (unsigned long *)data;
@@ -2929,7 +2923,7 @@ static long ptrace_peektext(int pid, long addr, long data)
if (rc != 0) { if (rc != 0) {
dkprintf("ptrace_peektext: bad area addr=0x%llx\n", addr); dkprintf("ptrace_peektext: bad area addr=0x%llx\n", addr);
} else { } else {
rc = copy_to_user(proc, p, &value, sizeof(value)); rc = copy_to_user(p, &value, sizeof(value));
} }
} }
ihk_mc_spinlock_unlock(savelock, irqstate); ihk_mc_spinlock_unlock(savelock, irqstate);
@@ -3225,7 +3219,6 @@ static long ptrace_geteventmsg(int pid, long data)
unsigned long *msg_p = (unsigned long *)data; unsigned long *msg_p = (unsigned long *)data;
long rc = -ESRCH; long rc = -ESRCH;
struct process *child; struct process *child;
struct process *proc = cpu_local_var(current);
ihk_spinlock_t *savelock; ihk_spinlock_t *savelock;
unsigned long irqstate; unsigned long irqstate;
@@ -3234,7 +3227,7 @@ static long ptrace_geteventmsg(int pid, long data)
return -ESRCH; return -ESRCH;
} }
if (child->ftn->status == PS_TRACED) { if (child->ftn->status == PS_TRACED) {
if (copy_to_user(proc, msg_p, &child->ftn->ptrace_eventmsg, sizeof(*msg_p))) { if (copy_to_user(msg_p, &child->ftn->ptrace_eventmsg, sizeof(*msg_p))) {
rc = -EFAULT; rc = -EFAULT;
} else { } else {
rc = 0; rc = 0;
@@ -3251,7 +3244,6 @@ ptrace_getsiginfo(int pid, siginfo_t *data)
ihk_spinlock_t *savelock; ihk_spinlock_t *savelock;
unsigned long irqstate; unsigned long irqstate;
struct process *child; struct process *child;
struct process *proc = cpu_local_var(current);
int rc = 0; int rc = 0;
child = findthread_and_lock(pid, -1, &savelock, &irqstate); child = findthread_and_lock(pid, -1, &savelock, &irqstate);
@@ -3263,7 +3255,7 @@ ptrace_getsiginfo(int pid, siginfo_t *data)
rc = -ESRCH; rc = -ESRCH;
} }
else if (child->ptrace_recvsig) { else if (child->ptrace_recvsig) {
if (copy_to_user(proc, data, &child->ptrace_recvsig->info, sizeof(siginfo_t))) { if (copy_to_user(data, &child->ptrace_recvsig->info, sizeof(siginfo_t))) {
rc = -EFAULT; rc = -EFAULT;
} }
} }
@@ -3519,7 +3511,7 @@ SYSCALL_DECLARE(sched_getparam)
process_unlock(lock, irqstate); process_unlock(lock, irqstate);
} }
retval = copy_to_user(proc, param, &proc->sched_param, sizeof(*param)) ? -EFAULT : 0; retval = copy_to_user(param, &proc->sched_param, sizeof(*param)) ? -EFAULT : 0;
return retval; return retval;
} }
@@ -3683,7 +3675,7 @@ SYSCALL_DECLARE(sched_rr_get_interval)
t.tv_nsec = 10000; t.tv_nsec = 10000;
} }
retval = copy_to_user(proc, utime, &t, sizeof(t)) ? -EFAULT : 0; retval = copy_to_user(utime, &t, sizeof(t)) ? -EFAULT : 0;
return retval; return retval;
} }
@@ -3784,7 +3776,7 @@ SYSCALL_DECLARE(sched_getaffinity)
kprintf("%s:%d Thread not found.\n", __FILE__, __LINE__); kprintf("%s:%d Thread not found.\n", __FILE__, __LINE__);
return -ESRCH; return -ESRCH;
} }
ret = copy_to_user(cpu_local_var(current), u_cpu_set, &k_cpu_set, len); ret = copy_to_user(u_cpu_set, &k_cpu_set, len);
kprintf("%s %d %d\n", __FILE__, __LINE__, ret); kprintf("%s %d %d\n", __FILE__, __LINE__, ret);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -4548,20 +4540,19 @@ SYSCALL_DECLARE(getcpu)
{ {
const uintptr_t cpup = ihk_mc_syscall_arg0(ctx); const uintptr_t cpup = ihk_mc_syscall_arg0(ctx);
const uintptr_t nodep = ihk_mc_syscall_arg1(ctx); const uintptr_t nodep = ihk_mc_syscall_arg1(ctx);
struct process *proc = cpu_local_var(current);
const int cpu = ihk_mc_get_processor_id(); const int cpu = ihk_mc_get_processor_id();
const int node = 0; const int node = 0;
int error; int error;
if (cpup) { if (cpup) {
error = copy_to_user(proc, (void *)cpup, &cpu, sizeof(cpu)); error = copy_to_user((void *)cpup, &cpu, sizeof(cpu));
if (error) { if (error) {
goto out; goto out;
} }
} }
if (nodep) { if (nodep) {
error = copy_to_user(proc, (void *)nodep, &node, sizeof(node)); error = copy_to_user((void *)nodep, &node, sizeof(node));
if (error) { if (error) {
goto out; goto out;
} }