Blob Blame History Raw
From: Heiko Carstens <heiko.carstens@de.ibm.com>
Subject: s390: fix transactional execution control register handling
Patch-mainline: v4.15-rc1
Git-commit: a1c5befc1c24eb9c1ee83f711e0f21ee79cbb556
References: bnc#1072915, LTC#162116

Description:  transactional execution: control register handling
Symptom:      User process crashes on transactional execution related
              instructions like tbegin.
Problem:      There are several bugs with control register handling with
              respect to transactional execution:
              - on task switch update_per_regs() is only called if the
                next task has an mm (is not a kernel thread). This
                however is incorrect. This breaks e.g. for user mode
                helper handling, where the kernel creates a kernel
                thread and then execve's a user space program. Control
                register contents related to transactional execution
                won't be updated on execve. If the previous task ran
                with transactional execution disabled then the new
                task will also run with transactional execution
                disabled, which is incorrect.
              - on startup the transactional execution facility is not
                enabled for the idle thread. This is not really a bug,
                but an inconsistency to other facilities. Therefore
              - on fork the new thread's per_flags field is not
                cleared. This means that a child process inherits the
                PER_FLAG_NO_TE flag. This flag can be set with a
                ptrace request to disable transactional execution for
                the current process. It should not be inherited by new
                child processes in order to be consistent with the
                handling of all other PER related debugging
                options.
Solution:     Call update_per_regs() unconditionally within switch_to(),
              enable the transactional execution facility as early as
              possible if it is available, and clear the per_flags field
              in copy_thread_tls().
Reproduction: -

Upstream-Description:

              s390: fix transactional execution control register handling

              Dan Horák reported the following crash related to transactional execution:

              User process fault: interruption code 0013 ilc:3 in libpthread-2.26.so[3ff93c00000+1b000]
              CPU: 2 PID: 1 Comm: /init Not tainted 4.13.4-300.fc27.s390x #1
              Hardware name: IBM 2827 H43 400 (z/VM 6.4.0)
              task: 00000000fafc8000 task.stack: 00000000fafc4000
              User PSW : 0705200180000000 000003ff93c14e70
                         R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:1 AS:0 CC:2 PM:0 RI:0 EA:3
              User GPRS: 0000000000000077 000003ff00000000 000003ff93144d48 000003ff93144d5e
                         0000000000000000 0000000000000002 0000000000000000 000003ff00000000
                         0000000000000000 0000000000000418 0000000000000000 000003ffcc9fe770
                         000003ff93d28f50 000003ff9310acf0 000003ff92b0319a 000003ffcc9fe6d0
              User Code: 000003ff93c14e62: 60e0b030            std     %f14,48(%r11)
                         000003ff93c14e66: 60f0b038            std     %f15,56(%r11)
                        #000003ff93c14e6a: e5600000ff0e        tbegin  0,65294
                        >000003ff93c14e70: a7740006            brc     7,3ff93c14e7c
                         000003ff93c14e74: a7080000            lhi     %r0,0
                         000003ff93c14e78: a7f40023            brc     15,3ff93c14ebe
                         000003ff93c14e7c: b2220000            ipm     %r0
                         000003ff93c14e80: 8800001c            srl     %r0,28

              There are several bugs with control register handling with respect to
              transactional execution:

              - on task switch update_per_regs() is only called if the next task has
                an mm (is not a kernel thread). This however is incorrect. This
                breaks e.g. for user mode helper handling, where the kernel creates
                a kernel thread and then execve's a user space program. Control
                register contents related to transactional execution won't be
                updated on execve. If the previous task ran with transactional
                execution disabled then the new task will also run with
                transactional execution disabled, which is incorrect. Therefore call
                update_per_regs() unconditionally within switch_to().

              - on startup the transactional execution facility is not enabled for
                the idle thread. This is not really a bug, but an inconsistency to
                other facilities. Therefore enable the facility if it is available.

              - on fork the new thread's per_flags field is not cleared. This means
                that a child process inherits the PER_FLAG_NO_TE flag. This flag can
                be set with a ptrace request to disable transactional execution for
                the current process. It should not be inherited by new child
                processes in order to be consistent with the handling of all other
                PER related debugging options. Therefore clear the per_flags field in
                copy_thread_tls().

              Reported-and-tested-by: Dan Horák <dan@danny.cz>
              Fixes: d35339a42dd1 ("s390: add support for transactional memory")
              Cc: <stable@vger.kernel.org> # v3.7+
              Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
              Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
              Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
              Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>


Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
---
 arch/s390/include/asm/switch_to.h |    2 +-
 arch/s390/kernel/early.c          |    4 +++-
 arch/s390/kernel/process.c        |    1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

--- a/arch/s390/include/asm/switch_to.h
+++ b/arch/s390/include/asm/switch_to.h
@@ -36,8 +36,8 @@ static inline void restore_access_regs(u
 		save_ri_cb(prev->thread.ri_cb);				\
 		save_gs_cb(prev->thread.gs_cb);				\
 	}								\
+	update_cr_regs(next);						\
 	if (next->mm) {							\
-		update_cr_regs(next);					\
 		set_cpu_flag(CIF_FPU);					\
 		restore_access_regs(&next->thread.acrs[0]);		\
 		restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);	\
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -373,8 +373,10 @@ static __init void detect_machine_facili
 		S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
 	if (test_facility(40))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
-	if (test_facility(50) && test_facility(73))
+	if (test_facility(50) && test_facility(73)) {
 		S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
+		__ctl_set_bit(0, 55);
+	}
 	if (test_facility(51))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
 	if (test_facility(129)) {
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -99,6 +99,7 @@ int copy_thread_tls(unsigned long clone_
 	memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
 	memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
 	clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
+	p->thread.per_flags = 0;
 	/* Initialize per thread user and system timer values */
 	p->thread.user_timer = 0;
 	p->thread.guest_timer = 0;