Commit 8524e2e7 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman
Browse files

powerpc/uaccess: Perform barrier_nospec() in KUAP allowance helpers



barrier_nospec() in uaccess helpers is there to protect against
speculative accesses around access_ok().

When using user_access_begin() sequences together with
unsafe_get_user() like macros, barrier_nospec() is called for
every single read although we know the access_ok() is done
onece.

Since all user accesses must be granted by a call to either
allow_read_from_user() or allow_read_write_user() which will
always happen after the access_ok() check, move the barrier_nospec()
there.

Reported-by: default avatarChristopher M. Riedl <cmr@codefail.de>
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/c72f014730823b413528e90ab6c4d3bcb79f8497.1612692067.git.christophe.leroy@csgroup.eu
parent 22b89ba1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ static __always_inline void setup_kup(void)

static inline void allow_read_from_user(const void __user *from, unsigned long size)
{
	barrier_nospec();
	allow_user_access(NULL, from, size, KUAP_READ);
}

@@ -102,6 +103,7 @@ static inline void allow_write_to_user(void __user *to, unsigned long size)
static inline void allow_read_write_user(void __user *to, const void __user *from,
					 unsigned long size)
{
	barrier_nospec();
	allow_user_access(to, from, size, KUAP_READ_WRITE);
}

+1 −11
Original line number Diff line number Diff line
@@ -315,7 +315,6 @@ do { \
	__chk_user_ptr(__gu_addr);				\
	if (!is_kernel_addr((unsigned long)__gu_addr))		\
		might_fault();					\
	barrier_nospec();					\
	if (do_allow)								\
		__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err);	\
	else									\
@@ -333,10 +332,8 @@ do { \
	__typeof__(size) __gu_size = (size);				\
									\
	might_fault();							\
	if (access_ok(__gu_addr, __gu_size)) {				\
		barrier_nospec();					\
	if (access_ok(__gu_addr, __gu_size))				\
		__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \
	}								\
	(x) = (__force __typeof__(*(ptr)))__gu_val;				\
									\
	__gu_err;							\
@@ -350,7 +347,6 @@ do { \
	__typeof__(size) __gu_size = (size);			\
								\
	__chk_user_ptr(__gu_addr);				\
	barrier_nospec();					\
	__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \
	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
								\
@@ -395,7 +391,6 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
{
	unsigned long ret;

	barrier_nospec();
	allow_read_write_user(to, from, n);
	ret = __copy_tofrom_user(to, from, n);
	prevent_read_write_user(to, from, n);
@@ -412,19 +407,15 @@ static inline unsigned long raw_copy_from_user(void *to,

		switch (n) {
		case 1:
			barrier_nospec();
			__get_user_size(*(u8 *)to, from, 1, ret);
			break;
		case 2:
			barrier_nospec();
			__get_user_size(*(u16 *)to, from, 2, ret);
			break;
		case 4:
			barrier_nospec();
			__get_user_size(*(u32 *)to, from, 4, ret);
			break;
		case 8:
			barrier_nospec();
			__get_user_size(*(u64 *)to, from, 8, ret);
			break;
		}
@@ -432,7 +423,6 @@ static inline unsigned long raw_copy_from_user(void *to,
			return 0;
	}

	barrier_nospec();
	allow_read_from_user(from, n);
	ret = __copy_tofrom_user((__force void __user *)to, from, n);
	prevent_read_from_user(from, n);