diff --git a/[refs] b/[refs] index acf59391c84c..d02868741a5f 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 50150d2bb9033de8a4d94b3feb2dfed81a605ed5 +refs/heads/master: b30c7d50af95f7450f877e8172a2341785bce5ab diff --git a/trunk/arch/mips/Kconfig b/trunk/arch/mips/Kconfig index 0772b5c5bc72..2ac626ab9d43 100644 --- a/trunk/arch/mips/Kconfig +++ b/trunk/arch/mips/Kconfig @@ -41,12 +41,6 @@ config MIPS select HAVE_MOD_ARCH_SPECIFIC select MODULES_USE_ELF_REL if MODULES select MODULES_USE_ELF_RELA if MODULES && 64BIT - select CLONE_BACKWARDS - select GENERIC_SIGALTSTACK - select GENERIC_COMPAT_RT_SIGACTION - select GENERIC_COMPAT_RT_SIGQUEUEINFO - select GENERIC_COMPAT_RT_SIGPROCMASK - select GENERIC_COMPAT_RT_SIGPENDING menu "Machine selection" diff --git a/trunk/arch/mips/include/asm/compat.h b/trunk/arch/mips/include/asm/compat.h index ebaae9649f8a..3c5d1464b7bd 100644 --- a/trunk/arch/mips/include/asm/compat.h +++ b/trunk/arch/mips/include/asm/compat.h @@ -288,14 +288,6 @@ struct compat_shmid64_ds { compat_ulong_t __unused2; }; -/* MIPS has unusual order of fields in stack_t */ -typedef struct compat_sigaltstack { - compat_uptr_t ss_sp; - compat_size_t ss_size; - int ss_flags; -} compat_stack_t; -#define compat_sigaltstack compat_sigaltstack - static inline int is_compat_task(void) { return test_thread_flag(TIF_32BIT_ADDR); diff --git a/trunk/arch/mips/include/asm/sim.h b/trunk/arch/mips/include/asm/sim.h index 91831800c480..0cd719fabb51 100644 --- a/trunk/arch/mips/include/asm/sim.h +++ b/trunk/arch/mips/include/asm/sim.h @@ -20,10 +20,10 @@ #define save_static_function(symbol) \ __asm__( \ ".text\n\t" \ - ".globl\t__" #symbol "\n\t" \ + ".globl\t" #symbol "\n\t" \ ".align\t2\n\t" \ - ".type\t__" #symbol ", @function\n\t" \ - ".ent\t__" #symbol ", 0\n__" \ + ".type\t" #symbol ", @function\n\t" \ + ".ent\t" #symbol ", 0\n" \ #symbol":\n\t" \ ".frame\t$29, 0, $31\n\t" \ "sw\t$16,"__str(PT_R16)"($29)\t\t\t# save_static_function\n\t" \ @@ -35,9 +35,9 @@ __asm__( \ "sw\t$22,"__str(PT_R22)"($29)\n\t" \ "sw\t$23,"__str(PT_R23)"($29)\n\t" \ "sw\t$30,"__str(PT_R30)"($29)\n\t" \ - "j\t" #symbol "\n\t" \ - ".end\t__" #symbol "\n\t" \ - ".size\t__" #symbol",. - __" #symbol) + "j\t_" #symbol "\n\t" \ + ".end\t" #symbol "\n\t" \ + ".size\t" #symbol",. - " #symbol) #define nabi_no_regargs @@ -48,10 +48,10 @@ __asm__( \ #define save_static_function(symbol) \ __asm__( \ ".text\n\t" \ - ".globl\t__" #symbol "\n\t" \ + ".globl\t" #symbol "\n\t" \ ".align\t2\n\t" \ - ".type\t__" #symbol ", @function\n\t" \ - ".ent\t__" #symbol ", 0\n__" \ + ".type\t" #symbol ", @function\n\t" \ + ".ent\t" #symbol ", 0\n" \ #symbol":\n\t" \ ".frame\t$29, 0, $31\n\t" \ "sd\t$16,"__str(PT_R16)"($29)\t\t\t# save_static_function\n\t" \ @@ -63,9 +63,9 @@ __asm__( \ "sd\t$22,"__str(PT_R22)"($29)\n\t" \ "sd\t$23,"__str(PT_R23)"($29)\n\t" \ "sd\t$30,"__str(PT_R30)"($29)\n\t" \ - "j\t" #symbol "\n\t" \ - ".end\t__" #symbol "\n\t" \ - ".size\t__" #symbol",. - __" #symbol) + "j\t_" #symbol "\n\t" \ + ".end\t" #symbol "\n\t" \ + ".size\t" #symbol",. - " #symbol) #define nabi_no_regargs \ unsigned long __dummy0, \ diff --git a/trunk/arch/mips/include/asm/unistd.h b/trunk/arch/mips/include/asm/unistd.h index 06f6463c24ad..9e47cc11aa26 100644 --- a/trunk/arch/mips/include/asm/unistd.h +++ b/trunk/arch/mips/include/asm/unistd.h @@ -43,8 +43,6 @@ # ifdef CONFIG_MIPS32_O32 # define __ARCH_WANT_COMPAT_SYS_TIME # endif -#define __ARCH_WANT_SYS_FORK -#define __ARCH_WANT_SYS_CLONE /* whitelists for checksyscalls */ #define __IGNORE_select diff --git a/trunk/arch/mips/kernel/linux32.c b/trunk/arch/mips/kernel/linux32.c index 253bd8ad7446..7adab86c632c 100644 --- a/trunk/arch/mips/kernel/linux32.c +++ b/trunk/arch/mips/kernel/linux32.c @@ -119,6 +119,22 @@ SYSCALL_DEFINE6(32_pwrite, unsigned int, fd, const char __user *, buf, return sys_pwrite64(fd, buf, count, merge_64(a4, a5)); } +SYSCALL_DEFINE2(32_sched_rr_get_interval, compat_pid_t, pid, + struct compat_timespec __user *, interval) +{ + struct timespec t; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t); + set_fs(old_fs); + if (put_user (t.tv_sec, &interval->tv_sec) || + __put_user(t.tv_nsec, &interval->tv_nsec)) + return -EFAULT; + return ret; +} + #ifdef CONFIG_SYSVIPC SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third, @@ -279,6 +295,27 @@ asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_a2, merge_64(len_a4, len_a5)); } +save_static_function(sys32_clone); +static int noinline __used +_sys32_clone(nabi_no_regargs struct pt_regs regs) +{ + unsigned long clone_flags; + unsigned long newsp; + int __user *parent_tidptr, *child_tidptr; + + clone_flags = regs.regs[4]; + newsp = regs.regs[5]; + if (!newsp) + newsp = regs.regs[29]; + parent_tidptr = (int __user *) regs.regs[6]; + + /* Use __dummy4 instead of getting it off the stack, so that + syscall() works. */ + child_tidptr = (int __user *) __dummy4; + return do_fork(clone_flags, newsp, 0, + parent_tidptr, child_tidptr); +} + asmlinkage long sys32_lookup_dcookie(u32 a0, u32 a1, char __user *buf, size_t len) { @@ -291,3 +328,10 @@ SYSCALL_DEFINE6(32_fanotify_mark, int, fanotify_fd, unsigned int, flags, return sys_fanotify_mark(fanotify_fd, flags, merge_64(a3, a4), dfd, pathname); } + +SYSCALL_DEFINE6(32_futex, u32 __user *, uaddr, int, op, u32, val, + struct compat_timespec __user *, utime, u32 __user *, uaddr2, + u32, val3) +{ + return compat_sys_futex(uaddr, op, val, utime, uaddr2, val3); +} diff --git a/trunk/arch/mips/kernel/process.c b/trunk/arch/mips/kernel/process.c index a33d2ef8f273..a11c6f9fdd5e 100644 --- a/trunk/arch/mips/kernel/process.c +++ b/trunk/arch/mips/kernel/process.c @@ -156,8 +156,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, *childregs = *regs; childregs->regs[7] = 0; /* Clear error flag */ childregs->regs[2] = 0; /* Child gets zero as return value */ - if (usp) - childregs->regs[29] = usp; + childregs->regs[29] = usp; ti->addr_limit = USER_DS; p->thread.reg29 = (unsigned long) childregs; diff --git a/trunk/arch/mips/kernel/scall32-o32.S b/trunk/arch/mips/kernel/scall32-o32.S index 80ff9422215f..d20a4bc9ed05 100644 --- a/trunk/arch/mips/kernel/scall32-o32.S +++ b/trunk/arch/mips/kernel/scall32-o32.S @@ -226,7 +226,7 @@ einval: li v0, -ENOSYS .macro syscalltable sys sys_syscall 8 /* 4000 */ sys sys_exit 1 - sys __sys_fork 0 + sys sys_fork 0 sys sys_read 3 sys sys_write 3 sys sys_open 3 /* 4005 */ @@ -344,7 +344,7 @@ einval: li v0, -ENOSYS sys sys_ipc 6 sys sys_fsync 1 sys sys_sigreturn 0 - sys __sys_clone 6 /* 4120 */ + sys sys_clone 0 /* 4120 */ sys sys_setdomainname 2 sys sys_newuname 1 sys sys_ni_syscall 0 /* sys_modify_ldt */ diff --git a/trunk/arch/mips/kernel/scall64-64.S b/trunk/arch/mips/kernel/scall64-64.S index 9444ad9ea575..b64f642da073 100644 --- a/trunk/arch/mips/kernel/scall64-64.S +++ b/trunk/arch/mips/kernel/scall64-64.S @@ -170,8 +170,8 @@ sys_call_table: PTR sys_socketpair PTR sys_setsockopt PTR sys_getsockopt - PTR __sys_clone /* 5055 */ - PTR __sys_fork + PTR sys_clone /* 5055 */ + PTR sys_fork PTR sys_execve PTR sys_exit PTR sys_wait4 diff --git a/trunk/arch/mips/kernel/scall64-n32.S b/trunk/arch/mips/kernel/scall64-n32.S index 3b18a8e29215..c29ac197f446 100644 --- a/trunk/arch/mips/kernel/scall64-n32.S +++ b/trunk/arch/mips/kernel/scall64-n32.S @@ -117,8 +117,8 @@ EXPORT(sysn32_call_table) PTR sys_mprotect /* 6010 */ PTR sys_munmap PTR sys_brk - PTR compat_sys_rt_sigaction - PTR compat_sys_rt_sigprocmask + PTR sys_32_rt_sigaction + PTR sys_32_rt_sigprocmask PTR compat_sys_ioctl /* 6015 */ PTR sys_pread64 PTR sys_pwrite64 @@ -159,8 +159,8 @@ EXPORT(sysn32_call_table) PTR sys_socketpair PTR compat_sys_setsockopt PTR sys_getsockopt - PTR __sys_clone /* 6055 */ - PTR __sys_fork + PTR sys_clone /* 6055 */ + PTR sys_fork PTR compat_sys_execve PTR sys_exit PTR compat_sys_wait4 @@ -229,11 +229,11 @@ EXPORT(sysn32_call_table) PTR sys_getsid PTR sys_capget PTR sys_capset - PTR compat_sys_rt_sigpending /* 6125 */ + PTR sys_32_rt_sigpending /* 6125 */ PTR compat_sys_rt_sigtimedwait - PTR compat_sys_rt_sigqueueinfo - PTR compat_sys_rt_sigsuspend - PTR compat_sys_sigaltstack + PTR sys_32_rt_sigqueueinfo + PTR sysn32_rt_sigsuspend + PTR sys32_sigaltstack PTR compat_sys_utime /* 6130 */ PTR sys_mknod PTR sys_32_personality @@ -249,7 +249,7 @@ EXPORT(sysn32_call_table) PTR sys_sched_getscheduler PTR sys_sched_get_priority_max PTR sys_sched_get_priority_min - PTR compat_sys_sched_rr_get_interval /* 6145 */ + PTR sys_32_sched_rr_get_interval /* 6145 */ PTR sys_mlock PTR sys_munlock PTR sys_mlockall @@ -298,7 +298,7 @@ EXPORT(sysn32_call_table) PTR sys_fremovexattr PTR sys_tkill PTR sys_ni_syscall - PTR compat_sys_futex + PTR sys_32_futex PTR compat_sys_sched_setaffinity /* 6195 */ PTR compat_sys_sched_getaffinity PTR sys_cacheflush diff --git a/trunk/arch/mips/kernel/scall64-o32.S b/trunk/arch/mips/kernel/scall64-o32.S index 063cd0d6ddd2..cf3e75e46650 100644 --- a/trunk/arch/mips/kernel/scall64-o32.S +++ b/trunk/arch/mips/kernel/scall64-o32.S @@ -194,7 +194,7 @@ einval: li v0, -ENOSYS sys_call_table: PTR sys32_syscall /* 4000 */ PTR sys_exit - PTR __sys_fork + PTR sys_fork PTR sys_read PTR sys_write PTR compat_sys_open /* 4005 */ @@ -312,7 +312,7 @@ sys_call_table: PTR sys_32_ipc PTR sys_fsync PTR sys32_sigreturn - PTR __sys_clone /* 4120 */ + PTR sys32_clone /* 4120 */ PTR sys_setdomainname PTR sys_newuname PTR sys_ni_syscall /* sys_modify_ldt */ @@ -357,7 +357,7 @@ sys_call_table: PTR sys_sched_yield PTR sys_sched_get_priority_max PTR sys_sched_get_priority_min - PTR compat_sys_sched_rr_get_interval /* 4165 */ + PTR sys_32_sched_rr_get_interval /* 4165 */ PTR compat_sys_nanosleep PTR sys_mremap PTR sys_accept @@ -386,19 +386,19 @@ sys_call_table: PTR sys_getresgid PTR sys_prctl PTR sys32_rt_sigreturn - PTR compat_sys_rt_sigaction - PTR compat_sys_rt_sigprocmask /* 4195 */ - PTR compat_sys_rt_sigpending + PTR sys_32_rt_sigaction + PTR sys_32_rt_sigprocmask /* 4195 */ + PTR sys_32_rt_sigpending PTR compat_sys_rt_sigtimedwait - PTR compat_sys_rt_sigqueueinfo - PTR compat_sys_rt_sigsuspend + PTR sys_32_rt_sigqueueinfo + PTR sys32_rt_sigsuspend PTR sys_32_pread /* 4200 */ PTR sys_32_pwrite PTR sys_chown PTR sys_getcwd PTR sys_capget PTR sys_capset /* 4205 */ - PTR compat_sys_sigaltstack + PTR sys32_sigaltstack PTR sys_32_sendfile PTR sys_ni_syscall PTR sys_ni_syscall @@ -430,7 +430,7 @@ sys_call_table: PTR sys_fremovexattr /* 4235 */ PTR sys_tkill PTR sys_sendfile64 - PTR compat_sys_futex + PTR sys_32_futex PTR compat_sys_sched_setaffinity PTR compat_sys_sched_getaffinity /* 4240 */ PTR compat_sys_io_setup @@ -470,7 +470,7 @@ sys_call_table: PTR compat_sys_mq_notify /* 4275 */ PTR compat_sys_mq_getsetattr PTR sys_ni_syscall /* sys_vserver */ - PTR compat_sys_waitid + PTR sys_32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key /* 4280 */ PTR sys_request_key diff --git a/trunk/arch/mips/kernel/signal.c b/trunk/arch/mips/kernel/signal.c index 95b019d92f50..4d790d1f03d6 100644 --- a/trunk/arch/mips/kernel/signal.c +++ b/trunk/arch/mips/kernel/signal.c @@ -247,12 +247,31 @@ void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, */ #ifdef CONFIG_TRAD_SIGNALS -SYSCALL_DEFINE1(sigsuspend, sigset_t __user *, uset) +asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs) { - return sys_rt_sigsuspend(uset, sizeof(sigset_t)); + sigset_t newset; + sigset_t __user *uset; + + uset = (sigset_t __user *) regs.regs[4]; + if (copy_from_user(&newset, uset, sizeof(sigset_t))) + return -EFAULT; + return sigsuspend(&newset); } #endif +SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *,unewset, size_t, sigsetsize) +{ + sigset_t newset; + + /* XXX Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + return sigsuspend(&newset); +} + #ifdef CONFIG_TRAD_SIGNALS SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, struct sigaction __user *, oact) @@ -294,6 +313,15 @@ SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, } #endif +asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs) +{ + const stack_t __user *uss = (const stack_t __user *) regs.regs[4]; + stack_t __user *uoss = (stack_t __user *) regs.regs[5]; + unsigned long usp = regs.regs[29]; + + return do_sigaltstack(uss, uoss, usp); +} + #ifdef CONFIG_TRAD_SIGNALS asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) { @@ -350,8 +378,9 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) else if (sig) force_sig(sig, current); - if (restore_altstack(&frame->rs_uc.uc_stack)) - goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs.regs[29]); /* * Don't let your children do this ... @@ -428,7 +457,12 @@ static int setup_rt_frame(void *sig_return, struct k_sigaction *ka, /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); err |= __put_user(NULL, &frame->rs_uc.uc_link); - err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); + err |= __put_user((void __user *)current->sas_ss_sp, + &frame->rs_uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->regs[29]), + &frame->rs_uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, + &frame->rs_uc.uc_stack.ss_size); err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); diff --git a/trunk/arch/mips/kernel/signal32.c b/trunk/arch/mips/kernel/signal32.c index ad7c2be0c33d..da1b56a39ac7 100644 --- a/trunk/arch/mips/kernel/signal32.c +++ b/trunk/arch/mips/kernel/signal32.c @@ -55,10 +55,23 @@ extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user typedef unsigned int __sighandler32_t; typedef void (*vfptr_t)(void); +struct sigaction32 { + unsigned int sa_flags; + __sighandler32_t sa_handler; + compat_sigset_t sa_mask; +}; + +/* IRIX compatible stack_t */ +typedef struct sigaltstack32 { + s32 ss_sp; + compat_size_t ss_size; + int ss_flags; +} stack32_t; + struct ucontext32 { u32 uc_flags; s32 uc_link; - compat_stack_t uc_stack; + stack32_t uc_stack; struct sigcontext32 uc_mcontext; compat_sigset_t uc_sigmask; /* mask last for extensibility */ }; @@ -267,13 +280,36 @@ static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset) +asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) { - return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t)); + compat_sigset_t __user *uset; + sigset_t newset; + + uset = (compat_sigset_t __user *) regs.regs[4]; + if (get_sigset(&newset, uset)) + return -EFAULT; + return sigsuspend(&newset); +} + +asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +{ + compat_sigset_t __user *uset; + sigset_t newset; + size_t sigsetsize; + + /* XXX Don't preclude handling different sized sigset_t's. */ + sigsetsize = regs.regs[5]; + if (sigsetsize != sizeof(compat_sigset_t)) + return -EINVAL; + + uset = (compat_sigset_t __user *) regs.regs[4]; + if (get_sigset(&newset, uset)) + return -EFAULT; + return sigsuspend(&newset); } -SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act, - struct compat_sigaction __user *, oact) +SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act, + struct sigaction32 __user *, oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -314,6 +350,45 @@ SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, return ret; } +asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) +{ + const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4]; + stack32_t __user *uoss = (stack32_t __user *) regs.regs[5]; + unsigned long usp = regs.regs[29]; + stack_t kss, koss; + int ret, err = 0; + mm_segment_t old_fs = get_fs(); + s32 sp; + + if (uss) { + if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) + return -EFAULT; + err |= __get_user(sp, &uss->ss_sp); + kss.ss_sp = (void __user *) (long) sp; + err |= __get_user(kss.ss_size, &uss->ss_size); + err |= __get_user(kss.ss_flags, &uss->ss_flags); + if (err) + return -EFAULT; + } + + set_fs(KERNEL_DS); + ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL, + uoss ? (stack_t __user *)&koss : NULL, usp); + set_fs(old_fs); + + if (!ret && uoss) { + if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) + return -EFAULT; + sp = (int) (unsigned long) koss.ss_sp; + err |= __put_user(sp, &uoss->ss_sp); + err |= __put_user(koss.ss_size, &uoss->ss_size); + err |= __put_user(koss.ss_flags, &uoss->ss_flags); + if (err) + return -EFAULT; + } + return ret; +} + int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err; @@ -415,7 +490,10 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe32 __user *frame; + mm_segment_t old_fs; sigset_t set; + stack_t st; + s32 sp; int sig; frame = (struct rt_sigframe32 __user *) regs.regs[29]; @@ -432,9 +510,22 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) else if (sig) force_sig(sig, current); - if (compat_restore_altstack(&frame->rs_uc.uc_stack)) + /* The ucontext contains a stack32_t, so we must convert! */ + if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) + goto badframe; + st.ss_sp = (void __user *)(long) sp; + if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size)) + goto badframe; + if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags)) goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]); + set_fs(old_fs); + /* * Don't let your children do this ... */ @@ -499,6 +590,7 @@ static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, { struct rt_sigframe32 __user *frame; int err = 0; + s32 sp; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) @@ -510,7 +602,13 @@ static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); err |= __put_user(0, &frame->rs_uc.uc_link); - err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); + sp = (int) (long) current->sas_ss_sp; + err |= __put_user(sp, + &frame->rs_uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->regs[29]), + &frame->rs_uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, + &frame->rs_uc.uc_stack.ss_size); err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); @@ -558,6 +656,131 @@ struct mips_abi mips_abi_32 = { .restart = __NR_O32_restart_syscall }; +SYSCALL_DEFINE4(32_rt_sigaction, int, sig, + const struct sigaction32 __user *, act, + struct sigaction32 __user *, oact, unsigned int, sigsetsize) +{ + struct k_sigaction new_sa, old_sa; + int ret = -EINVAL; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + goto out; + + if (act) { + s32 handler; + int err = 0; + + if (!access_ok(VERIFY_READ, act, sizeof(*act))) + return -EFAULT; + err |= __get_user(handler, &act->sa_handler); + new_sa.sa.sa_handler = (void __user *)(s64)handler; + err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags); + err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); + if (err) + return -EFAULT; + } + + ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); + + if (!ret && oact) { + int err = 0; + + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) + return -EFAULT; + + err |= __put_user((u32)(u64)old_sa.sa.sa_handler, + &oact->sa_handler); + err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags); + err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask); + if (err) + return -EFAULT; + } +out: + return ret; +} + +SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set, + compat_sigset_t __user *, oset, unsigned int, sigsetsize) +{ + sigset_t old_set, new_set; + int ret; + mm_segment_t old_fs = get_fs(); + + if (set && get_sigset(&new_set, set)) + return -EFAULT; + + set_fs(KERNEL_DS); + ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL, + oset ? (sigset_t __user *)&old_set : NULL, + sigsetsize); + set_fs(old_fs); + + if (!ret && oset && put_sigset(&old_set, oset)) + return -EFAULT; + + return ret; +} + +SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset, + unsigned int, sigsetsize) +{ + int ret; + sigset_t set; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize); + set_fs(old_fs); + + if (!ret && put_sigset(&set, uset)) + return -EFAULT; + + return ret; +} + +SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig, + compat_siginfo_t __user *, uinfo) +{ + siginfo_t info; + int ret; + mm_segment_t old_fs = get_fs(); + + if (copy_from_user(&info, uinfo, 3*sizeof(int)) || + copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info); + set_fs(old_fs); + return ret; +} + +SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid, + compat_siginfo_t __user *, uinfo, int, options, + struct compat_rusage __user *, uru) +{ + siginfo_t info; + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + info.si_signo = 0; + set_fs(KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, + uru ? (struct rusage __user *) &ru : NULL); + set_fs(old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru && (ret = put_compat_rusage(&ru, uru))) + return ret; + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return copy_siginfo_to_user32(uinfo, &info); +} + static int signal32_init(void) { if (cpu_has_fpu) { diff --git a/trunk/arch/mips/kernel/signal_n32.c b/trunk/arch/mips/kernel/signal_n32.c index 5f4ef2ae6199..3574c145511b 100644 --- a/trunk/arch/mips/kernel/signal_n32.c +++ b/trunk/arch/mips/kernel/signal_n32.c @@ -50,10 +50,18 @@ extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); + +/* IRIX compatible stack_t */ +typedef struct sigaltstack32 { + s32 ss_sp; + compat_size_t ss_size; + int ss_flags; +} stack32_t; + struct ucontextn32 { u32 uc_flags; s32 uc_link; - compat_stack_t uc_stack; + stack32_t uc_stack; struct sigcontext uc_mcontext; compat_sigset_t uc_sigmask; /* mask last for extensibility */ }; @@ -65,10 +73,34 @@ struct rt_sigframe_n32 { struct ucontextn32 rs_uc; }; +extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); + +asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +{ + compat_sigset_t __user *unewset; + compat_sigset_t uset; + size_t sigsetsize; + sigset_t newset; + + /* XXX Don't preclude handling different sized sigset_t's. */ + sigsetsize = regs.regs[5]; + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + unewset = (compat_sigset_t __user *) regs.regs[4]; + if (copy_from_user(&uset, unewset, sizeof(uset))) + return -EFAULT; + sigset_from_compat(&newset, &uset); + return sigsuspend(&newset); +} + asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe_n32 __user *frame; + mm_segment_t old_fs; sigset_t set; + stack_t st; + s32 sp; int sig; frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; @@ -85,9 +117,23 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) else if (sig) force_sig(sig, current); - if (compat_restore_altstack(&frame->rs_uc.uc_stack)) + /* The ucontext contains a stack32_t, so we must convert! */ + if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) + goto badframe; + st.ss_sp = (void __user *)(long) sp; + if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size)) + goto badframe; + if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags)) goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]); + set_fs(old_fs); + + /* * Don't let your children do this ... */ @@ -107,6 +153,7 @@ static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka, { struct rt_sigframe_n32 __user *frame; int err = 0; + s32 sp; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) @@ -118,7 +165,13 @@ static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka, /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); err |= __put_user(0, &frame->rs_uc.uc_link); - err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); + sp = (int) (long) current->sas_ss_sp; + err |= __put_user(sp, + &frame->rs_uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->regs[29]), + &frame->rs_uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, + &frame->rs_uc.uc_stack.ss_size); err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); diff --git a/trunk/arch/mips/kernel/syscall.c b/trunk/arch/mips/kernel/syscall.c index b32466a1a1d2..201cb76b4df9 100644 --- a/trunk/arch/mips/kernel/syscall.c +++ b/trunk/arch/mips/kernel/syscall.c @@ -46,14 +46,20 @@ * argument. Historically that used to be expensive in Linux. These days * the performance advantage is negligible. */ -asmlinkage int sysm_pipe(void) +asmlinkage int sysm_pipe(nabi_no_regargs volatile struct pt_regs regs) { int fd[2]; - int error = do_pipe_flags(fd, 0); - if (error) - return error; - current_pt_regs()->regs[3] = fd[1]; - return fd[0]; + int error, res; + + error = do_pipe_flags(fd, 0); + if (error) { + res = error; + goto out; + } + regs.regs[3] = fd[1]; + res = fd[0]; +out: + return res; } SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, @@ -83,7 +89,43 @@ SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len, } save_static_function(sys_fork); +static int __used noinline +_sys_fork(nabi_no_regargs struct pt_regs regs) +{ + return do_fork(SIGCHLD, regs.regs[29], 0, NULL, NULL); +} + save_static_function(sys_clone); +static int __used noinline +_sys_clone(nabi_no_regargs struct pt_regs regs) +{ + unsigned long clone_flags; + unsigned long newsp; + int __user *parent_tidptr, *child_tidptr; + + clone_flags = regs.regs[4]; + newsp = regs.regs[5]; + if (!newsp) + newsp = regs.regs[29]; + parent_tidptr = (int __user *) regs.regs[6]; +#ifdef CONFIG_32BIT + /* We need to fetch the fifth argument off the stack. */ + child_tidptr = NULL; + if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) { + int __user *__user *usp = (int __user *__user *) regs.regs[29]; + if (regs.regs[2] == __NR_syscall) { + if (get_user (child_tidptr, &usp[5])) + return -EFAULT; + } + else if (get_user (child_tidptr, &usp[4])) + return -EFAULT; + } +#else + child_tidptr = (int __user *) regs.regs[8]; +#endif + return do_fork(clone_flags, newsp, 0, + parent_tidptr, child_tidptr); +} SYSCALL_DEFINE1(set_thread_area, unsigned long, addr) { @@ -96,10 +138,10 @@ SYSCALL_DEFINE1(set_thread_area, unsigned long, addr) return 0; } -static inline int mips_atomic_set(unsigned long addr, unsigned long new) +static inline int mips_atomic_set(struct pt_regs *regs, + unsigned long addr, unsigned long new) { unsigned long old, tmp; - struct pt_regs *regs; unsigned int err; if (unlikely(addr & 3)) @@ -180,7 +222,6 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) if (unlikely(err)) return err; - regs = current_pt_regs(); regs->regs[2] = old; regs->regs[7] = 0; /* No error */ @@ -194,14 +235,22 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) : "r" (regs)); /* unreached. Honestly. */ - unreachable(); + while (1); } -SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2) +save_static_function(sys_sysmips); +static int __used noinline +_sys_sysmips(nabi_no_regargs struct pt_regs regs) { + long cmd, arg1, arg2; + + cmd = regs.regs[4]; + arg1 = regs.regs[5]; + arg2 = regs.regs[6]; + switch (cmd) { case MIPS_ATOMIC_SET: - return mips_atomic_set(arg1, arg2); + return mips_atomic_set(®s, arg1, arg2); case MIPS_FIXADE: if (arg1 & ~3) diff --git a/trunk/arch/mn10300/Kconfig b/trunk/arch/mn10300/Kconfig index e70001cfa05b..cb5022029606 100644 --- a/trunk/arch/mn10300/Kconfig +++ b/trunk/arch/mn10300/Kconfig @@ -10,6 +10,7 @@ config MN10300 select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER select GENERIC_CLOCKEVENTS select MODULES_USE_ELF_RELA + select GENERIC_SIGALTSTACK config AM33_2 def_bool n diff --git a/trunk/arch/mn10300/kernel/signal.c b/trunk/arch/mn10300/kernel/signal.c index f570b3085ef9..8223eb371e65 100644 --- a/trunk/arch/mn10300/kernel/signal.c +++ b/trunk/arch/mn10300/kernel/signal.c @@ -76,14 +76,6 @@ asmlinkage long sys_sigaction(int sig, return ret; } -/* - * set alternate signal stack syscall - */ -asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t *uoss) -{ - return do_sigaltstack(uss, uoss, current_frame()->sp); -} - /* * do a signal return; undo the signal stack. */ @@ -193,8 +185,7 @@ asmlinkage long sys_rt_sigreturn(void) if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0)) goto badframe; - if (do_sigaltstack(&frame->uc.uc_stack, NULL, current_frame()->sp) == - -EFAULT) + if (restore_altstack(&frame->uc.uc_stack)) goto badframe; return d0; @@ -359,9 +350,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* create the ucontext. */ if (__put_user(0, &frame->uc.uc_flags) || __put_user(0, &frame->uc.uc_link) || - __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || - __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags) || - __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size) || + __save_altstack(&frame->uc.uc_stack, regs->sp) || setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpuctx, regs, set->sig[0]) || __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set))) diff --git a/trunk/kernel/signal.c b/trunk/kernel/signal.c index 87c09e3061d2..775f5552fa0e 100644 --- a/trunk/kernel/signal.c +++ b/trunk/kernel/signal.c @@ -3562,6 +3562,7 @@ int sigsuspend(sigset_t *set) return -ERESTARTNOHAND; } +#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND /** * sys_rt_sigsuspend - replace the signal mask for a value with the * @unewset value until a signal is received @@ -3602,6 +3603,7 @@ COMPAT_SYSCALL_DEFINE2(rt_sigsuspend, compat_sigset_t __user *, unewset, compat_ #endif } #endif +#endif #ifdef CONFIG_OLD_SIGSUSPEND SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)