From 8411f353fe7138b2eb65fd4c632b61e34f7aa396 Mon Sep 17 00:00:00 2001 From: Tomoki Shirasawa Date: Mon, 13 Jan 2014 10:52:29 +0900 Subject: [PATCH] signal part 3 (EFAULT) --- arch/x86/kernel/include/signal.h | 4 +- arch/x86/kernel/memory.c | 60 +++++++++++++++++++++++++ kernel/include/process.h | 2 + kernel/syscall.c | 76 +++++++++++++++++++++++++------- 4 files changed, 123 insertions(+), 19 deletions(-) diff --git a/arch/x86/kernel/include/signal.h b/arch/x86/kernel/include/signal.h index f0755e09..8636c1d4 100644 --- a/arch/x86/kernel/include/signal.h +++ b/arch/x86/kernel/include/signal.h @@ -18,10 +18,8 @@ typedef unsigned long int __sigset_t; #define __sigmask(sig) (((__sigset_t) 1) << ((sig) - 1)) -# define _SIGSET_NWORDS (1024 / (8 * sizeof (__sigset_t))) - typedef struct { - __sigset_t __val[_SIGSET_NWORDS]; + __sigset_t __val[_NSIG_WORDS]; } sigset_t; #define SIG_BLOCK 0 diff --git a/arch/x86/kernel/memory.c b/arch/x86/kernel/memory.c index d0fd2f9d..fb695f13 100644 --- a/arch/x86/kernel/memory.c +++ b/arch/x86/kernel/memory.c @@ -1749,7 +1749,67 @@ unsigned long virt_to_phys(void *v) return va - MAP_ST_START; } } + 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) +{ + struct process_vm *vm = proc->vm; + struct vm_range *range; + size_t pos; + size_t wsiz; + unsigned long pgstart = (unsigned long)src; + + wsiz = siz + (pgstart & 0x0000000000000fffUL); + pgstart &= 0xfffffffffffff000UL; + if(!pgstart || pgstart >= MAP_KERNEL_START) + return -EFAULT; + ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock); + for(pos = 0; pos < wsiz; pos += 4096, pgstart += 4096){ + range = lookup_process_memory_range(vm, pgstart, pgstart+1); + if(range == NULL){ + ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock); + return -EFAULT; + } + if((range->flag & VR_PROT_MASK) == VR_PROT_NONE){ + ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock); + return -EFAULT; + } + } + ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock); + memcpy(dst, src, siz); + return 0; +} + +int copy_to_user(struct process *proc, void *dst, const void *src, size_t siz) +{ + struct process_vm *vm = proc->vm; + struct vm_range *range; + size_t pos; + size_t wsiz; + unsigned long pgstart = (unsigned long)dst; + + wsiz = siz + (pgstart & 0x0000000000000fffUL); + pgstart &= 0xfffffffffffff000UL; + if(!pgstart || pgstart >= MAP_KERNEL_START) + return -EFAULT; + ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock); + for(pos = 0; pos < wsiz; pos += 4096, pgstart += 4096){ + range = lookup_process_memory_range(vm, pgstart, pgstart+1); + if(range == NULL){ + ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock); + return -EFAULT; + } + if(((range->flag & VR_PROT_MASK) == VR_PROT_NONE) || + !(range->flag & VR_PROT_WRITE)){ + ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock); + return -EFAULT; + } + } + ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock); + memcpy(dst, src, siz); + return 0; +} diff --git a/kernel/include/process.h b/kernel/include/process.h index 4c0d8fa1..1db107eb 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -121,7 +121,9 @@ struct process { } thread; int tid; + volatile int sigevent; sigset_t sigmask; + sigset_t supmask; ihk_spinlock_t sigpendinglock; struct list_head sigpending; struct sig_shared *sigshared; diff --git a/kernel/syscall.c b/kernel/syscall.c index 4a57b6a8..311237e7 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -93,6 +93,8 @@ static char *syscall_name[] MCKERNEL_UNUSED = { }; void check_signal(long rc, unsigned long *regs); +int copy_from_user(struct process *, void *, const void *, size_t); +int copy_to_user(struct process *, void *, const void *, size_t); #ifdef DCFA_KMOD static void do_mod_exit(int status); @@ -1041,32 +1043,38 @@ do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) k = proc->sighandler->action + sig - 1; if(oact) memcpy(oact, k, sizeof(struct k_sigaction)); - if(act){ + if(act) memcpy(k, act, sizeof(struct k_sigaction)); - } ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate); return 0; } SYSCALL_DECLARE(rt_sigaction) { + struct process *proc = cpu_local_var(current); int sig = ihk_mc_syscall_arg0(ctx); const struct sigaction *act = (const struct sigaction *)ihk_mc_syscall_arg1(ctx); struct sigaction *oact = (struct sigaction *)ihk_mc_syscall_arg2(ctx); - //size_t sigsetsize = ihk_mc_syscall_arg3(ctx); + size_t sigsetsize = ihk_mc_syscall_arg3(ctx); struct k_sigaction new_sa, old_sa; int rc; - //if (sigsetsize != sizeof(sigset_t)) - //return -EINVAL; + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; if(act) - memcpy(&new_sa.sa, act, sizeof new_sa.sa); + if(copy_from_user(proc, &new_sa.sa, act, sizeof new_sa.sa)){ + goto fault; + } rc = do_sigaction(sig, act? &new_sa: NULL, oact? &old_sa: NULL); - if(oact) - memcpy(oact, &old_sa.sa, sizeof old_sa.sa); + if(rc == 0 && oact) + if(copy_to_user(proc, oact, &old_sa.sa, sizeof old_sa.sa)){ + goto fault; + } return rc; +fault: + return -EFAULT; } SYSCALL_DECLARE(rt_sigprocmask) @@ -1074,8 +1082,13 @@ SYSCALL_DECLARE(rt_sigprocmask) int how = ihk_mc_syscall_arg0(ctx); const sigset_t *set = (const sigset_t *)ihk_mc_syscall_arg1(ctx); sigset_t *oldset = (sigset_t *)ihk_mc_syscall_arg2(ctx); + size_t sigsetsize = (size_t)ihk_mc_syscall_arg3(ctx); struct process *proc = cpu_local_var(current); int flag; + __sigset_t wsig; + + if(sigsetsize != sizeof(sigset_t)) + return -EINVAL; if(set && how != SIG_BLOCK && @@ -1084,23 +1097,32 @@ SYSCALL_DECLARE(rt_sigprocmask) return -EINVAL; flag = ihk_mc_spinlock_lock(&proc->sighandler->lock); - if(oldset) - oldset->__val[0] = proc->sigmask.__val[0]; + if(oldset){ + wsig = proc->sigmask.__val[0]; + if(copy_to_user(proc, oldset->__val, &wsig, sizeof wsig)) + goto fault; + } if(set){ + if(copy_from_user(proc, &wsig, set->__val, sizeof wsig)) + goto fault; switch(how){ case SIG_BLOCK: - proc->sigmask.__val[0] |= set->__val[0]; + proc->sigmask.__val[0] |= wsig; break; case SIG_UNBLOCK: - proc->sigmask.__val[0] &= ~set->__val[0]; + proc->sigmask.__val[0] &= ~wsig; break; case SIG_SETMASK: - proc->sigmask.__val[0] = set->__val[0]; + proc->sigmask.__val[0] = wsig; break; } } + proc->supmask = proc->sigmask; ihk_mc_spinlock_unlock(&proc->sighandler->lock, flag); return 0; +fault: + ihk_mc_spinlock_unlock(&proc->sighandler->lock, flag); + return -EFAULT; } SYSCALL_DECLARE(rt_sigpending) @@ -1112,6 +1134,10 @@ SYSCALL_DECLARE(rt_sigpending) __sigset_t w = 0; struct process *proc = cpu_local_var(current); sigset_t *set = (sigset_t *)ihk_mc_syscall_arg0(ctx); + size_t sigsetsize = (size_t)ihk_mc_syscall_arg1(ctx); + + if (sigsetsize > sizeof(sigset_t)) + return -EINVAL; lock = &proc->sigshared->lock; head = &proc->sigshared->sigpending; @@ -1129,23 +1155,39 @@ SYSCALL_DECLARE(rt_sigpending) } ihk_mc_spinlock_unlock(lock, flag); - set->__val[0] = w; + if(copy_to_user(proc, set->__val, &w, sizeof w)) + return -EFAULT; return 0; } SYSCALL_DECLARE(rt_sigtimedwait) { +/* +sigset_t * +siginfo_t * +struct timespec * +size_t +*/ return 0; } SYSCALL_DECLARE(rt_sigqueueinfo) { +/* +pid_t +int +siginfo_t * +*/ return 0; } SYSCALL_DECLARE(rt_sigsuspend) { +/* +sigset_t * +size_t +*/ return 0; } @@ -1276,8 +1318,10 @@ SYSCALL_DECLARE(getrlimit) case RLIMIT_STACK: dkprintf("[%d] getrlimit() RLIMIT_STACK\n", ihk_mc_get_processor_id()); - rlm->rlim_cur = proc->rlimit_stack.rlim_cur; - rlm->rlim_max = proc->rlimit_stack.rlim_max; + if(copy_to_user(proc, &rlm->rlim_cur, &proc->rlimit_stack.rlim_cur, sizeof rlm->rlim_cur)) + return -EFAULT; + if(copy_to_user(proc, &rlm->rlim_max, &proc->rlimit_stack.rlim_max, sizeof rlm->rlim_max)) + return -EFAULT; ret = 0; break;