Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 272070
b: refs/heads/master
c: d4e81b3
h: refs/heads/master
v: v3
  • Loading branch information
Martin Schwidefsky committed Oct 30, 2011
1 parent a8a5413 commit 4427d11
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 25 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b50511e41aa51a89b4176784a670582424bc7db6
refs/heads/master: d4e81b35b882d96f059afdb0f98e5b6025973b09
2 changes: 1 addition & 1 deletion trunk/arch/s390/include/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ typedef struct
#define PSW_MASK_EA 0x0000000100000000UL
#define PSW_MASK_BA 0x0000000080000000UL

#define PSW_MASK_USER 0x00003F0000000000UL
#define PSW_MASK_USER 0x00003F0180000000UL

#define PSW_ADDR_AMODE 0x0000000000000000UL
#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
Expand Down
12 changes: 8 additions & 4 deletions trunk/arch/s390/kernel/compat_signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,8 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)

regs32.psw.mask = psw32_user_bits |
((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER);
regs32.psw.addr = PSW32_ADDR_AMODE | (__u32) regs->psw.addr;
regs32.psw.addr = (__u32) regs->psw.addr |
(__u32)(regs->psw.mask & PSW_MASK_BA);
for (i = 0; i < NUM_GPRS; i++)
regs32.gprs[i] = (__u32) regs->gprs[i];
save_access_regs(current->thread.acrs);
Expand All @@ -328,7 +329,8 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
if (err)
return err;
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
(__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32;
(__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
(__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
for (i = 0; i < NUM_GPRS; i++)
regs->gprs[i] = (__u64) regs32.gprs[i];
Expand Down Expand Up @@ -496,9 +498,9 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = (__u64) ka->sa.sa_restorer;
regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
} else {
regs->gprs[14] = (__u64) frame->retcode;
regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
(u16 __user *)(frame->retcode)))
goto give_sigsegv;
Expand All @@ -510,6 +512,7 @@ static int setup_frame32(int sig, struct k_sigaction *ka,

/* Set up registers for signal handler */
regs->gprs[15] = (__u64) frame;
regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */
regs->psw.addr = (__u64) ka->sa.sa_handler;

regs->gprs[2] = map_signal(sig);
Expand Down Expand Up @@ -573,6 +576,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,

/* Set up registers for signal handler */
regs->gprs[15] = (__u64) frame;
regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */
regs->psw.addr = (__u64) ka->sa.sa_handler;

regs->gprs[2] = map_signal(sig);
Expand Down
25 changes: 10 additions & 15 deletions trunk/arch/s390/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr)
tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr);
if (addr == (addr_t) &dummy->regs.psw.mask)
/* Return a clean psw mask. */
tmp = psw_user_bits | (tmp & PSW_MASK_USER) |
PSW_MASK_EA | PSW_MASK_BA;
tmp = psw_user_bits | (tmp & PSW_MASK_USER);

} else if (addr < (addr_t) &dummy->regs.orig_gpr2) {
/*
Expand Down Expand Up @@ -286,26 +285,17 @@ static inline void __poke_user_per(struct task_struct *child,
static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
{
struct user *dummy = NULL;
addr_t offset, tmp;
addr_t offset;

if (addr < (addr_t) &dummy->regs.acrs) {
/*
* psw and gprs are stored on the stack
*/
tmp = (data & ~PSW_MASK_USER) ^ psw_user_bits;
if (addr == (addr_t) &dummy->regs.psw.mask &&
#ifdef CONFIG_COMPAT
tmp != PSW_MASK_BA &&
#endif
tmp != (PSW_MASK_EA | PSW_MASK_BA))
((data & ~PSW_MASK_USER) != psw_user_bits ||
((data & PSW_MASK_EA) && !(data & PSW_MASK_BA))))
/* Invalid psw mask. */
return -EINVAL;
#ifndef CONFIG_64BIT
if (addr == (addr_t) &dummy->regs.psw.addr)
/* I'd like to reject addresses without the
high order bit but older gdb's rely on it */
data |= PSW_ADDR_AMODE;
#endif
if (addr == (addr_t) &dummy->regs.psw.addr)
/*
* The debugger changed the instruction address,
Expand Down Expand Up @@ -517,7 +507,8 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
tmp = psw32_user_bits | (tmp & PSW32_MASK_USER);
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
/* Fake a 31 bit psw address. */
tmp = (__u32) regs->psw.addr | PSW32_ADDR_AMODE;
tmp = (__u32) regs->psw.addr |
(__u32)(regs->psw.mask & PSW_MASK_BA);
} else {
/* gpr 0-15 */
tmp = *(__u32 *)((addr_t) &regs->psw + addr*2 + 4);
Expand Down Expand Up @@ -615,10 +606,14 @@ static int __poke_user_compat(struct task_struct *child,
/* Invalid psw mask. */
return -EINVAL;
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
(regs->psw.mask & PSW_MASK_BA) |
(__u64)(tmp & PSW32_MASK_USER) << 32;
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
/* Build a 64 bit psw address from 31 bit address. */
regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN;
/* Transfer 31 bit amode bit to psw mask. */
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_BA) |
(__u64)(tmp & PSW32_ADDR_AMODE);
/*
* The debugger changed the instruction address,
* reset system call restart, see signal.c:do_signal
Expand Down
14 changes: 10 additions & 4 deletions trunk/arch/s390/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)

/* Copy a 'clean' PSW mask to the user to avoid leaking
information about whether PER is currently on. */
user_sregs.regs.psw.mask = psw_user_bits | PSW_MASK_EA | PSW_MASK_BA |
(regs->psw.mask & PSW_MASK_USER);
user_sregs.regs.psw.mask = psw_user_bits |
(regs->psw.mask & PSW_MASK_USER);
user_sregs.regs.psw.addr = regs->psw.addr;
memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
memcpy(&user_sregs.regs.acrs, current->thread.acrs,
Expand All @@ -145,9 +145,13 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs));
if (err)
return err;
/* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
(user_sregs.regs.psw.mask & PSW_MASK_USER);
regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr;
(user_sregs.regs.psw.mask & PSW_MASK_USER);
/* Check for invalid amode */
if (regs->psw.mask & PSW_MASK_EA)
regs->psw.mask |= PSW_MASK_BA;
regs->psw.addr = user_sregs.regs.psw.addr;
memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
sizeof(sregs->regs.acrs));
Expand Down Expand Up @@ -290,6 +294,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,

/* Set up registers for signal handler */
regs->gprs[15] = (unsigned long) frame;
regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */
regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;

regs->gprs[2] = map_signal(sig);
Expand Down Expand Up @@ -358,6 +363,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,

/* Set up registers for signal handler */
regs->gprs[15] = (unsigned long) frame;
regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */
regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;

regs->gprs[2] = map_signal(sig);
Expand Down

0 comments on commit 4427d11

Please sign in to comment.