linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: linux-kernel@vger.kernel.org
Subject: [PATCH 14/45] C++: x86: Turn put_user(), get_user() & co. into inline template functions
Date: Sun, 01 Apr 2018 21:41:39 +0100	[thread overview]
Message-ID: <152261529959.30503.12922752484575508631.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <152261521484.30503.16131389653845029164.stgit@warthog.procyon.org.uk>

Turn put_user(), get_user() and similar functions into C++ inline template
functions as the source for this is simpler and more obvious and not
heavily macroised.

Note that it is unnecessary to stick an extension on the load or store
instruction that does the protected access to memory as the assembler can
work that out from the size of the source/destination register.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 arch/x86/include/asm/uaccess.h    |  630 ++++++++++++++++++++-----------------
 arch/x86/include/asm/uaccess_64.h |   66 +---
 2 files changed, 361 insertions(+), 335 deletions(-)

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index aae77eb8491c..64bd782c87c6 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -12,6 +12,10 @@
 #include <asm/smap.h>
 #include <asm/extable.h>
 
+/* FIXME: this hack is definitely wrong -AK */
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct __user *)(x))
+
 /*
  * The fs value determines whether argument validity checking should be
  * performed or not.  If get_fs() == USER_DS, checking is performed, with
@@ -101,6 +105,12 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
 	likely(!__range_not_ok(addr, size, user_addr_max()));		\
 })
 
+extern void __put_user_bad(void);
+extern void __get_user_unsupported_size(void)
+	__compiletime_error("Bad argument size for get_user");
+extern void __put_user_unsupported_size(void)
+	__compiletime_error("Bad argument size for put_user");
+
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
@@ -130,13 +140,6 @@ extern int __get_user_bad(void);
 	barrier_nospec();		\
 })
 
-/*
- * This is a type: either unsigned long, if the argument fits into
- * that type, or otherwise unsigned long long.
- */
-#define __inttype(x) \
-__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
-
 /**
  * get_user: - Get a simple variable from user space.
  * @x:   Variable to store result.
@@ -168,62 +171,21 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
  * Clang/LLVM cares about the size of the register, but still wants
  * the base register for something that ends up being a pair.
  */
