aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Martin <Dave.Martin@arm.com>2017-06-15 10:03:38 -0400
committerWill Deacon <will.deacon@arm.com>2017-06-20 07:42:58 -0400
commit20987de3c2c45c314e0386f724aa85f55d984ef2 (patch)
treee4239945bd5c53c4d7d7865e76d7683858bda8ff
parent8f36094802e4e6de180b36bcac4cfd9d319e1b64 (diff)
arm64: signal: split frame link record from sigcontext structure
In order to be able to increase the amount of the data currently written to the __reserved[] array in the signal frame, it is necessary to overwrite the locations currently occupied by the {fp,lr} frame link record pushed at the top of the signal stack. In order for this to work, this patch detaches the frame link record from struct rt_sigframe and places it separately at the top of the signal stack. This will allow subsequent patches to insert data between it and __reserved[]. This change relies on the non-ABI status of the placement of the frame record with respect to struct sigframe: this status is undocumented, but the placement is not declared or described in the user headers, and known unwinder implementations (libgcc, libunwind, gdb) appear not to rely on it. Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Dave Martin <Dave.Martin@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/kernel/signal.c50
1 files changed, 32 insertions, 18 deletions
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index c7b6de62f9d3..1e5ed3be78ed 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -19,6 +19,7 @@
19 19
20#include <linux/compat.h> 20#include <linux/compat.h>
21#include <linux/errno.h> 21#include <linux/errno.h>
22#include <linux/kernel.h>
22#include <linux/signal.h> 23#include <linux/signal.h>
23#include <linux/personality.h> 24#include <linux/personality.h>
24#include <linux/freezer.h> 25#include <linux/freezer.h>
@@ -41,10 +42,18 @@
41struct rt_sigframe { 42struct rt_sigframe {
42 struct siginfo info; 43 struct siginfo info;
43 struct ucontext uc; 44 struct ucontext uc;
45};
46
47struct frame_record {
44 u64 fp; 48 u64 fp;
45 u64 lr; 49 u64 lr;
46}; 50};
47 51
52struct rt_sigframe_user_layout {
53 struct rt_sigframe __user *sigframe;
54 struct frame_record __user *next_frame;
55};
56
48static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) 57static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
49{ 58{
50 struct fpsimd_state *fpsimd = &current->thread.fpsimd_state; 59 struct fpsimd_state *fpsimd = &current->thread.fpsimd_state;
@@ -162,16 +171,17 @@ badframe:
162 return 0; 171 return 0;
163} 172}
164 173
165static int setup_sigframe(struct rt_sigframe __user *sf, 174static int setup_sigframe(struct rt_sigframe_user_layout *user,
166 struct pt_regs *regs, sigset_t *set) 175 struct pt_regs *regs, sigset_t *set)
167{ 176{
168 int i, err = 0; 177 int i, err = 0;
178 struct rt_sigframe __user *sf = user->sigframe;
169 void *aux = sf->uc.uc_mcontext.__reserved; 179 void *aux = sf->uc.uc_mcontext.__reserved;
170 struct _aarch64_ctx *end; 180 struct _aarch64_ctx *end;
171 181
172 /* set up the stack frame for unwinding */ 182 /* set up the stack frame for unwinding */
173 __put_user_error(regs->regs[29], &sf->fp, err); 183 __put_user_error(regs->regs[29], &user->next_frame->fp, err);
174 __put_user_error(regs->regs[30], &sf->lr, err); 184 __put_user_error(regs->regs[30], &user->next_frame->lr, err);
175 185
176 for (i = 0; i < 31; i++) 186 for (i = 0; i < 31; i++)
177 __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], 187 __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
@@ -209,34 +219,36 @@ static int setup_sigframe(struct rt_sigframe __user *sf,
209 return err; 219 return err;
210} 220}
211 221
212static struct rt_sigframe __user *get_sigframe(struct ksignal *ksig, 222static int get_sigframe(struct rt_sigframe_user_layout *user,
213 struct pt_regs *regs) 223 struct ksignal *ksig, struct pt_regs *regs)
214{ 224{
215 unsigned long sp, sp_top; 225 unsigned long sp, sp_top;
216 struct rt_sigframe __user *frame;
217 226
218 sp = sp_top = sigsp(regs->sp, ksig); 227 sp = sp_top = sigsp(regs->sp, ksig);
219 228
220 sp = (sp - sizeof(struct rt_sigframe)) & ~15; 229 sp = round_down(sp - sizeof(struct frame_record), 16);
221 frame = (struct rt_sigframe __user *)sp; 230 user->next_frame = (struct frame_record __user *)sp;
231
232 sp = round_down(sp - sizeof(struct rt_sigframe), 16);
233 user->sigframe = (struct rt_sigframe __user *)sp;
222 234
223 /* 235 /*
224 * Check that we can actually write to the signal frame. 236 * Check that we can actually write to the signal frame.
225 */ 237 */
226 if (!access_ok(VERIFY_WRITE, frame, sp_top - sp)) 238 if (!access_ok(VERIFY_WRITE, user->sigframe, sp_top - sp))
227 frame = NULL; 239 return -EFAULT;
228 240
229 return frame; 241 return 0;
230} 242}
231 243
232static void setup_return(struct pt_regs *regs, struct k_sigaction *ka, 244static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
233 void __user *frame, int usig) 245 struct rt_sigframe_user_layout *user, int usig)
234{ 246{
235 __sigrestore_t sigtramp; 247 __sigrestore_t sigtramp;
236 248
237 regs->regs[0] = usig; 249 regs->regs[0] = usig;
238 regs->sp = (unsigned long)frame; 250 regs->sp = (unsigned long)user->sigframe;
239 regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp); 251 regs->regs[29] = (unsigned long)&user->next_frame->fp;
240 regs->pc = (unsigned long)ka->sa.sa_handler; 252 regs->pc = (unsigned long)ka->sa.sa_handler;
241 253
242 if (ka->sa.sa_flags & SA_RESTORER) 254 if (ka->sa.sa_flags & SA_RESTORER)
@@ -250,20 +262,22 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
250static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, 262static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
251 struct pt_regs *regs) 263 struct pt_regs *regs)
252{ 264{
265 struct rt_sigframe_user_layout user;
253 struct rt_sigframe __user *frame; 266 struct rt_sigframe __user *frame;
254 int err = 0; 267 int err = 0;
255 268
256 frame = get_sigframe(ksig, regs); 269 if (get_sigframe(&user, ksig, regs))
257 if (!frame)
258 return 1; 270 return 1;
259 271
272 frame = user.sigframe;
273
260 __put_user_error(0, &frame->uc.uc_flags, err); 274 __put_user_error(0, &frame->uc.uc_flags, err);
261 __put_user_error(NULL, &frame->uc.uc_link, err); 275 __put_user_error(NULL, &frame->uc.uc_link, err);
262 276
263 err |= __save_altstack(&frame->uc.uc_stack, regs->sp); 277 err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
264 err |= setup_sigframe(frame, regs, set); 278 err |= setup_sigframe(&user, regs, set);
265 if (err == 0) { 279 if (err == 0) {
266 setup_return(regs, &ksig->ka, frame, usig); 280 setup_return(regs, &ksig->ka, &user, usig);
267 if (ksig->ka.sa.sa_flags & SA_SIGINFO) { 281 if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
268 err |= copy_siginfo_to_user(&frame->info, &ksig->info); 282 err |= copy_siginfo_to_user(&frame->info, &ksig->info);
269 regs->regs[1] = (unsigned long)&frame->info; 283 regs->regs[1] = (unsigned long)&frame->info;