aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-02-12 19:05:11 -0500
committerRalf Baechle <ralf@linux-mips.org>2007-02-13 17:40:51 -0500
commit431dc8040354db65e4f8d4d4e21ae4fab41f5bc3 (patch)
tree54381eb2e9b738fd3d87fd129da85086983296c5
parent366d6aef281a670b32a51d289fc07bf0e5e72d9a (diff)
[MIPS] Fix sigset_t endianess swapping issues in 32-bit compat code.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/kernel/linux32.c47
-rw-r--r--arch/mips/kernel/scall64-64.S2
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/signal32.c11
-rw-r--r--arch/mips/kernel/signal_n32.c7
-rw-r--r--include/asm-mips/compat-signal.h55
6 files changed, 115 insertions, 9 deletions
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index ca7ad78f4def..fc4dd6c9dd80 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -39,6 +39,7 @@
39#include <net/sock.h> 39#include <net/sock.h>
40#include <net/scm.h> 40#include <net/scm.h>
41 41
42#include <asm/compat-signal.h>
42#include <asm/ipc.h> 43#include <asm/ipc.h>
43#include <asm/sim.h> 44#include <asm/sim.h>
44#include <asm/uaccess.h> 45#include <asm/uaccess.h>
@@ -736,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs)
736 return do_fork(clone_flags, newsp, &regs, 0, 737 return do_fork(clone_flags, newsp, &regs, 0,
737 parent_tidptr, child_tidptr); 738 parent_tidptr, child_tidptr);
738} 739}
740
741/*
742 * Implement the event wait interface for the eventpoll file. It is the kernel
743 * part of the user space epoll_pwait(2).
744 */
745asmlinkage long compat_sys_epoll_pwait(int epfd,
746 struct epoll_event __user *events, int maxevents, int timeout,
747 const compat_sigset_t __user *sigmask, size_t sigsetsize)
748{
749 int error;
750 sigset_t ksigmask, sigsaved;
751
752 /*
753 * If the caller wants a certain signal mask to be set during the wait,
754 * we apply it here.
755 */
756 if (sigmask) {
757 if (sigsetsize != sizeof(sigset_t))
758 return -EINVAL;
759 if (!access_ok(VERIFY_READ, sigmask, sizeof(ksigmask)))
760 return -EFAULT;
761 if (__copy_conv_sigset_from_user(&ksigmask, sigmask))
762 return -EFAULT;
763 sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
764 sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
765 }
766
767 error = sys_epoll_wait(epfd, events, maxevents, timeout);
768
769 /*
770 * If we changed the signal mask, we need to restore the original one.
771 * In case we've got a signal while waiting, we do not restore the
772 * signal mask yet, and we allow do_signal() to deliver the signal on
773 * the way back to userspace, before the signal mask is restored.
774 */
775 if (sigmask) {
776 if (error == -EINTR) {
777 memcpy(&current->saved_sigmask, &sigsaved,
778 sizeof(sigsaved));
779 set_thread_flag(TIF_RESTORE_SIGMASK);
780 } else
781 sigprocmask(SIG_SETMASK, &sigsaved, NULL);
782 }
783
784 return error;
785}
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index e569b846e9a3..10e9a18630aa 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -470,4 +470,4 @@ sys_call_table:
470 PTR sys_get_robust_list 470 PTR sys_get_robust_list
471 PTR sys_kexec_load /* 5270 */ 471 PTR sys_kexec_load /* 5270 */
472 PTR sys_getcpu 472 PTR sys_getcpu
473 PTR sys_epoll_pwait 473 PTR compat_sys_epoll_pwait
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index ee8802b59758..2ceda4644a4d 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -396,4 +396,4 @@ EXPORT(sysn32_call_table)
396 PTR compat_sys_get_robust_list 396 PTR compat_sys_get_robust_list
397 PTR compat_sys_kexec_load 397 PTR compat_sys_kexec_load
398 PTR sys_getcpu 398 PTR sys_getcpu
399 PTR sys_epoll_pwait 399 PTR compat_sys_epoll_pwait
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index db00c333bff3..c28cb21514c8 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -8,6 +8,7 @@
8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9 */ 9 */
10#include <linux/cache.h> 10#include <linux/cache.h>
11#include <linux/compat.h>
11#include <linux/sched.h> 12#include <linux/sched.h>
12#include <linux/mm.h> 13#include <linux/mm.h>
13#include <linux/smp.h> 14#include <linux/smp.h>
@@ -24,6 +25,7 @@
24 25
25#include <asm/abi.h> 26#include <asm/abi.h>
26#include <asm/asm.h> 27#include <asm/asm.h>
28#include <asm/compat-signal.h>
27#include <linux/bitops.h> 29#include <linux/bitops.h>
28#include <asm/cacheflush.h> 30#include <asm/cacheflush.h>
29#include <asm/sim.h> 31#include <asm/sim.h>
@@ -517,7 +519,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
517 frame = (struct sigframe32 __user *) regs.regs[29]; 519 frame = (struct sigframe32 __user *) regs.regs[29];
518 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 520 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
519 goto badframe; 521 goto badframe;
520 if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) 522 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
521 goto badframe; 523 goto badframe;
522 524
523 sigdelsetmask(&blocked, ~_BLOCKABLE); 525 sigdelsetmask(&blocked, ~_BLOCKABLE);
@@ -554,7 +556,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
554 frame = (struct rt_sigframe32 __user *) regs.regs[29]; 556 frame = (struct rt_sigframe32 __user *) regs.regs[29];
555 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 557 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
556 goto badframe; 558 goto badframe;
557 if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 559 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
558 goto badframe; 560 goto badframe;
559 561
560 sigdelsetmask(&set, ~_BLOCKABLE); 562 sigdelsetmask(&set, ~_BLOCKABLE);
@@ -609,7 +611,8 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
609 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn); 611 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
610 612
611 err |= setup_sigcontext32(regs, &frame->sf_sc); 613 err |= setup_sigcontext32(regs, &frame->sf_sc);
612 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 614 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
615
613 if (err) 616 if (err)
614 goto give_sigsegv; 617 goto give_sigsegv;
615 618
@@ -668,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
668 err |= __put_user(current->sas_ss_size, 671 err |= __put_user(current->sas_ss_size,
669 &frame->rs_uc.uc_stack.ss_size); 672 &frame->rs_uc.uc_stack.ss_size);
670 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); 673 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
671 err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 674 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
672 675
673 if (err) 676 if (err)
674 goto give_sigsegv; 677 goto give_sigsegv;
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 1a5f248faf3b..7ca2a078841f 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -31,6 +31,7 @@
31 31
32#include <asm/asm.h> 32#include <asm/asm.h>
33#include <asm/cacheflush.h> 33#include <asm/cacheflush.h>
34#include <asm/compat-signal.h>
34#include <asm/sim.h> 35#include <asm/sim.h>
35#include <asm/uaccess.h> 36#include <asm/uaccess.h>
36#include <asm/ucontext.h> 37#include <asm/ucontext.h>
@@ -63,7 +64,7 @@ struct ucontextn32 {
63 s32 uc_link; 64 s32 uc_link;
64 stack32_t uc_stack; 65 stack32_t uc_stack;
65 struct sigcontext uc_mcontext; 66 struct sigcontext uc_mcontext;
66 sigset_t uc_sigmask; /* mask last for extensibility */ 67 compat_sigset_t uc_sigmask; /* mask last for extensibility */
67}; 68};
68 69
69#if ICACHE_REFILLS_WORKAROUND_WAR == 0 70#if ICACHE_REFILLS_WORKAROUND_WAR == 0
@@ -129,7 +130,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
129 frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; 130 frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
130 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 131 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
131 goto badframe; 132 goto badframe;
132 if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 133 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
133 goto badframe; 134 goto badframe;
134 135
135 sigdelsetmask(&set, ~_BLOCKABLE); 136 sigdelsetmask(&set, ~_BLOCKABLE);
@@ -195,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka,
195 err |= __put_user(current->sas_ss_size, 196 err |= __put_user(current->sas_ss_size,
196 &frame->rs_uc.uc_stack.ss_size); 197 &frame->rs_uc.uc_stack.ss_size);
197 err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 198 err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
198 err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 199 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
199 200
200 if (err) 201 if (err)
201 goto give_sigsegv; 202 goto give_sigsegv;
diff --git a/include/asm-mips/compat-signal.h b/include/asm-mips/compat-signal.h
new file mode 100644
index 000000000000..672077084aa1
--- /dev/null
+++ b/include/asm-mips/compat-signal.h
@@ -0,0 +1,55 @@
1#ifndef __ASM_COMPAT_SIGNAL_H
2#define __ASM_COMPAT_SIGNAL_H
3
4#include <linux/bug.h>
5#include <linux/compat.h>
6#include <linux/compiler.h>
7
8static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d,
9 const sigset_t *s)
10{
11 int err;
12
13 BUG_ON(sizeof(*d) != sizeof(*s));
14 BUG_ON(_NSIG_WORDS != 2);
15
16 err = __put_user(s->sig[0], &d->sig[0]);
17 err |= __put_user(s->sig[0] >> 32, &d->sig[1]);
18 err |= __put_user(s->sig[1], &d->sig[2]);
19 err |= __put_user(s->sig[1] >> 32, &d->sig[3]);
20
21 return err;
22}
23
24static inline int __copy_conv_sigset_from_user(sigset_t *d,
25 const compat_sigset_t __user *s)
26{
27 int err;
28 union sigset_u {
29 sigset_t s;
30 compat_sigset_t c;
31 } *u = (union sigset_u *) d;
32
33 BUG_ON(sizeof(*d) != sizeof(*s));
34 BUG_ON(_NSIG_WORDS != 2);
35
36 if (unlikely(!access_ok(VERIFY_READ, d, sizeof(*d))))
37 return -EFAULT;
38
39#ifdef CONFIG_CPU_BIG_ENDIAN
40 err = __get_user(u->c.sig[1], &s->sig[0]);
41 err |= __get_user(u->c.sig[0], &s->sig[1]);
42 err |= __get_user(u->c.sig[3], &s->sig[2]);
43 err |= __get_user(u->c.sig[2], &s->sig[3]);
44#endif
45#ifdef CONFIG_CPU_LITTLE_ENDIAN
46 err = __get_user(u->c.sig[0], &s->sig[0]);
47 err |= __get_user(u->c.sig[1], &s->sig[1]);
48 err |= __get_user(u->c.sig[2], &s->sig[2]);
49 err |= __get_user(u->c.sig[3], &s->sig[3]);
50#endif
51
52 return err;
53}
54
55#endif /* __ASM_COMPAT_SIGNAL_H */