-#define get_user(x, ptr)						\
-({									\
-	int __ret_gu;							\
-	register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX);		\
-	__chk_user_ptr(ptr);						\
-	might_fault();							\
-	asm volatile("call __get_user_%P4"				\
-		     : "=a" (__ret_gu), "=r" (__val_gu),		\
-			ASM_CALL_CONSTRAINT				\
-		     : "0" (ptr), "i" (sizeof(*(ptr))));		\
-	(x) = (__force __typeof__(*(ptr))) __val_gu;			\
-	__builtin_expect(__ret_gu, 0);					\
-})
-
-#define __put_user_x(size, x, ptr, __ret_pu)			\
-	asm volatile("call __put_user_" #size : "=a" (__ret_pu)	\
-		     : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
-
-
-
-#ifdef CONFIG_X86_32
-#define __put_user_asm_u64(x, addr, err, errret)			\
-	asm volatile("\n"						\
-		     "1:	movl %%eax,0(%2)\n"			\
-		     "2:	movl %%edx,4(%2)\n"			\
-		     "3:"						\
-		     ".section .fixup,\"ax\"\n"				\
-		     "4:	movl %3,%0\n"				\
-		     "	jmp 3b\n"					\
-		     ".previous\n"					\
-		     _ASM_EXTABLE(1b, 4b)				\
-		     _ASM_EXTABLE(2b, 4b)				\
-		     : "=r" (err)					\
-		     : "A" (x), "r" (addr), "i" (errret), "0" (err))
-
-#define __put_user_asm_ex_u64(x, addr)					\
-	asm volatile("\n"						\
-		     "1:	movl %%eax,0(%1)\n"			\
-		     "2:	movl %%edx,4(%1)\n"			\
-		     "3:"						\
-		     _ASM_EXTABLE_EX(1b, 2b)				\
-		     _ASM_EXTABLE_EX(2b, 3b)				\
-		     : : "A" (x), "r" (addr))
-
-#define __put_user_x8(x, ptr, __ret_pu)				\
-	asm volatile("call __put_user_8" : "=a" (__ret_pu)	\
-		     : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
-#else
-#define __put_user_asm_u64(x, ptr, retval, errret) \
-	__put_user_asm(x, ptr, retval, "q", "", "er", errret)
-#define __put_user_asm_ex_u64(x, addr)	\
-	__put_user_asm_ex(x, addr, "q", "", "er")
-#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
-#endif
-
-extern void __put_user_bad(void);
+template <typename VAL, typename TYPE>
+static inline int get_user(VAL &x, TYPE *ptr)
+{
+	register TYPE val asm("%" _ASM_DX);
+	int ret;
+
+	__chk_user_ptr(ptr);
+	might_fault();
+	asm volatile("call __get_user_%P4"
+		     : "=a" (ret), "=r" (val),
+			ASM_CALL_CONSTRAINT
+		     : "0" (ptr), "i" (sizeof(*(ptr))));
+	x = val;
+	return __builtin_expect(ret, 0);
+}
 
 /*
  * Strange magic calling convention: pointer in %ecx,
@@ -251,157 +213,47 @@ extern void __put_user_8(void);
  *
  * Returns zero on success, or -EFAULT on error.
  */
-#define put_user(x, ptr)					\
-({								\
-	int __ret_pu;						\
-	__typeof__(*(ptr)) __pu_val;				\
-	__chk_user_ptr(ptr);					\
-	might_fault();						\
-	__pu_val = x;						\
-	switch (sizeof(*(ptr))) {				\
-	case 1:							\
-		__put_user_x(1, __pu_val, ptr, __ret_pu);	\
-		break;						\
-	case 2:							\
-		__put_user_x(2, __pu_val, ptr, __ret_pu);	\
-		break;						\
-	case 4:							\
-		__put_user_x(4, __pu_val, ptr, __ret_pu);	\
-		break;						\
-	case 8:							\
-		__put_user_x8(__pu_val, ptr, __ret_pu);		\
-		break;						\
-	default:						\
-		__put_user_x(X, __pu_val, ptr, __ret_pu);	\
-		break;						\
-	}							\
-	__builtin_expect(__ret_pu, 0);				\
-})
-
-#define __put_user_size(x, ptr, size, retval, errret)			\
-do {									\
-	retval = 0;							\
-	__chk_user_ptr(ptr);						\
-	switch (size) {							\
-	case 1:								\
-		__put_user_asm(x, ptr, retval, "b", "b", "iq", errret);	\
-		break;							\
-	case 2:								\
-		__put_user_asm(x, ptr, retval, "w", "w", "ir", errret);	\
-		break;							\
-	case 4:								\
-		__put_user_asm(x, ptr, retval, "l", "k", "ir", errret);	\
-		break;							\
-	case 8:								\
-		__put_user_asm_u64((__typeof__(*ptr))(x), ptr, retval,	\
-				   errret);				\
-		break;							\
-	default:							\
-		__put_user_bad();					\
-	}								\
-} while (0)
-
-/*
- * This doesn't do __uaccess_begin/end - the exception handling
- * around it must do that.
- */
-#define __put_user_size_ex(x, ptr, size)				\
-do {									\
-	__chk_user_ptr(ptr);						\
-	switch (size) {							\
-	case 1:								\
-		__put_user_asm_ex(x, ptr, "b", "b", "iq");		\
-		break;							\
-	case 2:								\
-		__put_user_asm_ex(x, ptr, "w", "w", "ir");		\
-		break;							\
-	case 4:								\
-		__put_user_asm_ex(x, ptr, "l", "k", "ir");		\
-		break;							\
-	case 8:								\
-		__put_user_asm_ex_u64((__typeof__(*ptr))(x), ptr);	\
-		break;							\
-	default:							\
-		__put_user_bad();					\
-	}								\
-} while (0)
+template <typename VAL, typename TYPE>
+static inline int put_user(VAL x, TYPE *ptr)
+{
+	register TYPE val asm("%" _ASM_DX);
+	int ret;
 
+	__chk_user_ptr(ptr);
+	might_fault();
+	switch (sizeof(*(ptr))) {
+	case 8:
 #ifdef CONFIG_X86_32
-#define __get_user_asm_u64(x, ptr, retval, errret)			\
-({									\
-	__typeof__(ptr) __ptr = (ptr);					\
-	asm volatile("\n"					\
-		     "1:	movl %2,%%eax\n"			\
-		     "2:	movl %3,%%edx\n"			\
-		     "3:\n"				\
-		     ".section .fixup,\"ax\"\n"				\
-		     "4:	mov %4,%0\n"				\
-		     "	xorl %%eax,%%eax\n"				\
-		     "	xorl %%edx,%%edx\n"				\
-		     "	jmp 3b\n"					\
-		     ".previous\n"					\
-		     _ASM_EXTABLE(1b, 4b)				\
-		     _ASM_EXTABLE(2b, 4b)				\
-		     : "=r" (retval), "=&A"(x)				\
-		     : "m" (__m(__ptr)), "m" __m(((u32 __user *)(__ptr)) + 1),	\
-		       "i" (errret), "0" (retval));			\
-})
+		asm volatile("call __put_user_%8"
+			     : "=a" (ret), "=r" (val),
+			       ASM_CALL_CONSTRAINT
+			     : "A" (val), "c" (ptr)
+			     : "ebx");
+		break;
+#endif
+		/* Fall through */
+	case 1:
+	case 2:
+	case 4:
+		asm volatile("call __put_user_%P4"
+			     : "=a" (ret), "=r" (val),
+			       ASM_CALL_CONSTRAINT
+			     : "0" (val), "c" (ptr)
+			     : "ebx");
+		break;
+	default:
+		__put_user_unsupported_size();
+	}
+	return __builtin_expect(ret, 0);
+}
 
+#ifdef CONFIG_X86_32
 #define __get_user_asm_ex_u64(x, ptr)			(x) = __get_user_bad()
 #else
-#define __get_user_asm_u64(x, ptr, retval, errret) \
-	 __get_user_asm(x, ptr, retval, "q", "", "=r", errret)
 #define __get_user_asm_ex_u64(x, ptr) \
 	 __get_user_asm_ex(x, ptr, "q", "", "=r")
 #endif
 
-#define __get_user_size(x, ptr, size, retval, errret)			\
-do {									\
-	retval = 0;							\
-	__chk_user_ptr(ptr);						\
-	switch (size) {							\
-	case 1:								\
-		__get_user_asm(x, ptr, retval, "b", "b", "=q", errret);	\
-		break;							\
-	case 2:								\
-		__get_user_asm(x, ptr, retval, "w", "w", "=r", errret);	\
-		break;							\
-	case 4:								\
-		__get_user_asm(x, ptr, retval, "l", "k", "=r", errret);	\
-		break;							\
-	case 8:								\
-		__get_user_asm_u64(x, ptr, retval, errret);		\
-		break;							\
-	default:							\
-		(x) = __get_user_bad();					\
-	}								\
-} while (0)
-
-#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("\n"						\
-		     "1:	mov"itype" %2,%"rtype"1\n"		\
-		     "2:\n"						\
-		     ".section .fixup,\"ax\"\n"				\
-		     "3:	mov %3,%0\n"				\
-		     "	xor"itype" %"rtype"1,%"rtype"1\n"		\
-		     "	jmp 2b\n"					\
-		     ".previous\n"					\
-		     _ASM_EXTABLE(1b, 3b)				\
-		     : "=r" (err), ltype(x)				\
-		     : "m" (__m(addr)), "i" (errret), "0" (err))
-
-#define __get_user_asm_nozero(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("\n"						\
-		     "1:	mov"itype" %2,%"rtype"1\n"		\
-		     "2:\n"						\
-		     ".section .fixup,\"ax\"\n"				\
-		     "3:	mov %3,%0\n"				\
-		     "	jmp 2b\n"					\
-		     ".previous\n"					\
-		     _ASM_EXTABLE(1b, 3b)				\
-		     : "=r" (err), ltype(x)				\
-		     : "m" (__m(addr)), "i" (errret), "0" (err))
-
 /*
  * This doesn't do __uaccess_begin/end - the exception handling
  * around it must do that.
@@ -437,53 +289,6 @@ do {									\
 		     _ASM_EXTABLE_EX(1b, 3b)				\
 		     : ltype(x) : "m" (__m(addr)))
 
-#define __put_user_nocheck(x, ptr, size)			\
-({								\
-	int __pu_err;						\
-	__uaccess_begin();					\
-	__put_user_size((x), (ptr), (size), __pu_err, -EFAULT);	\
-	__uaccess_end();					\
-	__builtin_expect(__pu_err, 0);				\
-})
-
-#define __get_user_nocheck(x, ptr, size)				\
-({									\
-	int __gu_err;							\
-	__inttype(*(ptr)) __gu_val;					\
-	__uaccess_begin_nospec();					\
-	__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);	\
-	__uaccess_end();						\
-	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
-	__builtin_expect(__gu_err, 0);					\
-})
-
-/* FIXME: this hack is definitely wrong -AK */
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct __user *)(x))
-
-/*
- * Tell gcc we read from memory instead of writing: this is because
- * we do not write to any memory gcc knows about, so there are no
- * aliasing issues.
- */
-#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("\n"						\
-		     "1:	mov"itype" %"rtype"1,%2\n"		\
-		     "2:\n"						\
-		     ".section .fixup,\"ax\"\n"				\
-		     "3:	mov %3,%0\n"				\
-		     "	jmp 2b\n"					\
-		     ".previous\n"					\
-		     _ASM_EXTABLE(1b, 3b)				\
-		     : "=r"(err)					\
-		     : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
-
-#define __put_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile("1:	mov"itype" %"rtype"0,%1\n"		\
-		     "2:\n"						\
-		     _ASM_EXTABLE_EX(1b, 2b)				\
-		     : : ltype(x), "m" (__m(addr)))
-
 /*
  * uaccess_try and catch
  */
