aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2012-11-07 04:44:08 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-11-12 10:24:38 -0500
commitfa968ee215c0ca91e4a9c3a69ac2405aae6e5d2f (patch)
tree1b1f45f608ab83a8b4bf741b6f439a473a6b82b6 /arch/s390
parent77b67063bb6bce6d475e910d3b886a606d0d91f7 (diff)
s390/signal: set correct address space control
If user space is running in primary mode it can switch to secondary or access register mode, this is used e.g. in the clock_gettime code of the vdso. If a signal is delivered to the user space process while it has been running in access register mode the signal handler is executed in access register mode as well which will result in a crash most of the time. Set the address space control bits in the PSW to the default for the execution of the signal handler and make sure that the previous address space control is restored on signal return. Take care that user space can not switch to the kernel address space by modifying the registers in the signal frame. Cc: stable@vger.kernel.org Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/compat.h2
-rw-r--r--arch/s390/include/uapi/asm/ptrace.h4
-rw-r--r--arch/s390/kernel/compat_signal.c14
-rw-r--r--arch/s390/kernel/signal.c14
4 files changed, 27 insertions, 7 deletions
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index a34a9d612fc0..18cd6b592650 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -20,7 +20,7 @@
20#define PSW32_MASK_CC 0x00003000UL 20#define PSW32_MASK_CC 0x00003000UL
21#define PSW32_MASK_PM 0x00000f00UL 21#define PSW32_MASK_PM 0x00000f00UL
22 22
23#define PSW32_MASK_USER 0x00003F00UL 23#define PSW32_MASK_USER 0x0000FF00UL
24 24
25#define PSW32_ADDR_AMODE 0x80000000UL 25#define PSW32_ADDR_AMODE 0x80000000UL
26#define PSW32_ADDR_INSN 0x7FFFFFFFUL 26#define PSW32_ADDR_INSN 0x7FFFFFFFUL
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
index 705588a16d70..a5ca214b34fd 100644
--- a/arch/s390/include/uapi/asm/ptrace.h
+++ b/arch/s390/include/uapi/asm/ptrace.h
@@ -239,7 +239,7 @@ typedef struct
239#define PSW_MASK_EA 0x00000000UL 239#define PSW_MASK_EA 0x00000000UL
240#define PSW_MASK_BA 0x00000000UL 240#define PSW_MASK_BA 0x00000000UL
241 241
242#define PSW_MASK_USER 0x00003F00UL 242#define PSW_MASK_USER 0x0000FF00UL
243 243
244#define PSW_ADDR_AMODE 0x80000000UL 244#define PSW_ADDR_AMODE 0x80000000UL
245#define PSW_ADDR_INSN 0x7FFFFFFFUL 245#define PSW_ADDR_INSN 0x7FFFFFFFUL
@@ -269,7 +269,7 @@ typedef struct
269#define PSW_MASK_EA 0x0000000100000000UL 269#define PSW_MASK_EA 0x0000000100000000UL
270#define PSW_MASK_BA 0x0000000080000000UL 270#define PSW_MASK_BA 0x0000000080000000UL
271 271
272#define PSW_MASK_USER 0x00003F8180000000UL 272#define PSW_MASK_USER 0x0000FF8180000000UL
273 273
274#define PSW_ADDR_AMODE 0x0000000000000000UL 274#define PSW_ADDR_AMODE 0x0000000000000000UL
275#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL 275#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index a1e8a8694bb7..593fcc9253fc 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -309,6 +309,10 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
309 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 309 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
310 (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 | 310 (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
311 (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE); 311 (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
312 /* Check for invalid user address space control. */
313 if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC))
314 regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) |
315 (regs->psw.mask & ~PSW_MASK_ASC);
312 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN); 316 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
313 for (i = 0; i < NUM_GPRS; i++) 317 for (i = 0; i < NUM_GPRS; i++)
314 regs->gprs[i] = (__u64) regs32.gprs[i]; 318 regs->gprs[i] = (__u64) regs32.gprs[i];
@@ -481,7 +485,10 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
481 485
482 /* Set up registers for signal handler */ 486 /* Set up registers for signal handler */
483 regs->gprs[15] = (__force __u64) frame; 487 regs->gprs[15] = (__force __u64) frame;
484 regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */ 488 /* Force 31 bit amode and default user address space control. */
489 regs->psw.mask = PSW_MASK_BA |
490 (psw_user_bits & PSW_MASK_ASC) |
491 (regs->psw.mask & ~PSW_MASK_ASC);
485 regs->psw.addr = (__force __u64) ka->sa.sa_handler; 492 regs->psw.addr = (__force __u64) ka->sa.sa_handler;
486 493
487 regs->gprs[2] = map_signal(sig); 494 regs->gprs[2] = map_signal(sig);
@@ -549,7 +556,10 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
549 556
550 /* Set up registers for signal handler */ 557 /* Set up registers for signal handler */
551 regs->gprs[15] = (__force __u64) frame; 558 regs->gprs[15] = (__force __u64) frame;
552 regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */ 559 /* Force 31 bit amode and default user address space control. */
560 regs->psw.mask = PSW_MASK_BA |
561 (psw_user_bits & PSW_MASK_ASC) |
562 (regs->psw.mask & ~PSW_MASK_ASC);
553 regs->psw.addr = (__u64) ka->sa.sa_handler; 563 regs->psw.addr = (__u64) ka->sa.sa_handler;
554 564
555 regs->gprs[2] = map_signal(sig); 565 regs->gprs[2] = map_signal(sig);
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index c13a2a37ef00..d1259d875074 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -136,6 +136,10 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
136 /* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */ 136 /* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */
137 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 137 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
138 (user_sregs.regs.psw.mask & PSW_MASK_USER); 138 (user_sregs.regs.psw.mask & PSW_MASK_USER);
139 /* Check for invalid user address space control. */
140 if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC))
141 regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) |
142 (regs->psw.mask & ~PSW_MASK_ASC);
139 /* Check for invalid amode */ 143 /* Check for invalid amode */
140 if (regs->psw.mask & PSW_MASK_EA) 144 if (regs->psw.mask & PSW_MASK_EA)
141 regs->psw.mask |= PSW_MASK_BA; 145 regs->psw.mask |= PSW_MASK_BA;
@@ -273,7 +277,10 @@ static int setup_frame(int sig, struct k_sigaction *ka,
273 277
274 /* Set up registers for signal handler */ 278 /* Set up registers for signal handler */
275 regs->gprs[15] = (unsigned long) frame; 279 regs->gprs[15] = (unsigned long) frame;
276 regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */ 280 /* Force default amode and default user address space control. */
281 regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
282 (psw_user_bits & PSW_MASK_ASC) |
283 (regs->psw.mask & ~PSW_MASK_ASC);
277 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; 284 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
278 285
279 regs->gprs[2] = map_signal(sig); 286 regs->gprs[2] = map_signal(sig);
@@ -346,7 +353,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
346 353
347 /* Set up registers for signal handler */ 354 /* Set up registers for signal handler */
348 regs->gprs[15] = (unsigned long) frame; 355 regs->gprs[15] = (unsigned long) frame;
349 regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */ 356 /* Force default amode and default user address space control. */
357 regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
358 (psw_user_bits & PSW_MASK_ASC) |
359 (regs->psw.mask & ~PSW_MASK_ASC);
350 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; 360 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
351 361
352 regs->gprs[2] = map_signal(sig); 362 regs->gprs[2] = map_signal(sig);