[MIPS] Fix sigset_t endianess swapping issues in 32-bit compat code.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
366d6aef28
commit
431dc80403
6 changed files with 115 additions and 9 deletions
|
@ -39,6 +39,7 @@
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
#include <net/scm.h>
|
#include <net/scm.h>
|
||||||
|
|
||||||
|
#include <asm/compat-signal.h>
|
||||||
#include <asm/ipc.h>
|
#include <asm/ipc.h>
|
||||||
#include <asm/sim.h>
|
#include <asm/sim.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
@ -736,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs)
|
||||||
return do_fork(clone_flags, newsp, ®s, 0,
|
return do_fork(clone_flags, newsp, ®s, 0,
|
||||||
parent_tidptr, child_tidptr);
|
parent_tidptr, child_tidptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implement the event wait interface for the eventpoll file. It is the kernel
|
||||||
|
* part of the user space epoll_pwait(2).
|
||||||
|
*/
|
||||||
|
asmlinkage long compat_sys_epoll_pwait(int epfd,
|
||||||
|
struct epoll_event __user *events, int maxevents, int timeout,
|
||||||
|
const compat_sigset_t __user *sigmask, size_t sigsetsize)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
sigset_t ksigmask, sigsaved;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the caller wants a certain signal mask to be set during the wait,
|
||||||
|
* we apply it here.
|
||||||
|
*/
|
||||||
|
if (sigmask) {
|
||||||
|
if (sigsetsize != sizeof(sigset_t))
|
||||||
|
return -EINVAL;
|
||||||
|
if (!access_ok(VERIFY_READ, sigmask, sizeof(ksigmask)))
|
||||||
|
return -EFAULT;
|
||||||
|
if (__copy_conv_sigset_from_user(&ksigmask, sigmask))
|
||||||
|
return -EFAULT;
|
||||||
|
sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
|
||||||
|
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = sys_epoll_wait(epfd, events, maxevents, timeout);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we changed the signal mask, we need to restore the original one.
|
||||||
|
* In case we've got a signal while waiting, we do not restore the
|
||||||
|
* signal mask yet, and we allow do_signal() to deliver the signal on
|
||||||
|
* the way back to userspace, before the signal mask is restored.
|
||||||
|
*/
|
||||||
|
if (sigmask) {
|
||||||
|
if (error == -EINTR) {
|
||||||
|
memcpy(¤t->saved_sigmask, &sigsaved,
|
||||||
|
sizeof(sigsaved));
|
||||||
|
set_thread_flag(TIF_RESTORE_SIGMASK);
|
||||||
|
} else
|
||||||
|
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
|
@ -470,4 +470,4 @@ sys_call_table:
|
||||||
PTR sys_get_robust_list
|
PTR sys_get_robust_list
|
||||||
PTR sys_kexec_load /* 5270 */
|
PTR sys_kexec_load /* 5270 */
|
||||||
PTR sys_getcpu
|
PTR sys_getcpu
|
||||||
PTR sys_epoll_pwait
|
PTR compat_sys_epoll_pwait
|
||||||
|
|
|
@ -396,4 +396,4 @@ EXPORT(sysn32_call_table)
|
||||||
PTR compat_sys_get_robust_list
|
PTR compat_sys_get_robust_list
|
||||||
PTR compat_sys_kexec_load
|
PTR compat_sys_kexec_load
|
||||||
PTR sys_getcpu
|
PTR sys_getcpu
|
||||||
PTR sys_epoll_pwait
|
PTR compat_sys_epoll_pwait
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
|
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
|
||||||
*/
|
*/
|
||||||
#include <linux/cache.h>
|
#include <linux/cache.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
|
|
||||||
#include <asm/abi.h>
|
#include <asm/abi.h>
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
|
#include <asm/compat-signal.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
#include <asm/sim.h>
|
#include <asm/sim.h>
|
||||||
|
@ -517,7 +519,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
|
||||||
frame = (struct sigframe32 __user *) regs.regs[29];
|
frame = (struct sigframe32 __user *) regs.regs[29];
|
||||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
|
if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
sigdelsetmask(&blocked, ~_BLOCKABLE);
|
sigdelsetmask(&blocked, ~_BLOCKABLE);
|
||||||
|
@ -554,7 +556,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
|
||||||
frame = (struct rt_sigframe32 __user *) regs.regs[29];
|
frame = (struct rt_sigframe32 __user *) regs.regs[29];
|
||||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
|
if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||||
|
@ -609,7 +611,8 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
|
||||||
err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
|
err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
|
||||||
|
|
||||||
err |= setup_sigcontext32(regs, &frame->sf_sc);
|
err |= setup_sigcontext32(regs, &frame->sf_sc);
|
||||||
err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
|
err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
|
|
||||||
|
@ -668,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
|
||||||
err |= __put_user(current->sas_ss_size,
|
err |= __put_user(current->sas_ss_size,
|
||||||
&frame->rs_uc.uc_stack.ss_size);
|
&frame->rs_uc.uc_stack.ss_size);
|
||||||
err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
|
err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
|
||||||
err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
|
err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
|
#include <asm/compat-signal.h>
|
||||||
#include <asm/sim.h>
|
#include <asm/sim.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/ucontext.h>
|
#include <asm/ucontext.h>
|
||||||
|
@ -63,7 +64,7 @@ struct ucontextn32 {
|
||||||
s32 uc_link;
|
s32 uc_link;
|
||||||
stack32_t uc_stack;
|
stack32_t uc_stack;
|
||||||
struct sigcontext uc_mcontext;
|
struct sigcontext uc_mcontext;
|
||||||
sigset_t uc_sigmask; /* mask last for extensibility */
|
compat_sigset_t uc_sigmask; /* mask last for extensibility */
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ICACHE_REFILLS_WORKAROUND_WAR == 0
|
#if ICACHE_REFILLS_WORKAROUND_WAR == 0
|
||||||
|
@ -129,7 +130,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
|
||||||
frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
|
frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
|
||||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
|
if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||||
|
@ -195,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka,
|
||||||
err |= __put_user(current->sas_ss_size,
|
err |= __put_user(current->sas_ss_size,
|
||||||
&frame->rs_uc.uc_stack.ss_size);
|
&frame->rs_uc.uc_stack.ss_size);
|
||||||
err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
|
err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
|
||||||
err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
|
err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
|
|
55
include/asm-mips/compat-signal.h
Normal file
55
include/asm-mips/compat-signal.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef __ASM_COMPAT_SIGNAL_H
|
||||||
|
#define __ASM_COMPAT_SIGNAL_H
|
||||||
|
|
||||||
|
#include <linux/bug.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
|
static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d,
|
||||||
|
const sigset_t *s)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
BUG_ON(sizeof(*d) != sizeof(*s));
|
||||||
|
BUG_ON(_NSIG_WORDS != 2);
|
||||||
|
|
||||||
|
err = __put_user(s->sig[0], &d->sig[0]);
|
||||||
|
err |= __put_user(s->sig[0] >> 32, &d->sig[1]);
|
||||||
|
err |= __put_user(s->sig[1], &d->sig[2]);
|
||||||
|
err |= __put_user(s->sig[1] >> 32, &d->sig[3]);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __copy_conv_sigset_from_user(sigset_t *d,
|
||||||
|
const compat_sigset_t __user *s)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
union sigset_u {
|
||||||
|
sigset_t s;
|
||||||
|
compat_sigset_t c;
|
||||||
|
} *u = (union sigset_u *) d;
|
||||||
|
|
||||||
|
BUG_ON(sizeof(*d) != sizeof(*s));
|
||||||
|
BUG_ON(_NSIG_WORDS != 2);
|
||||||
|
|
||||||
|
if (unlikely(!access_ok(VERIFY_READ, d, sizeof(*d))))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||||
|
err = __get_user(u->c.sig[1], &s->sig[0]);
|
||||||
|
err |= __get_user(u->c.sig[0], &s->sig[1]);
|
||||||
|
err |= __get_user(u->c.sig[3], &s->sig[2]);
|
||||||
|
err |= __get_user(u->c.sig[2], &s->sig[3]);
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CPU_LITTLE_ENDIAN
|
||||||
|
err = __get_user(u->c.sig[0], &s->sig[0]);
|
||||||
|
err |= __get_user(u->c.sig[1], &s->sig[1]);
|
||||||
|
err |= __get_user(u->c.sig[2], &s->sig[2]);
|
||||||
|
err |= __get_user(u->c.sig[3], &s->sig[3]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ASM_COMPAT_SIGNAL_H */
|
Loading…
Reference in a new issue