@@ -501,6 +306,111 @@ struct __large_struct { unsigned long buf[100]; };
 	(err) |= (current->thread.uaccess_err ? -EFAULT : 0);		\
 } while (0)
 
+/**
+ * __get_user_unsafe_nozero - Read a value from userspace with no uaccess check
+ */
+template <typename VAL, typename TYPE>
+static inline int __get_user_unsafe_nozero(VAL &x, const TYPE *ptr, int err=-EFAULT)
+{
+	TYPE val;
+	int ret = 0;
+
+	__chk_user_ptr(ptr);
+	switch (sizeof(TYPE)) {
+	case 8:
+#if __LONG_WIDTH__ == 32
+		asm volatile("\n"
+			     "1:	mov %2,%%eax\n"
+			     "2:	mov %3,%%edx\n"
+			     "3:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "4:	mov %4,%0\n"
+			     "		jmp 3b\n"
+			     ".previous\n"
+			     _ASM_EXTABLE(1b, 4b)
+			     _ASM_EXTABLE(2b, 4b)
+			     : "=r" (ret), "=&A"(val)
+			     : "m" (__m(ptr)),
+			       "m" (__m((const char *)ptr + 4)),
+			       "i" (err), "0" (ret));
+		break;
+#endif
+	case 1:
+	case 2:
+	case 4:
+		asm volatile("\n"
+			     "1:	mov %2,%1\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:	mov %3,%0\n"
+			     "		jmp 2b\n"
+			     ".previous\n"
+			     _ASM_EXTABLE(1b, 3b)
+			     : "=r" (ret), "=r"(val)
+			     : "m" (__m(ptr)), "i" (err), "0" (ret));
+		break;
+	default:
+		__get_user_unsupported_size();
+	}
+
+	x = val;
+	return __builtin_expect(ret, 0);
+}
+
+/**
+ * __get_user_unsafe - Read a value from userspace with no uaccess check
+ */
+template <typename VAL, typename TYPE>
+static inline int __get_user_unsafe(VAL &x, const TYPE *ptr, int err=-EFAULT)
+{
+	TYPE val;
+	int ret = 0;
+
+	__chk_user_ptr(ptr);
+	switch (sizeof(TYPE)) {
+	case 8:
+#if __LONG_WIDTH__ == 32
+		asm volatile("\n"
+			     "1:	mov %2,%%eax\n"
+			     "2:	mov %3,%%edx\n"
+			     "3:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "4:	mov %4,%0\n"
+			     "		xor %%eax,%%eax\n"
+			     "		xor %%edx,%%edx\n"
+			     "		jmp 3b\n"
+			     ".previous\n"
+			     _ASM_EXTABLE(1b, 4b)
+			     _ASM_EXTABLE(2b, 4b)
+			     : "=r" (ret), "=&A"(val)
+			     : "m" (__m(ptr)),
+			       "m" (__m((const char *)ptr + 4)),
+			       "i" (err), "0" (ret));
+		break;
+#endif
+	case 1:
+	case 2:
+	case 4:
+		asm volatile("\n"
+			     "1:	mov %2,%1\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:	mov %3,%0\n"
+			     "		xor %1,%1\n"
+			     "		jmp 2b\n"
+			     ".previous\n"
+			     _ASM_EXTABLE(1b, 3b)
+			     : "=r" (ret), "=r"(val)
+			     : "m" (__m(ptr)), "i" (err), "0" (ret));
+		break;
+	default:
+		__get_user_unsupported_size();
+	}
+
+	x = val;
+	return __builtin_expect(ret, 0);
+}
+
 /**
  * __get_user: - Get a simple variable from user space, with less checking.
  * @x:   Variable to store result.
@@ -509,9 +419,9 @@ struct __large_struct { unsigned long buf[100]; };
  * Context: User context only. This function may sleep if pagefaults are
  *          enabled.
  *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
+ * This function copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger data
+ * types like structures or arrays.
  *
  * @ptr must have pointer-to-simple-variable type, and the result of
  * dereferencing @ptr must be assignable to @x without a cast.
@@ -522,9 +432,68 @@ struct __large_struct { unsigned long buf[100]; };
  * Returns zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
+template <typename VAL, typename TYPE>
+static inline int __get_user(VAL &x, const TYPE *ptr)
+{
+	int ret;
 
-#define __get_user(x, ptr)						\
-	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
+	__uaccess_begin_nospec();
+	ret = __get_user_unsafe(x, ptr);
+	__uaccess_end();
+	return ret;
+}
+
+/**
+ * __put_user_unsafe - Copy a value to userspace with no uaccess check
+ */
+template <typename VAL, typename TYPE>
+static inline int __put_user_unsafe(VAL x, TYPE *ptr, int err=-EFAULT)
+{
+	TYPE val;
+	int ret = 0;
+
+	__chk_user_ptr(ptr);
+	switch (sizeof(TYPE)) {
+	case 8:
+#if __LONG_WIDTH__ == 32
+		asm volatile("\n"
+			     "1:	mov %%eax,%2\n"
+			     "2:	mov %%edx,%3\n"
+			     "3:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "4:	mov %4,%0\n"
+			     "		jmp 3b\n"
+			     ".previous\n"
+			     _ASM_EXTABLE(1b, 4b)
+			     _ASM_EXTABLE(2b, 4b)
+			     : "=r" (ret)
+			     : "A"(val),
+			       "m" (__m(ptr)),
+			       "m" (__m((const char *)ptr + 4)),
+			       "i" (err), "0" (ret));
+		break;
+#endif
+	case 1:
+	case 2:
+	case 4:
+		asm volatile("\n"
+			     "1:	mov %1,%2\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:	mov %3,%0\n"
+			     "		jmp 2b\n"
+			     ".previous\n"
+			     _ASM_EXTABLE(1b, 3b)
+			     : "=r" (ret), "=r"(val)
+			     : "m" (__m(ptr)), "i" (err), "0" (ret));
+		break;
+	default:
+		__put_user_unsupported_size();
+	}
+
+	x = val;
+	return __builtin_expect(ret, 0);
+}
 
 /**
  * __put_user: - Write a simple value into user space, with less checking.
@@ -546,32 +515,117 @@ struct __large_struct { unsigned long buf[100]; };
  *
  * Returns zero on success, or -EFAULT on error.
  */
