diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2018-04-16 14:55:06 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2018-09-27 15:57:52 -0400 |
commit | 8b9c6b28312cc51a87055e292b11c5aa28f0c935 (patch) | |
tree | 72d2fb5a392dd97c11799884f8982ba44943588d | |
parent | 795a83714526754a2b8089a0533bfef24287bcb9 (diff) |
signal/ia64: Use the generic force_sigsegv in setup_frame
The ia64 handling of failure to setup a signal frame has been trying
to set overlapping fields in struct siginfo since 2.3.43. The si_pid
and si_uid fields are stomped when the si_addr field is set. The
si_code of SI_KERNEL indicates that si_pid and si_uid should be valid,
and that si_addr does not exist.
Being at odds with the definition of SI_KERNEL and with nothing to
indicate that this was a signal frame setup failure there is no way
for userspace to know that si_addr was filled out instead.
In practice failure to setup a signal frame is rare, and si_pid and
si_uid are always set to 0 when si_code is SI_KERNEL so I expect no
one has looked closely enough before to see this weirdness. Further
the only difference between force_sigsegv_info and the generic
force_sigsegv other than the return code is that force_sigsegv_info
stomps the si_uid and si_pid fields.
Remove the bug and simplify the code by using force_sigsegv in this
case just like other architectures.
Fixes: 2.3.43
Cc: Tony Luck <tony.luck@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: linux-ia64@vger.kernel.org
Acked-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | arch/ia64/kernel/signal.c | 50 |
1 files changed, 12 insertions, 38 deletions
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index d1234a5ba4c5..01fc133b2e4c 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c | |||
@@ -232,37 +232,6 @@ rbs_on_sig_stack (unsigned long bsp) | |||
232 | } | 232 | } |
233 | 233 | ||
234 | static long | 234 | static long |
235 | force_sigsegv_info (int sig, void __user *addr) | ||
236 | { | ||
237 | unsigned long flags; | ||
238 | struct siginfo si; | ||
239 | |||
240 | clear_siginfo(&si); | ||
241 | if (sig == SIGSEGV) { | ||
242 | /* | ||
243 | * Acquiring siglock around the sa_handler-update is almost | ||
244 | * certainly overkill, but this isn't a | ||
245 | * performance-critical path and I'd rather play it safe | ||
246 | * here than having to debug a nasty race if and when | ||
247 | * something changes in kernel/signal.c that would make it | ||
248 | * no longer safe to modify sa_handler without holding the | ||
249 | * lock. | ||
250 | */ | ||
251 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
252 | current->sighand->action[sig - 1].sa.sa_handler = SIG_DFL; | ||
253 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
254 | } | ||
255 | si.si_signo = SIGSEGV; | ||
256 | si.si_errno = 0; | ||
257 | si.si_code = SI_KERNEL; | ||
258 | si.si_pid = task_pid_vnr(current); | ||
259 | si.si_uid = from_kuid_munged(current_user_ns(), current_uid()); | ||
260 | si.si_addr = addr; | ||
261 | force_sig_info(SIGSEGV, &si, current); | ||
262 | return 1; | ||
263 | } | ||
264 | |||
265 | static long | ||
266 | setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr) | 235 | setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr) |
267 | { | 236 | { |
268 | extern char __kernel_sigtramp[]; | 237 | extern char __kernel_sigtramp[]; |
@@ -295,15 +264,18 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr) | |||
295 | * instead so we will die with SIGSEGV. | 264 | * instead so we will die with SIGSEGV. |
296 | */ | 265 | */ |
297 | check_sp = (new_sp - sizeof(*frame)) & -STACK_ALIGN; | 266 | check_sp = (new_sp - sizeof(*frame)) & -STACK_ALIGN; |
298 | if (!likely(on_sig_stack(check_sp))) | 267 | if (!likely(on_sig_stack(check_sp))) { |
299 | return force_sigsegv_info(ksig->sig, (void __user *) | 268 | force_sigsegv(ksig->sig, current); |
300 | check_sp); | 269 | return 1; |
270 | } | ||
301 | } | 271 | } |
302 | } | 272 | } |
303 | frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN); | 273 | frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN); |
304 | 274 | ||
305 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 275 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) { |
306 | return force_sigsegv_info(ksig->sig, frame); | 276 | force_sigsegv(ksig->sig, current); |
277 | return 1; | ||
278 | } | ||
307 | 279 | ||
308 | err = __put_user(ksig->sig, &frame->arg0); | 280 | err = __put_user(ksig->sig, &frame->arg0); |
309 | err |= __put_user(&frame->info, &frame->arg1); | 281 | err |= __put_user(&frame->info, &frame->arg1); |
@@ -317,8 +289,10 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr) | |||
317 | err |= __save_altstack(&frame->sc.sc_stack, scr->pt.r12); | 289 | err |= __save_altstack(&frame->sc.sc_stack, scr->pt.r12); |
318 | err |= setup_sigcontext(&frame->sc, set, scr); | 290 | err |= setup_sigcontext(&frame->sc, set, scr); |
319 | 291 | ||
320 | if (unlikely(err)) | 292 | if (unlikely(err)) { |
321 | return force_sigsegv_info(ksig->sig, frame); | 293 | force_sigsegv(ksig->sig, current); |
294 | return 1; | ||
295 | } | ||
322 | 296 | ||
323 | scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */ | 297 | scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */ |
324 | scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ | 298 | scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ |