[PATCH 4/4] s390/uaccess: remove set_fs() interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Remove set_fs() interface and therefore the possibility to use uaccess
primitives for kernel address space.  In order to safely access kernel
address space copy_to/from_kernel_nofault() or get_kernel_nofault()
have to be used.

Address spaces still have to switched/changed for machines without the
mvcos instructions and especially for instructions like e.g. compare
and swap (-> futex) which must be executed in kernel address space but
access user address space. For such instructions enable_sacf_uaccess()
and disable_sacf_uaccess() must be used like before.

Signed-off-by: Heiko Carstens <hca@xxxxxxxxxxxxx>
---
 arch/s390/Kconfig                   |  1 -
 arch/s390/include/asm/futex.h       | 12 ++---
 arch/s390/include/asm/mmu_context.h |  7 +--
 arch/s390/include/asm/processor.h   |  4 +-
 arch/s390/include/asm/uaccess.h     | 18 -------
 arch/s390/kernel/entry.S            | 19 ++------
 arch/s390/kernel/entry.h            |  1 -
 arch/s390/kernel/process.c          | 15 +-----
 arch/s390/lib/uaccess.c             | 76 +++++++++++++----------------
 arch/s390/mm/fault.c                |  9 ++--
 arch/s390/mm/pgalloc.c              | 11 ++---
 arch/s390/pci/pci_mmio.c            | 12 ++---
 12 files changed, 63 insertions(+), 122 deletions(-)

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index af72fca9ccd5..b29fcc66ec39 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -185,7 +185,6 @@ config S390
 	select OLD_SIGSUSPEND3
 	select PCI_DOMAINS		if PCI
 	select PCI_MSI			if PCI
-	select SET_FS
 	select SPARSE_IRQ
 	select SYSCTL_EXCEPTION_TRACE
 	select THREAD_INFO_IN_TASK
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 26f9144562c9..ea225b5a9c80 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -26,9 +26,9 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
 		u32 __user *uaddr)
 {
 	int oldval = 0, newval, ret;
-	mm_segment_t old_fs;
+	bool old;
 
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	switch (op) {
 	case FUTEX_OP_SET:
 		__futex_atomic_op("lr %2,%5\n",
@@ -53,7 +53,7 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
 	default:
 		ret = -ENOSYS;
 	}
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 
 	if (!ret)
 		*oval = oldval;
@@ -64,10 +64,10 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
 static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 						u32 oldval, u32 newval)
 {
-	mm_segment_t old_fs;
+	bool old;
 	int ret;
 
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	asm volatile(
 		"   sacf 256\n"
 		"0: cs   %1,%4,0(%5)\n"
@@ -77,7 +77,7 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 		: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
 		: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
 		: "cc", "memory");
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 	*uval = oldval;
 	return ret;
 }
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index c9f3d8a52756..11b8557b1d1d 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -85,8 +85,9 @@ static inline void clear_user_asce(void)
 	set_cpu_flag(CIF_ASCE_PRIMARY);
 }
 
-mm_segment_t enable_sacf_uaccess(void);
-void disable_sacf_uaccess(mm_segment_t old_fs);
+void setup_address_spaces(void);
+bool enable_sacf_uaccess(void);
+void disable_sacf_uaccess(bool old);
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 			     struct task_struct *tsk)
@@ -122,7 +123,7 @@ static inline void finish_arch_post_lock_switch(void)
 		__tlb_flush_mm_lazy(mm);
 		preempt_enable();
 	}
-	set_fs(current->thread.mm_segment);
+	setup_address_spaces();
 }
 
 #define enter_lazy_tlb(mm,tsk)	do { } while (0)
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 962da04234af..5a951527f1bd 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -102,8 +102,6 @@ extern void __bpon(void);
 
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 
-typedef unsigned int mm_segment_t;
-
 /*
  * Thread structure
  */