+template <typename VAL, typename TYPE>
+static inline int __put_user(VAL x, TYPE *ptr, int err=-EFAULT)
+{
+	int ret;
 
-#define __put_user(x, ptr)						\
-	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+	__uaccess_begin();
+	ret = __put_user_unsafe(x, ptr, err);
+	__uaccess_end();
+	return ret;
+}
 
-/*
- * {get|put}_user_try and catch
+/**
+ * get_user_ex - Read a value from userspace with indirect error
  *
- * get_user_try {
- *	get_user_ex(...);
- * } get_user_catch(err)
+ * Use as:
+ *	get_user_try {
+ *		get_user_ex(...);
+ *	} get_user_catch(err)
  */
+template <typename VAL, typename TYPE>
+static inline void get_user_ex(VAL &x, const TYPE *ptr)
+{
+	TYPE val;
+
+	__chk_user_ptr(ptr);
+	switch (sizeof(TYPE)) {
+	case 8:
+#if __LONG_WIDTH__ == 32
+		asm volatile("\n"
+			     "1:	mov %1,%%eax\n"
+			     "2:	mov %2,%%edx\n"
+			     "3:\n"
+			     _ASM_EXTABLE(1b, 3b)
+			     _ASM_EXTABLE(2b, 3b)
+			     : "=&A"(val)
+			     : "m" (__m(ptr)),
+			       "m" (__m((const char *)ptr + 4)));
+		break;
+#endif
+	case 1:
+	case 2:
+	case 4:
+		asm volatile("\n"
+			     "1:	mov %1,%0\n"
+			     "2:\n"
+			     _ASM_EXTABLE(1b, 2b)
+			     : "=r"(val)
+			     : "m" (__m(ptr)));
+		break;
+	default:
+		__get_user_unsupported_size();
+	}
+
+	x = val;
+}
 #define get_user_try		uaccess_try_nospec
 #define get_user_catch(err)	uaccess_catch(err)
 
