diff options
Diffstat (limited to 'arch/s390/kernel/signal.c')
-rw-r--r-- | arch/s390/kernel/signal.c | 49 |
1 files changed, 28 insertions, 21 deletions
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index c45becf82e01..fb535874a246 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
@@ -57,40 +57,48 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) | |||
57 | 57 | ||
58 | /* Copy a 'clean' PSW mask to the user to avoid leaking | 58 | /* Copy a 'clean' PSW mask to the user to avoid leaking |
59 | information about whether PER is currently on. */ | 59 | information about whether PER is currently on. */ |
60 | user_sregs.regs.psw.mask = psw_user_bits | | 60 | user_sregs.regs.psw.mask = PSW_USER_BITS | |
61 | (regs->psw.mask & PSW_MASK_USER); | 61 | (regs->psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); |
62 | user_sregs.regs.psw.addr = regs->psw.addr; | 62 | user_sregs.regs.psw.addr = regs->psw.addr; |
63 | memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); | 63 | memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); |
64 | memcpy(&user_sregs.regs.acrs, current->thread.acrs, | 64 | memcpy(&user_sregs.regs.acrs, current->thread.acrs, |
65 | sizeof(sregs->regs.acrs)); | 65 | sizeof(user_sregs.regs.acrs)); |
66 | /* | 66 | /* |
67 | * We have to store the fp registers to current->thread.fp_regs | 67 | * We have to store the fp registers to current->thread.fp_regs |
68 | * to merge them with the emulated registers. | 68 | * to merge them with the emulated registers. |
69 | */ | 69 | */ |
70 | save_fp_regs(¤t->thread.fp_regs); | 70 | save_fp_ctl(¤t->thread.fp_regs.fpc); |
71 | save_fp_regs(current->thread.fp_regs.fprs); | ||
71 | memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs, | 72 | memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs, |
72 | sizeof(s390_fp_regs)); | 73 | sizeof(user_sregs.fpregs)); |
73 | return __copy_to_user(sregs, &user_sregs, sizeof(_sigregs)); | 74 | if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs))) |
75 | return -EFAULT; | ||
76 | return 0; | ||
74 | } | 77 | } |
75 | 78 | ||
76 | /* Returns positive number on error */ | ||
77 | static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) | 79 | static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) |
78 | { | 80 | { |
79 | int err; | ||
80 | _sigregs user_sregs; | 81 | _sigregs user_sregs; |
81 | 82 | ||
82 | /* Alwys make any pending restarted system call return -EINTR */ | 83 | /* Alwys make any pending restarted system call return -EINTR */ |
83 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 84 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
84 | 85 | ||
85 | err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs)); | 86 | if (__copy_from_user(&user_sregs, sregs, sizeof(user_sregs))) |
86 | if (err) | 87 | return -EFAULT; |
87 | return err; | 88 | |
88 | /* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */ | 89 | if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI)) |
90 | return -EINVAL; | ||
91 | |||
92 | /* Loading the floating-point-control word can fail. Do that first. */ | ||
93 | if (restore_fp_ctl(&user_sregs.fpregs.fpc)) | ||
94 | return -EINVAL; | ||
95 | |||
96 | /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */ | ||
89 | regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | | 97 | regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | |
90 | (user_sregs.regs.psw.mask & PSW_MASK_USER); | 98 | (user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); |
91 | /* Check for invalid user address space control. */ | 99 | /* Check for invalid user address space control. */ |
92 | if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC)) | 100 | if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME) |
93 | regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) | | 101 | regs->psw.mask = PSW_ASC_PRIMARY | |
94 | (regs->psw.mask & ~PSW_MASK_ASC); | 102 | (regs->psw.mask & ~PSW_MASK_ASC); |
95 | /* Check for invalid amode */ | 103 | /* Check for invalid amode */ |
96 | if (regs->psw.mask & PSW_MASK_EA) | 104 | if (regs->psw.mask & PSW_MASK_EA) |
@@ -98,14 +106,13 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) | |||
98 | regs->psw.addr = user_sregs.regs.psw.addr; | 106 | regs->psw.addr = user_sregs.regs.psw.addr; |
99 | memcpy(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); | 107 | memcpy(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); |
100 | memcpy(¤t->thread.acrs, &user_sregs.regs.acrs, | 108 | memcpy(¤t->thread.acrs, &user_sregs.regs.acrs, |
101 | sizeof(sregs->regs.acrs)); | 109 | sizeof(current->thread.acrs)); |
102 | restore_access_regs(current->thread.acrs); | 110 | restore_access_regs(current->thread.acrs); |
103 | 111 | ||
104 | memcpy(¤t->thread.fp_regs, &user_sregs.fpregs, | 112 | memcpy(¤t->thread.fp_regs, &user_sregs.fpregs, |
105 | sizeof(s390_fp_regs)); | 113 | sizeof(current->thread.fp_regs)); |
106 | current->thread.fp_regs.fpc &= FPC_VALID_MASK; | ||
107 | 114 | ||
108 | restore_fp_regs(¤t->thread.fp_regs); | 115 | restore_fp_regs(current->thread.fp_regs.fprs); |
109 | clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */ | 116 | clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */ |
110 | return 0; | 117 | return 0; |
111 | } | 118 | } |
@@ -224,7 +231,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
224 | regs->gprs[15] = (unsigned long) frame; | 231 | regs->gprs[15] = (unsigned long) frame; |
225 | /* Force default amode and default user address space control. */ | 232 | /* Force default amode and default user address space control. */ |
226 | regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | | 233 | regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | |
227 | (psw_user_bits & PSW_MASK_ASC) | | 234 | (PSW_USER_BITS & PSW_MASK_ASC) | |
228 | (regs->psw.mask & ~PSW_MASK_ASC); | 235 | (regs->psw.mask & ~PSW_MASK_ASC); |
229 | regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; | 236 | regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; |
230 | 237 | ||
@@ -295,7 +302,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
295 | regs->gprs[15] = (unsigned long) frame; | 302 | regs->gprs[15] = (unsigned long) frame; |
296 | /* Force default amode and default user address space control. */ | 303 | /* Force default amode and default user address space control. */ |
297 | regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | | 304 | regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | |
298 | (psw_user_bits & PSW_MASK_ASC) | | 305 | (PSW_USER_BITS & PSW_MASK_ASC) | |
299 | (regs->psw.mask & ~PSW_MASK_ASC); | 306 | (regs->psw.mask & ~PSW_MASK_ASC); |
300 | regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; | 307 | regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; |
301 | 308 | ||