aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/compat_signal.c12
-rw-r--r--arch/s390/kernel/ptrace.c25
-rw-r--r--arch/s390/kernel/signal.c14
3 files changed, 28 insertions, 23 deletions
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index fd83b69207f5..a1dc6457016c 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -302,7 +302,8 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
302 302
303 regs32.psw.mask = psw32_user_bits | 303 regs32.psw.mask = psw32_user_bits |
304 ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER); 304 ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER);
305 regs32.psw.addr = PSW32_ADDR_AMODE | (__u32) regs->psw.addr; 305 regs32.psw.addr = (__u32) regs->psw.addr |
306 (__u32)(regs->psw.mask & PSW_MASK_BA);
306 for (i = 0; i < NUM_GPRS; i++) 307 for (i = 0; i < NUM_GPRS; i++)
307 regs32.gprs[i] = (__u32) regs->gprs[i]; 308 regs32.gprs[i] = (__u32) regs->gprs[i];
308 save_access_regs(current->thread.acrs); 309 save_access_regs(current->thread.acrs);
@@ -328,7 +329,8 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
328 if (err) 329 if (err)
329 return err; 330 return err;
330 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 331 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
331 (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32; 332 (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
333 (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
332 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN); 334 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
333 for (i = 0; i < NUM_GPRS; i++) 335 for (i = 0; i < NUM_GPRS; i++)
334 regs->gprs[i] = (__u64) regs32.gprs[i]; 336 regs->gprs[i] = (__u64) regs32.gprs[i];
@@ -496,9 +498,9 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
496 /* Set up to return from userspace. If provided, use a stub 498 /* Set up to return from userspace. If provided, use a stub
497 already in userspace. */ 499 already in userspace. */
498 if (ka->sa.sa_flags & SA_RESTORER) { 500 if (ka->sa.sa_flags & SA_RESTORER) {
499 regs->gprs[14] = (__u64) ka->sa.sa_restorer; 501 regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
500 } else { 502 } else {
501 regs->gprs[14] = (__u64) frame->retcode; 503 regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
502 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, 504 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
503 (u16 __user *)(frame->retcode))) 505 (u16 __user *)(frame->retcode)))
504 goto give_sigsegv; 506 goto give_sigsegv;
@@ -510,6 +512,7 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
510 512
511 /* Set up registers for signal handler */ 513 /* Set up registers for signal handler */
512 regs->gprs[15] = (__u64) frame; 514 regs->gprs[15] = (__u64) frame;
515 regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */
513 regs->psw.addr = (__u64) ka->sa.sa_handler; 516 regs->psw.addr = (__u64) ka->sa.sa_handler;
514 517
515 regs->gprs[2] = map_signal(sig); 518 regs->gprs[2] = map_signal(sig);
@@ -573,6 +576,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
573 576
574 /* Set up registers for signal handler */ 577 /* Set up registers for signal handler */
575 regs->gprs[15] = (__u64) frame; 578 regs->gprs[15] = (__u64) frame;
579 regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */
576 regs->psw.addr = (__u64) ka->sa.sa_handler; 580 regs->psw.addr = (__u64) ka->sa.sa_handler;
577 581
578 regs->gprs[2] = map_signal(sig); 582 regs->gprs[2] = map_signal(sig);
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 41e20763886e..450931a45b68 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -170,8 +170,7 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr)
170 tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); 170 tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr);
171 if (addr == (addr_t) &dummy->regs.psw.mask) 171 if (addr == (addr_t) &dummy->regs.psw.mask)
172 /* Return a clean psw mask. */ 172 /* Return a clean psw mask. */
173 tmp = psw_user_bits | (tmp & PSW_MASK_USER) | 173 tmp = psw_user_bits | (tmp & PSW_MASK_USER);
174 PSW_MASK_EA | PSW_MASK_BA;
175 174
176 } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { 175 } else if (addr < (addr_t) &dummy->regs.orig_gpr2) {
177 /* 176 /*
@@ -286,26 +285,17 @@ static inline void __poke_user_per(struct task_struct *child,
286static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) 285static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
287{ 286{
288 struct user *dummy = NULL; 287 struct user *dummy = NULL;
289 addr_t offset, tmp; 288 addr_t offset;
290 289
291 if (addr < (addr_t) &dummy->regs.acrs) { 290 if (addr < (addr_t) &dummy->regs.acrs) {
292 /* 291 /*
293 * psw and gprs are stored on the stack 292 * psw and gprs are stored on the stack
294 */ 293 */
295 tmp = (data & ~PSW_MASK_USER) ^ psw_user_bits;
296 if (addr == (addr_t) &dummy->regs.psw.mask && 294 if (addr == (addr_t) &dummy->regs.psw.mask &&
297#ifdef CONFIG_COMPAT 295 ((data & ~PSW_MASK_USER) != psw_user_bits ||
298 tmp != PSW_MASK_BA && 296 ((data & PSW_MASK_EA) && !(data & PSW_MASK_BA))))
299#endif
300 tmp != (PSW_MASK_EA | PSW_MASK_BA))
301 /* Invalid psw mask. */ 297 /* Invalid psw mask. */
302 return -EINVAL; 298 return -EINVAL;
303#ifndef CONFIG_64BIT
304 if (addr == (addr_t) &dummy->regs.psw.addr)
305 /* I'd like to reject addresses without the
306 high order bit but older gdb's rely on it */
307 data |= PSW_ADDR_AMODE;
308#endif
309 if (addr == (addr_t) &dummy->regs.psw.addr) 299 if (addr == (addr_t) &dummy->regs.psw.addr)
310 /* 300 /*
311 * The debugger changed the instruction address, 301 * The debugger changed the instruction address,
@@ -517,7 +507,8 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
517 tmp = psw32_user_bits | (tmp & PSW32_MASK_USER); 507 tmp = psw32_user_bits | (tmp & PSW32_MASK_USER);
518 } else if (addr == (addr_t) &dummy32->regs.psw.addr) { 508 } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
519 /* Fake a 31 bit psw address. */ 509 /* Fake a 31 bit psw address. */
520 tmp = (__u32) regs->psw.addr | PSW32_ADDR_AMODE; 510 tmp = (__u32) regs->psw.addr |
511 (__u32)(regs->psw.mask & PSW_MASK_BA);
521 } else { 512 } else {
522 /* gpr 0-15 */ 513 /* gpr 0-15 */
523 tmp = *(__u32 *)((addr_t) &regs->psw + addr*2 + 4); 514 tmp = *(__u32 *)((addr_t) &regs->psw + addr*2 + 4);
@@ -615,10 +606,14 @@ static int __poke_user_compat(struct task_struct *child,
615 /* Invalid psw mask. */ 606 /* Invalid psw mask. */
616 return -EINVAL; 607 return -EINVAL;
617 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 608 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
609 (regs->psw.mask & PSW_MASK_BA) |
618 (__u64)(tmp & PSW32_MASK_USER) << 32; 610 (__u64)(tmp & PSW32_MASK_USER) << 32;
619 } else if (addr == (addr_t) &dummy32->regs.psw.addr) { 611 } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
620 /* Build a 64 bit psw address from 31 bit address. */ 612 /* Build a 64 bit psw address from 31 bit address. */
621 regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN; 613 regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN;
614 /* Transfer 31 bit amode bit to psw mask. */
615 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_BA) |
616 (__u64)(tmp & PSW32_ADDR_AMODE);
622 /* 617 /*
623 * The debugger changed the instruction address, 618 * The debugger changed the instruction address,
624 * reset system call restart, see signal.c:do_signal 619 * reset system call restart, see signal.c:do_signal
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index c19755815e53..05a85bc14c98 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -117,8 +117,8 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
117 117
118 /* Copy a 'clean' PSW mask to the user to avoid leaking 118 /* Copy a 'clean' PSW mask to the user to avoid leaking
119 information about whether PER is currently on. */ 119 information about whether PER is currently on. */
120 user_sregs.regs.psw.mask = psw_user_bits | PSW_MASK_EA | PSW_MASK_BA | 120 user_sregs.regs.psw.mask = psw_user_bits |
121 (regs->psw.mask & PSW_MASK_USER); 121 (regs->psw.mask & PSW_MASK_USER);
122 user_sregs.regs.psw.addr = regs->psw.addr; 122 user_sregs.regs.psw.addr = regs->psw.addr;
123 memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs)); 123 memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
124 memcpy(&user_sregs.regs.acrs, current->thread.acrs, 124 memcpy(&user_sregs.regs.acrs, current->thread.acrs,
@@ -145,9 +145,13 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
145 err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs)); 145 err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs));
146 if (err) 146 if (err)
147 return err; 147 return err;
148 /* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */
148 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 149 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
149 (user_sregs.regs.psw.mask & PSW_MASK_USER); 150 (user_sregs.regs.psw.mask & PSW_MASK_USER);
150 regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr; 151 /* Check for invalid amode */
152 if (regs->psw.mask & PSW_MASK_EA)
153 regs->psw.mask |= PSW_MASK_BA;
154 regs->psw.addr = user_sregs.regs.psw.addr;
151 memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); 155 memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
152 memcpy(&current->thread.acrs, &user_sregs.regs.acrs, 156 memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
153 sizeof(sregs->regs.acrs)); 157 sizeof(sregs->regs.acrs));
@@ -290,6 +294,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
290 294
291 /* Set up registers for signal handler */ 295 /* Set up registers for signal handler */
292 regs->gprs[15] = (unsigned long) frame; 296 regs->gprs[15] = (unsigned long) frame;
297 regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */
293 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; 298 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
294 299
295 regs->gprs[2] = map_signal(sig); 300 regs->gprs[2] = map_signal(sig);
@@ -358,6 +363,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
358 363
359 /* Set up registers for signal handler */ 364 /* Set up registers for signal handler */
360 regs->gprs[15] = (unsigned long) frame; 365 regs->gprs[15] = (unsigned long) frame;
366 regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */
361 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; 367 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
362 368
363 regs->gprs[2] = map_signal(sig); 369 regs->gprs[2] = map_signal(sig);