-#define get_user_ex(x, ptr)	do {					\
-	unsigned long __gue_val;					\
-	__get_user_size_ex((__gue_val), (ptr), (sizeof(*(ptr))));	\
-	(x) = (__force __typeof__(*(ptr)))__gue_val;			\
-} while (0)
+/**
+ * put_user_ex - Copy a value to userspace with indirect error
+ *
+ * Use as:
+ *	put_user_try {
+ *		put_user_ex(...);
+ *	} put_user_catch(err)
+ */
+template <typename VAL, typename TYPE>
+static inline void put_user_ex(VAL x, TYPE *ptr)
+{
+	TYPE val;
+
+
+	/* We tell gcc that we're reading from memory instead of writing: this
+	 * is because we do not write to any memory gcc knows about, so there
+	 * are no aliasing issues.
+	 */
+	__chk_user_ptr(ptr);
+	switch (sizeof(TYPE)) {
+	case 8:
+#if __LONG_WIDTH__ == 32
+		asm volatile("\n"
+			     "1:	mov %%eax,%1\n"
+			     "2:	mov %%edx,%2\n"
+			     "3:\n"
+			     _ASM_EXTABLE(1b, 3b)
+			     _ASM_EXTABLE(2b, 3b)
+			     :
+			     : "A"(val),
+			       "m" (__m(ptr)),
+			       "m" (__m((const char *)ptr + 4)));
+		break;
+#endif
+	case 1:
+	case 2:
+	case 4:
+		asm volatile("\n"
+			     "1:	mov %0,%1\n"
+			     "2:\n"
+			     ".previous\n"
+			     _ASM_EXTABLE(1b, 2b)
+			     :
+			     : "=r"(val), "m" (__m(ptr)));
+		break;
+	default:
+		__put_user_unsupported_size();
+	}
+}
 
 #define put_user_try		uaccess_try
 #define put_user_catch(err)	uaccess_catch(err)
 
