aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel/signal.c')
-rw-r--r--arch/arm64/kernel/signal.c49
1 files changed, 22 insertions, 27 deletions
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 8807ba2cf262..abd756315cb5 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);
@@ -196,11 +202,11 @@ static int setup_sigframe(struct rt_sigframe __user *sf,
196 return err; 202 return err;
197} 203}
198 204
199static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 205static struct rt_sigframe __user *get_sigframe(struct k_sigaction *ka,
200 int framesize) 206 struct pt_regs *regs)
201{ 207{
202 unsigned long sp, sp_top; 208 unsigned long sp, sp_top;
203 void __user *frame; 209 struct rt_sigframe __user *frame;
204 210
205 sp = sp_top = regs->sp; 211 sp = sp_top = regs->sp;
206 212
@@ -210,11 +216,8 @@ 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) */ 219 sp = (sp - sizeof(struct rt_sigframe)) & ~15;
214 sp -= 16; 220 frame = (struct rt_sigframe __user *)sp;
215
216 sp = (sp - framesize) & ~15;
217 frame = (void __user *)sp;
218 221
219 /* 222 /*
220 * Check that we can actually write to the signal frame. 223 * Check that we can actually write to the signal frame.
@@ -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,
@@ -258,7 +253,7 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
258 stack_t stack; 253 stack_t stack;
259 int err = 0; 254 int err = 0;
260 255
261 frame = get_sigframe(ka, regs, sizeof(*frame)); 256 frame = get_sigframe(ka, regs);
262 if (!frame) 257 if (!frame)
263 return 1; 258 return 1;
264 259
@@ -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;