@@ -116,7 +114,7 @@ struct thread_struct {
 	unsigned long hardirq_timer;	/* task cputime in hardirq context */
 	unsigned long softirq_timer;	/* task cputime in softirq context */
 	unsigned long sys_call_table;	/* system call table address */
-	mm_segment_t mm_segment;
+	bool sacf_uaccess;		/* uaccess with sacf enabled */
 	unsigned long gmap_addr;	/* address of last gmap fault. */
 	unsigned int gmap_write_flag;	/* gmap fault write indication */
 	unsigned int gmap_int_code;	/* int code of last gmap fault */
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 3ef424bca082..f71e93e1ff73 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -18,24 +18,6 @@
 #include <asm/extable.h>
 #include <asm/facility.h>
 
-/*
- * The fs value determines whether argument validity checking should be
- * performed or not.  If get_fs() == USER_DS, checking is performed, with
- * get_fs() == KERNEL_DS, checking is bypassed.
- *
- * For historical reasons, these macros are grossly misnamed.
- */
-
-#define KERNEL_DS	(0)
-#define KERNEL_DS_SACF	(1)
-#define USER_DS		(2)
-#define USER_DS_SACF	(3)
-
-#define get_fs()        (current->thread.mm_segment)
-#define uaccess_kernel() ((get_fs() & 2) == KERNEL_DS)
-
-void set_fs(mm_segment_t fs);
-
 static inline int __range_ok(unsigned long addr, unsigned long size)
 {
 	return 1;
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 23edf196d3dc..434b059bb9fb 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -486,19 +486,13 @@ ENTRY(system_call)
 .Lsysc_asce:
 	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE_SECONDARY
 	lctlg	%c7,%c7,__LC_VDSO_ASCE		# load secondary asce
+#ifndef CONFIG_HAVE_MARCH_Z10_FEATURES
 	TSTMSK	__LC_CPU_FLAGS,_CIF_ASCE_PRIMARY
 	jz	.Lsysc_return
-#ifndef CONFIG_HAVE_MARCH_Z10_FEATURES
-	tm	__LC_STFLE_FAC_LIST+3,0x10	# has MVCOS ?
-	jnz	.Lsysc_set_fs_fixup
 	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE_PRIMARY
 	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
-	j	.Lsysc_return
-.Lsysc_set_fs_fixup:
 #endif
-	larl	%r14,.Lsysc_return
-	jg	set_fs_fixup
-
+	j	.Lsysc_return
 
 #
 # _TIF_SIGPENDING is set, call do_signal
@@ -877,18 +871,13 @@ ENTRY(io_int_handler)
 .Lio_asce:
 	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE_SECONDARY
 	lctlg	%c7,%c7,__LC_VDSO_ASCE		# load secondary asce
+#ifndef CONFIG_HAVE_MARCH_Z10_FEATURES
 	TSTMSK	__LC_CPU_FLAGS,_CIF_ASCE_PRIMARY
 	jz	.Lio_return
-#ifndef CONFIG_HAVE_MARCH_Z10_FEATURES
-	tm	__LC_STFLE_FAC_LIST+3,0x10	# has MVCOS ?
-	jnz	.Lio_set_fs_fixup
 	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE_PRIMARY
 	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
-	j	.Lio_return
-.Lio_set_fs_fixup:
 #endif
-	larl	%r14,.Lio_return
-	jg	set_fs_fixup
+	j	.Lio_return
 
 #
 # CIF_FPU is set, restore floating-point controls and floating-point registers.
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index faca269d5f27..2e9be5657120 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -86,7 +86,6 @@ long sys_s390_sthyi(unsigned long function_code, void __user *buffer, u64 __user
 DECLARE_PER_CPU(u64, mt_cycles[8]);
 
 void gs_load_bc_cb(struct pt_regs *regs);
-void set_fs_fixup(void);
 
 unsigned long stack_alloc(void);
 void stack_free(unsigned long stack);
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index ec801d3bbb37..2a87c2dde6fc 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -94,7 +94,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
 	/* Save access registers to new thread structure. */
 	save_access_regs(&p->thread.acrs[0]);
 	/* start new process with ar4 pointing to the correct address space */
-	p->thread.mm_segment = get_fs();
+	p->thread.sacf_uaccess = current->thread.sacf_uaccess;
 	/* Don't copy debug registers */
 	memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
 	memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
@@ -208,16 +208,3 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
 	ret = PAGE_ALIGN(mm->brk + brk_rnd());
 	return (ret > mm->brk) ? ret : mm->brk;
 }
-
-void set_fs_fixup(void)
-{
-	struct pt_regs *regs = current_pt_regs();
-	static bool warned;
-
-	set_fs(USER_DS);
-	if (warned)
-		return;
-	WARN(1, "Unbalanced set_fs - int code: 0x%x\n", regs->int_code);
-	show_registers(regs);
-	warned = true;
-}
diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c
index 0267405ab7c6..eb5f2b7360e1 100644
--- a/arch/s390/lib/uaccess.c
+++ b/arch/s390/lib/uaccess.c
@@ -40,61 +40,51 @@ static inline int copy_with_mvcos(void)
 }
 #endif
 
-void set_fs(mm_segment_t fs)
+void setup_address_spaces(void)
 {
-	current->thread.mm_segment = fs;
-	if (fs == USER_DS) {
+	if (likely(!current->thread.sacf_uaccess)) {
 		__ctl_load(S390_lowcore.user_asce, 1, 1);
 		clear_cpu_flag(CIF_ASCE_PRIMARY);
 	} else {
 		__ctl_load(S390_lowcore.kernel_asce, 1, 1);
 		set_cpu_flag(CIF_ASCE_PRIMARY);
-	}
-	if (fs & 1) {
-		if (fs == USER_DS_SACF)
-			__ctl_load(S390_lowcore.user_asce, 7, 7);
-		else
-			__ctl_load(S390_lowcore.kernel_asce, 7, 7);
+		__ctl_load(S390_lowcore.user_asce, 7, 7);
 		set_cpu_flag(CIF_ASCE_SECONDARY);
 	}
 }
-EXPORT_SYMBOL(set_fs);
 
-mm_segment_t enable_sacf_uaccess(void)
+bool enable_sacf_uaccess(void)
 {
-	mm_segment_t old_fs;
 	unsigned long asce, cr;
 	unsigned long flags;
+	bool old;
 
-	old_fs = current->thread.mm_segment;
-	if (old_fs & 1)
-		return old_fs;
+	old = current->thread.sacf_uaccess;
+	if (old)
+		return old;
 	/* protect against a concurrent page table upgrade */
 	local_irq_save(flags);
-	current->thread.mm_segment |= 1;
-	asce = S390_lowcore.kernel_asce;
-	if (likely(old_fs == USER_DS)) {
-		__ctl_store(cr, 1, 1);
-		if (cr != S390_lowcore.kernel_asce) {
-			__ctl_load(S390_lowcore.kernel_asce, 1, 1);
-			set_cpu_flag(CIF_ASCE_PRIMARY);
-		}
-		asce = S390_lowcore.user_asce;
+	current->thread.sacf_uaccess = true;
+	__ctl_store(cr, 1, 1);
+	if (cr != S390_lowcore.kernel_asce) {
+		__ctl_load(S390_lowcore.kernel_asce, 1, 1);
+		set_cpu_flag(CIF_ASCE_PRIMARY);
 	}
+	asce = S390_lowcore.user_asce;
 	__ctl_store(cr, 7, 7);
 	if (cr != asce) {
 		__ctl_load(asce, 7, 7);
 		set_cpu_flag(CIF_ASCE_SECONDARY);
 	}
 	local_irq_restore(flags);
-	return old_fs;
+	return old;
 }
 EXPORT_SYMBOL(enable_sacf_uaccess);
 
-void disable_sacf_uaccess(mm_segment_t old_fs)
+void disable_sacf_uaccess(bool old)
 {
-	current->thread.mm_segment = old_fs;
-	if (old_fs == USER_DS && test_facility(27)) {
+	current->thread.sacf_uaccess = old;
+	if (!old && test_facility(27)) {
 		__ctl_load(S390_lowcore.user_asce, 1, 1);
 		clear_cpu_flag(CIF_ASCE_PRIMARY);
 	}
@@ -135,9 +125,9 @@ static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
 						unsigned long size)
 {
 	unsigned long tmp1, tmp2;
-	mm_segment_t old_fs;
+	bool old;
 
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	tmp1 = -256UL;
 	asm volatile(
 		"   sacf  0\n"
@@ -164,7 +154,7 @@ static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
 		EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
 		: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
 		: : "cc", "memory");
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 	return size;
 }
 
@@ -210,9 +200,9 @@ static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
 					      unsigned long size)
 {
 	unsigned long tmp1, tmp2;
-	mm_segment_t old_fs;
+	bool old;
 
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	tmp1 = -256UL;
 	asm volatile(
 		"   sacf  0\n"
@@ -239,7 +229,7 @@ static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
 		EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
 		: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
 		: : "cc", "memory");
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 	return size;
 }
 
@@ -277,10 +267,10 @@ static inline unsigned long copy_in_user_mvcos(void __user *to, const void __use
 static inline unsigned long copy_in_user_mvc(void __user *to, const void __user *from,
 					     unsigned long size)
 {
-	mm_segment_t old_fs;
 	unsigned long tmp1;
+	bool old;
 
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	asm volatile(
 		"   sacf  256\n"
 		"   aghi  %0,-1\n"
@@ -304,7 +294,7 @@ static inline unsigned long copy_in_user_mvc(void __user *to, const void __user
 		EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
 		: "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
 		: : "cc", "memory");
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 	return size;
 }
 
@@ -346,10 +336,10 @@ static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size
 
 static inline unsigned long clear_user_xc(void __user *to, unsigned long size)
 {
-	mm_segment_t old_fs;
 	unsigned long tmp1, tmp2;
+	bool old;
 
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	asm volatile(
 		"   sacf  256\n"
 		"   aghi  %0,-1\n"
@@ -378,7 +368,7 @@ static inline unsigned long clear_user_xc(void __user *to, unsigned long size)
 		EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
 		: "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2)
 		: : "cc", "memory");
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 	return size;
 }
 
@@ -414,14 +404,14 @@ static inline unsigned long strnlen_user_srst(const char __user *src,
 
 unsigned long __strnlen_user(const char __user *src, unsigned long size)
 {
-	mm_segment_t old_fs;
 	unsigned long len;
+	bool old;
 
 	if (unlikely(!size))
 		return 0;
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	len = strnlen_user_srst(src, size);
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 	return len;
 }
 EXPORT_SYMBOL(__strnlen_user);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 4c8c063bce5b..86569da371a1 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -80,17 +80,14 @@ static enum fault_type get_fault_type(struct pt_regs *regs)
 		if (IS_ENABLED(CONFIG_PGSTE) &&
 		    test_pt_regs_flag(regs, PIF_GUEST_FAULT))
 			return GMAP_FAULT;
-		if (current->thread.mm_segment == USER_DS)
+		if (!current->thread.sacf_uaccess)
 			return USER_FAULT;
 		return KERNEL_FAULT;
 	}
 	if (trans_exc_code == 2) {
 		/* secondary space exception */
-		if (current->thread.mm_segment & 1) {
-			if (current->thread.mm_segment == USER_DS_SACF)
-				return USER_FAULT;
-			return KERNEL_FAULT;
-		}
+		if (current->thread.sacf_uaccess)
+			return USER_FAULT;
 		return VDSO_FAULT;
 	}
 	if (trans_exc_code == 1) {
diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c
index 11d2c8395e2a..0d748645694c 100644
--- a/arch/s390/mm/pgalloc.c
+++ b/arch/s390/mm/pgalloc.c
@@ -73,15 +73,14 @@ static void __crst_table_upgrade(void *arg)
 	/* we must change all active ASCEs to avoid the creation of new TLBs */
 	if (current->active_mm == mm) {
 		S390_lowcore.user_asce = mm->context.asce;
-		if (current->thread.mm_segment == USER_DS) {
-			__ctl_load(S390_lowcore.user_asce, 1, 1);
-			/* Mark user-ASCE present in CR1 */
-			clear_cpu_flag(CIF_ASCE_PRIMARY);
-		}
-		if (current->thread.mm_segment == USER_DS_SACF) {
+		if (current->thread.sacf_uaccess) {
 			__ctl_load(S390_lowcore.user_asce, 7, 7);
 			/* enable_sacf_uaccess does all or nothing */
 			WARN_ON(!test_cpu_flag(CIF_ASCE_SECONDARY));
+		} else {
+			__ctl_load(S390_lowcore.user_asce, 1, 1);
+			/* Mark user-ASCE present in CR1 */
+			clear_cpu_flag(CIF_ASCE_PRIMARY);
 		}
 	}
 	__tlb_flush_local();
diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c
index 401cf670a243..6fff2e5e27df 100644
--- a/arch/s390/pci/pci_mmio.c
+++ b/arch/s390/pci/pci_mmio.c
@@ -93,12 +93,12 @@ static inline int __memcpy_toio_inuser(void __iomem *dst,
 {
 	int size, rc = 0;
 	u8 status = 0;
-	mm_segment_t old_fs;
+	bool old;
 
 	if (!src)
 		return -EINVAL;
 
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	while (n > 0) {
 		size = zpci_get_max_write_size((u64 __force) dst,
 					       (u64 __force) src, n,
@@ -113,7 +113,7 @@ static inline int __memcpy_toio_inuser(void __iomem *dst,
 		dst += size;
 		n -= size;
 	}
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 	if (rc)
 		zpci_err_mmio(rc, status, (__force u64) dst);
 	return rc;
@@ -248,9 +248,9 @@ static inline int __memcpy_fromio_inuser(void __user *dst,
 {
 	int size, rc = 0;
 	u8 status;
-	mm_segment_t old_fs;
+	bool old;
 
-	old_fs = enable_sacf_uaccess();
+	old = enable_sacf_uaccess();
 	while (n > 0) {
 		size = zpci_get_max_write_size((u64 __force) src,
 					       (u64 __force) dst, n,
@@ -262,7 +262,7 @@ static inline int __memcpy_fromio_inuser(void __user *dst,
 		dst += size;
 		n -= size;
 	}
-	disable_sacf_uaccess(old_fs);
+	disable_sacf_uaccess(old);
 	if (rc)
 		zpci_err_mmio(rc, status, (__force u64) dst);
 	return rc;
-- 
2.17.1




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Kernel Development]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Info]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Linux Media]     [Device Mapper]

  Powered by Linux