-#define put_user_ex(x, ptr)						\
-	__put_user_size_ex((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
-
 extern unsigned long
 copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
 extern __must_check long
@@ -711,22 +765,20 @@ extern struct movsl_mask {
 #define user_access_begin()	__uaccess_begin()
 #define user_access_end()	__uaccess_end()
 
-#define unsafe_put_user(x, ptr, err_label)					\
-do {										\
-	int __pu_err;								\
-	__typeof__(*(ptr)) __pu_val = (x);					\
-	__put_user_size(__pu_val, (ptr), sizeof(*(ptr)), __pu_err, -EFAULT);	\
-	if (unlikely(__pu_err)) goto err_label;					\
-} while (0)
-
-#define unsafe_get_user(x, ptr, err_label)					\
-do {										\
-	int __gu_err;								\
-	__inttype(*(ptr)) __gu_val;						\
-	__get_user_size(__gu_val, (ptr), sizeof(*(ptr)), __gu_err, -EFAULT);	\
-	(x) = (__force __typeof__(*(ptr)))__gu_val;				\
-	if (unlikely(__gu_err)) goto err_label;					\
-} while (0)
+#define unsafe_put_user(x, ptr, err_label)				\
+	do {								\
+		int __pu_err;						\
+		__pu_err = __put_user_unsafe(x, ptr);			\
+		if (unlikely(__gu_err))					\
+			goto err_label;					\
+	} while (0)
+
+#define unsafe_get_user(x, ptr, err_label)				\
+	do {								\
+		int __gu_err;						\
+		__gu_err = __get_user_unsafe(x, ptr);			\
+		if (unlikely(__gu_err))					\
+			goto err_label;					\
+	} while (0)
 
 #endif /* _ASM_X86_UACCESS_H */
-
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index 62546b3a398e..24bf7d0a21b6 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -56,46 +56,40 @@ raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
 	switch (size) {
 	case 1:
 		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u8 *)dst, (u8 __user *)src,
-			      ret, "b", "b", "=q", 1);
+		ret = __get_user_unsafe_nozero(*(u8 *)dst, (u8 __user *)src, 1);
 		__uaccess_end();
 		return ret;
 	case 2:
 		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u16 *)dst, (u16 __user *)src,
-			      ret, "w", "w", "=r", 2);
+		ret = __get_user_unsafe_nozero(*(u16 *)dst, (u16 __user *)src, 2);
 		__uaccess_end();
 		return ret;
 	case 4:
 		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u32 *)dst, (u32 __user *)src,
-			      ret, "l", "k", "=r", 4);
+		ret = __get_user_unsafe_nozero(*(u32 *)dst, (u32 __user *)src, 4);
 		__uaccess_end();
 		return ret;
 	case 8:
 		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
-			      ret, "q", "", "=r", 8);
+		ret = __get_user_unsafe_nozero(*(u64 *)dst, (u64 __user *)src, 8);
 		__uaccess_end();
 		return ret;
 	case 10:
 		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
-			       ret, "q", "", "=r", 10);
+		ret = __get_user_unsafe_nozero(*(u64 *)dst, (u64 __user *)src, 10);
 		if (likely(!ret))
-			__get_user_asm_nozero(*(u16 *)(8 + (char *)dst),
-				       (u16 __user *)(8 + (char __user *)src),
-				       ret, "w", "w", "=r", 2);
+			ret = __get_user_unsafe_nozero(
+				*(u16 *)(8 + (char *)dst),
+				(u16 __user *)(8 + (char __user *)src), 2);
 		__uaccess_end();
 		return ret;
 	case 16:
 		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
-			       ret, "q", "", "=r", 16);
+		ret = __get_user_unsafe_nozero(*(u64 *)dst, (u64 __user *)src, 16);
 		if (likely(!ret))
-			__get_user_asm_nozero(*(u64 *)(8 + (char *)dst),
-				       (u64 __user *)(8 + (char __user *)src),
-				       ret, "q", "", "=r", 8);
+			ret = __get_user_unsafe_nozero(
+				*(u64 *)(8 + (char *)dst),
+				(u64 __user *)(8 + (char __user *)src), 8);
 		__uaccess_end();
 		return ret;
 	default:
@@ -112,48 +106,28 @@ raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
 		return copy_user_generic((__force void *)dst, src, size);
 	switch (size) {
 	case 1:
-		__uaccess_begin();
-		__put_user_asm(*(u8 *)src, (u8 __user *)dst,
-			      ret, "b", "b", "iq", 1);
-		__uaccess_end();
-		return ret;
+		return __put_user(*(u8 *)src, (u8 __user *)dst, 1);
 	case 2:
-		__uaccess_begin();
-		__put_user_asm(*(u16 *)src, (u16 __user *)dst,
-			      ret, "w", "w", "ir", 2);
-		__uaccess_end();
-		return ret;
+		return __put_user(*(u16 *)src, (u16 __user *)dst, 2);
 	case 4:
-		__uaccess_begin();
-		__put_user_asm(*(u32 *)src, (u32 __user *)dst,
-			      ret, "l", "k", "ir", 4);
-		__uaccess_end();
-		return ret;
+		return __put_user(*(u32 *)src, (u32 __user *)dst, 4);
 	case 8:
-		__uaccess_begin();
-		__put_user_asm(*(u64 *)src, (u64 __user *)dst,
-			      ret, "q", "", "er", 8);
-		__uaccess_end();
-		return ret;
+		return __put_user(*(u64 *)src, (u64 __user *)dst, 8);
 	case 10:
 		__uaccess_begin();
-		__put_user_asm(*(u64 *)src, (u64 __user *)dst,
-			       ret, "q", "", "er", 10);
+		ret = __put_user_unsafe(*(u64 *)src, (u64 __user *)dst, 10);
 		if (likely(!ret)) {
 			asm("":::"memory");
-			__put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
-				       ret, "w", "w", "ir", 2);
+			ret = __put_user_unsafe(4[(u16 *)src], 4 + (u16 __user *)dst, 2);
 		}
 		__uaccess_end();
 		return ret;
 	case 16:
 		__uaccess_begin();
