diff options
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/compat_signal.c | 12 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 25 | ||||
-rw-r--r-- | arch/s390/kernel/signal.c | 14 |
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, | |||
286 | static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | 285 | static 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) ®s->psw + addr*2 + 4); | 514 | tmp = *(__u32 *)((addr_t) ®s->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, ®s->gprs, sizeof(sregs->regs.gprs)); | 123 | memcpy(&user_sregs.regs.gprs, ®s->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(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); | 155 | memcpy(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); |
152 | memcpy(¤t->thread.acrs, &user_sregs.regs.acrs, | 156 | memcpy(¤t->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); |