aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-11-23 07:34:13 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2012-11-23 13:09:19 -0500
commit304ef4e8367244b547734143c792a2ab764831e8 (patch)
treebcc73b221daac07e8cea238cbea2344edb778aa0 /arch/arm64
parent0f07dfee2776a875613e2eeef25408d350322b71 (diff)
arm64: signal: push the unwinding prologue on the signal stack
To allow debuggers to unwind through signal frames, we create a fake stack unwinding prologue containing the link register and frame pointer of the interrupted context. The signal frame is then offset by 16 bytes to make room for the two saved registers which are pushed onto the frame of the *interrupted* context, rather than placed directly above the signal stack. This doesn't work when an alternative signal stack is set up for a SEGV handler, which is raised in response to RLIMIT_STACK being reached. In this case, we try to push the unwinding prologue onto the full stack and subsequently take a fault which we fail to resolve, causing setup_return to return -EFAULT and handle_signal to force_sigsegv on the current task. This patch fixes the problem by including the unwinding prologue as part of the rt_sigframe definition, which is populated during setup_sigframe, ensuring that it always ends up on the signal stack. Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Cc: <stable@vger.kernel.org>
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/kernel/signal.c37
1 files changed, 16 insertions, 21 deletions
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 8807ba2cf262..051bb523ba2c 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -41,6 +41,8 @@
41struct rt_sigframe { 41struct rt_sigframe {
42 struct siginfo info; 42 struct siginfo info;
43 struct ucontext uc; 43 struct ucontext uc;
44 u64 fp;
45 u64 lr;
44}; 46};
45 47
46static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) 48static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
@@ -175,6 +177,10 @@ static int setup_sigframe(struct rt_sigframe __user *sf,
175 struct aux_context __user *aux = 177 struct aux_context __user *aux =
176 (struct aux_context __user *)sf->uc.uc_mcontext.__reserved; 178 (struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
177 179
180 /* set up the stack frame for unwinding */
181 __put_user_error(regs->regs[29], &sf->fp, err);
182 __put_user_error(regs->regs[30], &sf->lr, err);
183
178 for (i = 0; i < 31; i++) 184 for (i = 0; i < 31; i++)
179 __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], 185 __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
180 err); 186 err);
@@ -210,9 +216,6 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
210 if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) 216 if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
211 sp = sp_top = current->sas_ss_sp + current->sas_ss_size; 217 sp = sp_top = current->sas_ss_sp + current->sas_ss_size;
212 218
213 /* room for stack frame (FP, LR) */
214 sp -= 16;
215
216 sp = (sp - framesize) & ~15; 219 sp = (sp - framesize) & ~15;
217 frame = (void __user *)sp; 220 frame = (void __user *)sp;
218 221
@@ -225,20 +228,14 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
225 return frame; 228 return frame;
226} 229}
227 230
228static int setup_return(struct pt_regs *regs, struct k_sigaction *ka, 231static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
229 void __user *frame, int usig) 232 void __user *frame, int usig)
230{ 233{
231 int err = 0;
232 __sigrestore_t sigtramp; 234 __sigrestore_t sigtramp;
233 unsigned long __user *sp = (unsigned long __user *)regs->sp;
234
235 /* set up the stack frame */
236 __put_user_error(regs->regs[29], sp - 2, err);
237 __put_user_error(regs->regs[30], sp - 1, err);
238 235
239 regs->regs[0] = usig; 236 regs->regs[0] = usig;
240 regs->regs[29] = regs->sp - 16;
241 regs->sp = (unsigned long)frame; 237 regs->sp = (unsigned long)frame;
238 regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp);
242 regs->pc = (unsigned long)ka->sa.sa_handler; 239 regs->pc = (unsigned long)ka->sa.sa_handler;
243 240
244 if (ka->sa.sa_flags & SA_RESTORER) 241 if (ka->sa.sa_flags & SA_RESTORER)
@@ -247,8 +244,6 @@ static int setup_return(struct pt_regs *regs, struct k_sigaction *ka,
247 sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp); 244 sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
248 245
249 regs->regs[30] = (unsigned long)sigtramp; 246 regs->regs[30] = (unsigned long)sigtramp;
250
251 return err;
252} 247}
253 248
254static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, 249static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
@@ -272,13 +267,13 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
272 err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); 267 err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack));
273 268
274 err |= setup_sigframe(frame, regs, set); 269 err |= setup_sigframe(frame, regs, set);
275 if (err == 0) 270 if (err == 0) {
276 err = setup_return(regs, ka, frame, usig); 271 setup_return(regs, ka, frame, usig);
277 272 if (ka->sa.sa_flags & SA_SIGINFO) {
278 if (err == 0 && ka->sa.sa_flags & SA_SIGINFO) { 273 err |= copy_siginfo_to_user(&frame->info, info);
279 err |= copy_siginfo_to_user(&frame->info, info); 274 regs->regs[1] = (unsigned long)&frame->info;
280 regs->regs[1] = (unsigned long)&frame->info; 275 regs->regs[2] = (unsigned long)&frame->uc;
281 regs->regs[2] = (unsigned long)&frame->uc; 276 }
282 } 277 }
283 278
284 return err; 279 return err;