-		__put_user_asm(*(u64 *)src, (u64 __user *)dst,
-			       ret, "q", "", "er", 16);
+		ret =__put_user_unsafe(*(u64 *)src, (u64 __user *)dst, 16);
 		if (likely(!ret)) {
 			asm("":::"memory");
-			__put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
-				       ret, "q", "", "er", 8);
+			ret = __put_user_unsafe(1[(u64 *)src], 1 + (u64 __user *)dst, 8);
 		}
 		__uaccess_end();
 		return ret;

  parent reply	other threads:[~2018-04-01 20:41 UTC|newest]

Thread overview: 98+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-01 20:40 [PATCH 00/45] C++: Convert the kernel to C++ David Howells
2018-04-01 20:40 ` [PATCH 01/45] Use UINT_MAX, not -1, to represent an invalid UID, GID or project ID David Howells
2018-04-01 23:04   ` Randy Dunlap
2018-04-01 20:40 ` [PATCH 02/45] Fix exception_enter() return value David Howells
2018-04-05  1:34   ` Sasha Levin
2018-04-01 20:40 ` [PATCH 03/45] Fix loop var in be32_to_cpu_array() and cpu_to_be32_array() David Howells
2018-04-01 20:40 ` [PATCH 04/45] Fix use of ACPI_COMPANION_SET() David Howells
2018-04-01 20:40 ` [PATCH 05/45] C++: Set compilation as C++ for .c files David Howells
2018-04-02  6:10   ` kbuild test robot
2018-04-02  6:10   ` kbuild test robot
2018-04-03 13:16   ` David Howells
2018-04-03 13:27     ` Fengguang Wu
2018-04-10  8:44     ` David Howells
2018-04-10  9:45       ` Fengguang Wu
2018-04-11  1:13         ` Li, Philip
2018-04-01 20:40 ` [PATCH 06/45] C++: Do some basic C++ type definition David Howells
2018-04-02  4:37   ` kbuild test robot
2018-04-02  6:10   ` kbuild test robot
2018-04-01 20:40 ` [PATCH 07/45] C++: Define a header with some C++ type traits for type checking David Howells
2018-04-02  7:00   ` kbuild test robot
2018-04-01 20:41 ` [PATCH 08/45] C++: Implement abs() as an inline template function David Howells
2018-04-01 20:41 ` [PATCH 09/45] C++: x86: Fix the x86 syscall table production for C++ David Howells
2018-04-02  7:57   ` kbuild test robot
2018-04-01 20:41 ` [PATCH 10/45] C++: x86: Turn xchg(), xadd() & co. into inline template functions David Howells
2018-04-01 20:41 ` [PATCH 11/45] C++: x86: Turn cmpxchg() " David Howells
2018-04-01 20:41 ` [PATCH 12/45] C++: x86: Turn cmpxchg_double() " David Howells
2018-04-01 20:41 ` [PATCH 13/45] C++: x86: Turn cmpxchg64() " David Howells
2018-04-01 20:41 ` David Howells [this message]
2018-04-01 20:41 ` [PATCH 15/45] C++: Need space between string and symbol David Howells
2018-04-01 20:41 ` [PATCH 16/45] C++: Disable VERIFY_OCTAL_PERMISSIONS() for the moment David Howells
2018-04-01 20:41 ` [PATCH 17/45] C++: Turn READ_ONCE(), WRITE_ONCE() & co. into inline template functions David Howells
2018-04-01 20:42 ` [PATCH 18/45] C++: Turn RCU accessors " David Howells
2018-04-01 20:42 ` [PATCH 19/45] C++: Turn ktime_add/sub_ns() " David Howells
2018-04-01 20:42 ` [PATCH 20/45] C++: init/main: Constify pointers David Howells
2018-04-01 20:42 ` [PATCH 21/45] C++: Set the type of atomic64_t to s64 David Howells
2018-04-01 20:42 ` [PATCH 22/45] C++: Define apic_intr_mode after the enum definition, not before David Howells
2018-04-01 20:42 ` [PATCH 23/45] C++: Don't do "extern asmlinkage" David Howells
2018-04-01 20:42 ` [PATCH 24/45] C++: Fix BUILD_BUG_ON_ZERO() David Howells
2018-04-01 20:42 ` [PATCH 25/45] C++: Fix void variables David Howells
2018-04-01 20:42 ` [PATCH 26/45] C++: Can't have variable/member names the same as typedef names David Howells
2018-04-01 20:42 ` [PATCH 27/45] C++: Disable __same_type() for the moment David Howells
2018-04-01 20:43 ` [PATCH 28/45] C++: Move ctx_state enum out of struct context_tracking David Howells
2018-04-01 20:43 ` [PATCH 29/45] C++: Move the print_line_t enum before first use David Howells
2018-04-01 20:43 ` [PATCH 30/45] C++: Include linux/hrtimer.h from linux/timer.h David Howells
2018-04-01 20:43 ` [PATCH 31/45] C++: Avoid using 'compl' and 'and' as names David Howells
2018-04-02  7:57   ` kbuild test robot
2018-04-01 20:43 ` [PATCH 32/45] C++: __to_fd() needs to reduce the size of v for struct fd::flags David Howells
2018-04-01 20:43 ` [PATCH 33/45] C++: Move irqchip_irq_state enum David Howells
2018-04-01 20:43 ` [PATCH 34/45] C++: Fix up use of LIST_POISON* David Howells
2018-04-01 20:43 ` [PATCH 35/45] C++: Fix static_branch_likely/unlikely() David Howells
2018-04-01 20:43 ` [PATCH 36/45] C++: Fix kernfs_type() int->enum David Howells
2018-04-01 20:43 ` [PATCH 37/45] C++: Fix page_zonenum() int->enum David Howells
2018-04-01 20:44 ` [PATCH 38/45] C++: mutex_trylock_recursive_enum() int->enum David Howells
2018-04-01 23:10   ` Randy Dunlap
2018-04-01 20:44 ` [PATCH 39/45] C++: Fix spinlock initialisation David Howells
2018-04-01 20:44 ` [PATCH 40/45] C++: Fix sema_init() David Howells
2018-04-01 20:44 ` [PATCH 41/45] C++: Cast in bitops David Howells
2018-04-02  6:10   ` kbuild test robot
2018-04-01 20:44 ` [PATCH 42/45] C++: Hide C++ keywords David Howells
2018-04-02  7:32   ` kbuild test robot
2018-04-01 20:44 ` [PATCH 43/45] C++: Don't need to declare struct pgd_t after typedef David Howells
2018-04-01 20:44 ` [PATCH 44/45] C++: Can't declare unsized-array in struct cgroup David Howells
2018-04-01 20:44 ` [PATCH 45/45] C++: Move initcall_level_names[] to __initdata section David Howells
2018-04-01 22:20 ` [PATCH 00/45] C++: Convert the kernel to C++ Randy Dunlap
2018-04-02  9:28 ` Vegard Nossum
2024-01-09 19:57 ` H. Peter Anvin
2024-01-09 23:29   ` Andrew Pinski
2024-01-11 21:01     ` Arsen Arsenović
2024-01-10  0:29   ` David Howells
2024-01-10  8:58   ` Jiri Slaby
2024-01-10 13:04     ` Neal Gompa
2024-01-10 15:52       ` Jason Gunthorpe
2024-01-10 16:05         ` H. Peter Anvin
2024-01-10 16:25         ` Neal Gompa
2024-01-10 17:57           ` Theodore Ts'o
2024-01-12  2:23             ` H. Peter Anvin
2024-01-12  2:52               ` Kent Overstreet
2024-01-11  8:06       ` Andreas Herrmann
2024-01-10 15:01   ` Michael de Lang
     [not found]     ` <69fe1c0c-b5ec-4031-b719-d9c14742929c@metux.net>
2024-01-12 21:58       ` Michael de Lang
2024-01-11  4:24   ` John Hubbard
2024-01-11  5:09     ` Dave Airlie
2024-01-11 15:24       ` Eric Curtin
2024-01-11 21:37       ` David Laight
2024-01-11 12:39   ` Chris Down
2024-01-11 19:40     ` David Laight
2024-01-24  6:53       ` Jiri Slaby
2024-01-12  2:54   ` H. Peter Anvin
2024-01-12  8:52   ` David Howells
2024-01-12 23:53     ` H. Peter Anvin
2024-01-09 23:40 ` David Howells
2024-01-10  7:13   ` Alexey Dobriyan
2024-01-12  2:25   ` H. Peter Anvin
2024-01-12  2:40   ` H. Peter Anvin
2024-01-11 23:09 ` Arsen Arsenović
2024-01-12  9:20 ` David Howells
2024-01-12 21:35   ` Arsen Arsenović
2024-01-12 23:41   ` David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=152261529959.30503.12922752484575508631.stgit@warthog.procyon.org.uk \
    --to=dhowells@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).