diff options
Diffstat (limited to 'arch/um/sys-x86_64')
-rw-r--r-- | arch/um/sys-x86_64/signal.c | 56 |
1 files changed, 41 insertions, 15 deletions
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index fe1d065332b1..e75c4e1838b0 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c | |||
@@ -55,7 +55,8 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, | |||
55 | } | 55 | } |
56 | 56 | ||
57 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | 57 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, |
58 | struct pt_regs *regs, unsigned long mask) | 58 | struct pt_regs *regs, unsigned long mask, |
59 | unsigned long sp) | ||
59 | { | 60 | { |
60 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; | 61 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; |
61 | int err = 0; | 62 | int err = 0; |
@@ -70,7 +71,11 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
70 | err |= PUTREG(regs, RDI, to, rdi); | 71 | err |= PUTREG(regs, RDI, to, rdi); |
71 | err |= PUTREG(regs, RSI, to, rsi); | 72 | err |= PUTREG(regs, RSI, to, rsi); |
72 | err |= PUTREG(regs, RBP, to, rbp); | 73 | err |= PUTREG(regs, RBP, to, rbp); |
73 | err |= PUTREG(regs, RSP, to, rsp); | 74 | /* Must use orignal RSP, which is passed in, rather than what's in |
75 | * the pt_regs, because that's already been updated to point at the | ||
76 | * signal frame. | ||
77 | */ | ||
78 | err |= __put_user(sp, &to->rsp); | ||
74 | err |= PUTREG(regs, RBX, to, rbx); | 79 | err |= PUTREG(regs, RBX, to, rbx); |
75 | err |= PUTREG(regs, RDX, to, rdx); | 80 | err |= PUTREG(regs, RDX, to, rdx); |
76 | err |= PUTREG(regs, RCX, to, rcx); | 81 | err |= PUTREG(regs, RCX, to, rcx); |
@@ -102,7 +107,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
102 | 107 | ||
103 | #ifdef CONFIG_MODE_TT | 108 | #ifdef CONFIG_MODE_TT |
104 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | 109 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, |
105 | int fpsize) | 110 | int fpsize) |
106 | { | 111 | { |
107 | struct _fpstate *to_fp, *from_fp; | 112 | struct _fpstate *to_fp, *from_fp; |
108 | unsigned long sigs; | 113 | unsigned long sigs; |
@@ -120,7 +125,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | |||
120 | } | 125 | } |
121 | 126 | ||
122 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | 127 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, |
123 | struct sigcontext *from, int fpsize) | 128 | struct sigcontext *from, int fpsize, unsigned long sp) |
124 | { | 129 | { |
125 | struct _fpstate *to_fp, *from_fp; | 130 | struct _fpstate *to_fp, *from_fp; |
126 | int err; | 131 | int err; |
@@ -128,11 +133,17 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | |||
128 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); | 133 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); |
129 | from_fp = from->fpstate; | 134 | from_fp = from->fpstate; |
130 | err = copy_to_user(to, from, sizeof(*to)); | 135 | err = copy_to_user(to, from, sizeof(*to)); |
136 | /* The SP in the sigcontext is the updated one for the signal | ||
137 | * delivery. The sp passed in is the original, and this needs | ||
138 | * to be restored, so we stick it in separately. | ||
139 | */ | ||
140 | err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); | ||
141 | |||
131 | if(from_fp != NULL){ | 142 | if(from_fp != NULL){ |
132 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | 143 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); |
133 | err |= copy_to_user(to_fp, from_fp, fpsize); | 144 | err |= copy_to_user(to_fp, from_fp, fpsize); |
134 | } | 145 | } |
135 | return(err); | 146 | return err; |
136 | } | 147 | } |
137 | 148 | ||
138 | #endif | 149 | #endif |
@@ -148,11 +159,12 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) | |||
148 | } | 159 | } |
149 | 160 | ||
150 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, | 161 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, |
151 | struct pt_regs *from, unsigned long mask) | 162 | struct pt_regs *from, unsigned long mask, |
163 | unsigned long sp) | ||
152 | { | 164 | { |
153 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), | 165 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), |
154 | sizeof(*fp)), | 166 | sizeof(*fp), sp), |
155 | copy_sc_to_user_skas(to, fp, from, mask))); | 167 | copy_sc_to_user_skas(to, fp, from, mask, sp))); |
156 | } | 168 | } |
157 | 169 | ||
158 | struct rt_sigframe | 170 | struct rt_sigframe |
@@ -170,6 +182,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
170 | { | 182 | { |
171 | struct rt_sigframe __user *frame; | 183 | struct rt_sigframe __user *frame; |
172 | struct _fpstate __user *fp = NULL; | 184 | struct _fpstate __user *fp = NULL; |
185 | unsigned long save_sp = PT_REGS_RSP(regs); | ||
173 | int err = 0; | 186 | int err = 0; |
174 | struct task_struct *me = current; | 187 | struct task_struct *me = current; |
175 | 188 | ||
@@ -193,14 +206,25 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
193 | goto out; | 206 | goto out; |
194 | } | 207 | } |
195 | 208 | ||
209 | /* Update SP now because the page fault handler refuses to extend | ||
210 | * the stack if the faulting address is too far below the current | ||
211 | * SP, which frame now certainly is. If there's an error, the original | ||
212 | * value is restored on the way out. | ||
213 | * When writing the sigcontext to the stack, we have to write the | ||
214 | * original value, so that's passed to copy_sc_to_user, which does | ||
215 | * the right thing with it. | ||
216 | */ | ||
217 | PT_REGS_RSP(regs) = (unsigned long) frame; | ||
218 | |||
196 | /* Create the ucontext. */ | 219 | /* Create the ucontext. */ |
197 | err |= __put_user(0, &frame->uc.uc_flags); | 220 | err |= __put_user(0, &frame->uc.uc_flags); |
198 | err |= __put_user(0, &frame->uc.uc_link); | 221 | err |= __put_user(0, &frame->uc.uc_link); |
199 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 222 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
200 | err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), | 223 | err |= __put_user(sas_ss_flags(save_sp), |
201 | &frame->uc.uc_stack.ss_flags); | 224 | &frame->uc.uc_stack.ss_flags); |
202 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | 225 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); |
203 | err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); | 226 | err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0], |
227 | save_sp); | ||
204 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); | 228 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); |
205 | if (sizeof(*set) == 16) { | 229 | if (sizeof(*set) == 16) { |
206 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); | 230 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); |
@@ -217,10 +241,10 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
217 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 241 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
218 | else | 242 | else |
219 | /* could use a vstub here */ | 243 | /* could use a vstub here */ |
220 | goto out; | 244 | goto restore_sp; |
221 | 245 | ||
222 | if (err) | 246 | if (err) |
223 | goto out; | 247 | goto restore_sp; |
224 | 248 | ||
225 | /* Set up registers for signal handler */ | 249 | /* Set up registers for signal handler */ |
226 | { | 250 | { |
@@ -238,10 +262,12 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
238 | PT_REGS_RSI(regs) = (unsigned long) &frame->info; | 262 | PT_REGS_RSI(regs) = (unsigned long) &frame->info; |
239 | PT_REGS_RDX(regs) = (unsigned long) &frame->uc; | 263 | PT_REGS_RDX(regs) = (unsigned long) &frame->uc; |
240 | PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; | 264 | PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; |
241 | |||
242 | PT_REGS_RSP(regs) = (unsigned long) frame; | ||
243 | out: | 265 | out: |
244 | return(err); | 266 | return err; |
267 | |||
268 | restore_sp: | ||
269 | PT_REGS_RSP(regs) = save_sp; | ||
270 | return err; | ||
245 | } | 271 | } |
246 | 272 | ||
247 | long sys_rt_sigreturn(struct pt_regs *regs) | 273 | long sys_rt_sigreturn(struct pt_regs *regs) |