diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 21:11:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 21:11:45 -0400 |
commit | f9369910a6225b8d4892c3f20ae740a711cd5ace (patch) | |
tree | 8650ff79d7607bceb35509c028400ecf1c317de0 /arch/sh/kernel | |
parent | 05f144a0d5c2207a0349348127f996e104ad7404 (diff) | |
parent | 415d04d08fec74b226c92c1fb54ad117c9c6bac4 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull first series of signal handling cleanups from Al Viro:
"This is just the first part of the queue (about a half of it);
assorted fixes all over the place in signal handling.
This one ends with all sigsuspend() implementations switched to
generic one (->saved_sigmask-based).
With this, a bunch of assorted old buglets are fixed and most of the
missing bits of NOTIFY_RESUME hookup are in place. Two more fixes sit
in arm and um trees respectively, and there's a couple of broken ones
that need obvious fixes - parisc and avr32 check TIF_NOTIFY_RESUME
only on one of two codepaths; fixes for that will happen in the next
series"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (55 commits)
unicore32: if there's no handler we need to restore sigmask, syscall or no syscall
xtensa: add handling of TIF_NOTIFY_RESUME
microblaze: drop 'oldset' argument of do_notify_resume()
microblaze: handle TIF_NOTIFY_RESUME
score: add handling of NOTIFY_RESUME to do_notify_resume()
m68k: add TIF_NOTIFY_RESUME and handle it.
sparc: kill ancient comment in sparc_sigaction()
h8300: missing checks of __get_user()/__put_user() return values
frv: missing checks of __get_user()/__put_user() return values
cris: missing checks of __get_user()/__put_user() return values
powerpc: missing checks of __get_user()/__put_user() return values
sh: missing checks of __get_user()/__put_user() return values
sparc: missing checks of __get_user()/__put_user() return values
avr32: struct old_sigaction is never used
m32r: struct old_sigaction is never used
xtensa: xtensa_sigaction doesn't exist
alpha: tidy signal delivery up
score: don't open-code force_sigsegv()
cris: don't open-code force_sigsegv()
blackfin: don't open-code force_sigsegv()
...
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/signal_32.c | 53 | ||||
-rw-r--r-- | arch/sh/kernel/signal_64.c | 84 |
2 files changed, 39 insertions, 98 deletions
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 5901fba3176..cb4172c8af7 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
@@ -53,23 +53,11 @@ struct fdpic_func_descriptor { | |||
53 | * Atomically swap in the new signal mask, and wait for a signal. | 53 | * Atomically swap in the new signal mask, and wait for a signal. |
54 | */ | 54 | */ |
55 | asmlinkage int | 55 | asmlinkage int |
56 | sys_sigsuspend(old_sigset_t mask, | 56 | sys_sigsuspend(old_sigset_t mask) |
57 | unsigned long r5, unsigned long r6, unsigned long r7, | ||
58 | struct pt_regs __regs) | ||
59 | { | 57 | { |
60 | sigset_t blocked; | 58 | sigset_t blocked; |
61 | |||
62 | current->saved_sigmask = current->blocked; | ||
63 | |||
64 | mask &= _BLOCKABLE; | ||
65 | siginitset(&blocked, mask); | 59 | siginitset(&blocked, mask); |
66 | set_current_blocked(&blocked); | 60 | return sigsuspend(&blocked); |
67 | |||
68 | current->state = TASK_INTERRUPTIBLE; | ||
69 | schedule(); | ||
70 | set_restore_sigmask(); | ||
71 | |||
72 | return -ERESTARTNOHAND; | ||
73 | } | 61 | } |
74 | 62 | ||
75 | asmlinkage int | 63 | asmlinkage int |
@@ -83,10 +71,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
83 | old_sigset_t mask; | 71 | old_sigset_t mask; |
84 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 72 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
85 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 73 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
86 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 74 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || |
75 | __get_user(new_ka.sa.sa_flags, &act->sa_flags) || | ||
76 | __get_user(mask, &act->sa_mask)) | ||
87 | return -EFAULT; | 77 | return -EFAULT; |
88 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
89 | __get_user(mask, &act->sa_mask); | ||
90 | siginitset(&new_ka.sa.sa_mask, mask); | 78 | siginitset(&new_ka.sa.sa_mask, mask); |
91 | } | 79 | } |
92 | 80 | ||
@@ -95,10 +83,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
95 | if (!ret && oact) { | 83 | if (!ret && oact) { |
96 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 84 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
97 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 85 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
98 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 86 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || |
87 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || | ||
88 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) | ||
99 | return -EFAULT; | 89 | return -EFAULT; |
100 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
101 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
102 | } | 90 | } |
103 | 91 | ||
104 | return ret; | 92 | return ret; |
@@ -162,12 +150,11 @@ static inline int save_sigcontext_fpu(struct sigcontext __user *sc, | |||
162 | if (!(boot_cpu_data.flags & CPU_HAS_FPU)) | 150 | if (!(boot_cpu_data.flags & CPU_HAS_FPU)) |
163 | return 0; | 151 | return 0; |
164 | 152 | ||
165 | if (!used_math()) { | 153 | if (!used_math()) |
166 | __put_user(0, &sc->sc_ownedfp); | 154 | return __put_user(0, &sc->sc_ownedfp); |
167 | return 0; | ||
168 | } | ||
169 | 155 | ||
170 | __put_user(1, &sc->sc_ownedfp); | 156 | if (__put_user(1, &sc->sc_ownedfp)) |
157 | return -EFAULT; | ||
171 | 158 | ||
172 | /* This will cause a "finit" to be triggered by the next | 159 | /* This will cause a "finit" to be triggered by the next |
173 | attempted FPU operation by the 'current' process. | 160 | attempted FPU operation by the 'current' process. |
@@ -207,7 +194,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p | |||
207 | regs->sr |= SR_FD; /* Release FPU */ | 194 | regs->sr |= SR_FD; /* Release FPU */ |
208 | clear_fpu(tsk, regs); | 195 | clear_fpu(tsk, regs); |
209 | clear_used_math(); | 196 | clear_used_math(); |
210 | __get_user (owned_fp, &sc->sc_ownedfp); | 197 | err |= __get_user (owned_fp, &sc->sc_ownedfp); |
211 | if (owned_fp) | 198 | if (owned_fp) |
212 | err |= restore_sigcontext_fpu(sc); | 199 | err |= restore_sigcontext_fpu(sc); |
213 | } | 200 | } |
@@ -398,11 +385,14 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
398 | struct fdpic_func_descriptor __user *funcptr = | 385 | struct fdpic_func_descriptor __user *funcptr = |
399 | (struct fdpic_func_descriptor __user *)ka->sa.sa_handler; | 386 | (struct fdpic_func_descriptor __user *)ka->sa.sa_handler; |
400 | 387 | ||
401 | __get_user(regs->pc, &funcptr->text); | 388 | err |= __get_user(regs->pc, &funcptr->text); |
402 | __get_user(regs->regs[12], &funcptr->GOT); | 389 | err |= __get_user(regs->regs[12], &funcptr->GOT); |
403 | } else | 390 | } else |
404 | regs->pc = (unsigned long)ka->sa.sa_handler; | 391 | regs->pc = (unsigned long)ka->sa.sa_handler; |
405 | 392 | ||
393 | if (err) | ||
394 | goto give_sigsegv; | ||
395 | |||
406 | set_fs(USER_DS); | 396 | set_fs(USER_DS); |
407 | 397 | ||
408 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 398 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
@@ -482,11 +472,14 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
482 | struct fdpic_func_descriptor __user *funcptr = | 472 | struct fdpic_func_descriptor __user *funcptr = |
483 | (struct fdpic_func_descriptor __user *)ka->sa.sa_handler; | 473 | (struct fdpic_func_descriptor __user *)ka->sa.sa_handler; |
484 | 474 | ||
485 | __get_user(regs->pc, &funcptr->text); | 475 | err |= __get_user(regs->pc, &funcptr->text); |
486 | __get_user(regs->regs[12], &funcptr->GOT); | 476 | err |= __get_user(regs->regs[12], &funcptr->GOT); |
487 | } else | 477 | } else |
488 | regs->pc = (unsigned long)ka->sa.sa_handler; | 478 | regs->pc = (unsigned long)ka->sa.sa_handler; |
489 | 479 | ||
480 | if (err) | ||
481 | goto give_sigsegv; | ||
482 | |||
490 | set_fs(USER_DS); | 483 | set_fs(USER_DS); |
491 | 484 | ||
492 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 485 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 3c9a6f7dcdc..b589a354c06 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
@@ -83,11 +83,12 @@ handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa) | |||
83 | * the kernel can handle, and then we build all the user-level signal handling | 83 | * the kernel can handle, and then we build all the user-level signal handling |
84 | * stack-frames in one go after that. | 84 | * stack-frames in one go after that. |
85 | */ | 85 | */ |
86 | static int do_signal(struct pt_regs *regs, sigset_t *oldset) | 86 | static void do_signal(struct pt_regs *regs) |
87 | { | 87 | { |
88 | siginfo_t info; | 88 | siginfo_t info; |
89 | int signr; | 89 | int signr; |
90 | struct k_sigaction ka; | 90 | struct k_sigaction ka; |
91 | sigset_t *oldset; | ||
91 | 92 | ||
92 | /* | 93 | /* |
93 | * We want the common case to go fast, which | 94 | * We want the common case to go fast, which |
@@ -96,11 +97,11 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
96 | * if so. | 97 | * if so. |
97 | */ | 98 | */ |
98 | if (!user_mode(regs)) | 99 | if (!user_mode(regs)) |
99 | return 1; | 100 | return; |
100 | 101 | ||
101 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) | 102 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) |
102 | oldset = ¤t->saved_sigmask; | 103 | oldset = ¤t->saved_sigmask; |
103 | else if (!oldset) | 104 | else |
104 | oldset = ¤t->blocked; | 105 | oldset = ¤t->blocked; |
105 | 106 | ||
106 | signr = get_signal_to_deliver(&info, &ka, regs, 0); | 107 | signr = get_signal_to_deliver(&info, &ka, regs, 0); |
@@ -118,7 +119,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
118 | 119 | ||
119 | tracehook_signal_handler(signr, &info, &ka, regs, | 120 | tracehook_signal_handler(signr, &info, &ka, regs, |
120 | test_thread_flag(TIF_SINGLESTEP)); | 121 | test_thread_flag(TIF_SINGLESTEP)); |
121 | return 1; | 122 | return; |
122 | } | 123 | } |
123 | } | 124 | } |
124 | 125 | ||
@@ -147,71 +148,18 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
147 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 148 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
148 | } | 149 | } |
149 | 150 | ||
150 | return 0; | 151 | return; |
151 | } | 152 | } |
152 | 153 | ||
153 | /* | 154 | /* |
154 | * Atomically swap in the new signal mask, and wait for a signal. | 155 | * Atomically swap in the new signal mask, and wait for a signal. |
155 | */ | 156 | */ |
156 | asmlinkage int | 157 | asmlinkage int |
157 | sys_sigsuspend(old_sigset_t mask, | 158 | sys_sigsuspend(old_sigset_t mask) |
158 | unsigned long r3, unsigned long r4, unsigned long r5, | ||
159 | unsigned long r6, unsigned long r7, | ||
160 | struct pt_regs * regs) | ||
161 | { | 159 | { |
162 | sigset_t saveset, blocked; | 160 | sigset_t blocked; |
163 | |||
164 | saveset = current->blocked; | ||
165 | |||
166 | mask &= _BLOCKABLE; | ||
167 | siginitset(&blocked, mask); | 161 | siginitset(&blocked, mask); |
168 | set_current_blocked(&blocked); | 162 | return sigsuspend(&blocked); |
169 | |||
170 | REF_REG_RET = -EINTR; | ||
171 | while (1) { | ||
172 | current->state = TASK_INTERRUPTIBLE; | ||
173 | schedule(); | ||
174 | set_restore_sigmask(); | ||
175 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ | ||
176 | if (do_signal(regs, &saveset)) { | ||
177 | /* pc now points at signal handler. Need to decrement | ||
178 | it because entry.S will increment it. */ | ||
179 | regs->pc -= 4; | ||
180 | return -EINTR; | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | asmlinkage int | ||
186 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, | ||
187 | unsigned long r4, unsigned long r5, unsigned long r6, | ||
188 | unsigned long r7, | ||
189 | struct pt_regs * regs) | ||
190 | { | ||
191 | sigset_t saveset, newset; | ||
192 | |||
193 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
194 | if (sigsetsize != sizeof(sigset_t)) | ||
195 | return -EINVAL; | ||
196 | |||
197 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
198 | return -EFAULT; | ||
199 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
200 | saveset = current->blocked; | ||
201 | set_current_blocked(&newset); | ||
202 | |||
203 | REF_REG_RET = -EINTR; | ||
204 | while (1) { | ||
205 | current->state = TASK_INTERRUPTIBLE; | ||
206 | schedule(); | ||
207 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ | ||
208 | if (do_signal(regs, &saveset)) { | ||
209 | /* pc now points at signal handler. Need to decrement | ||
210 | it because entry.S will increment it. */ | ||
211 | regs->pc -= 4; | ||
212 | return -EINTR; | ||
213 | } | ||
214 | } | ||
215 | } | 163 | } |
216 | 164 | ||
217 | asmlinkage int | 165 | asmlinkage int |
@@ -225,10 +173,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
225 | old_sigset_t mask; | 173 | old_sigset_t mask; |
226 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 174 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
227 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 175 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
228 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 176 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || |
177 | __get_user(new_ka.sa.sa_flags, &act->sa_flags) || | ||
178 | __get_user(mask, &act->sa_mask)) | ||
229 | return -EFAULT; | 179 | return -EFAULT; |
230 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
231 | __get_user(mask, &act->sa_mask); | ||
232 | siginitset(&new_ka.sa.sa_mask, mask); | 180 | siginitset(&new_ka.sa.sa_mask, mask); |
233 | } | 181 | } |
234 | 182 | ||
@@ -237,10 +185,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
237 | if (!ret && oact) { | 185 | if (!ret && oact) { |
238 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 186 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
239 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 187 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
240 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 188 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || |
189 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || | ||
190 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) | ||
241 | return -EFAULT; | 191 | return -EFAULT; |
242 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
243 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
244 | } | 192 | } |
245 | 193 | ||
246 | return ret; | 194 | return ret; |
@@ -732,7 +680,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
732 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) | 680 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) |
733 | { | 681 | { |
734 | if (thread_info_flags & _TIF_SIGPENDING) | 682 | if (thread_info_flags & _TIF_SIGPENDING) |
735 | do_signal(regs, 0); | 683 | do_signal(regs); |
736 | 684 | ||
737 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 685 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
738 | clear_thread_flag(TIF_NOTIFY_RESUME); | 686 | clear_thread_flag(TIF_NOTIFY_RESUME); |