Commit 15420269 authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Russell King (Oracle)
Browse files

ARM: 9179/1: uaccess: avoid alignment faults in copy_[from|to]_kernel_nofault



The helpers that are used to implement copy_from_kernel_nofault() and
copy_to_kernel_nofault() cast a void* to a pointer to a wider type,
which may result in alignment faults on ARM if the compiler decides to
use double-word or multiple-word load/store instructions.

Only configurations that define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
are affected, given that commit 2423de2e ("ARM: 9115/1: mm/maccess:
fix unaligned copy_{from,to}_kernel_nofault") ensures that dst and src
are sufficiently aligned otherwise.

So use the unaligned accessors for accessing dst and src in cases where
they may be misaligned.

Cc: <stable@vger.kernel.org> # depends on 2423de2e
Fixes: 2df4c9a7 ("ARM: 9112/1: uaccess: add __{get,put}_kernel_nofault")
Reviewed-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
Signed-off-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
parent 8b59b0a5
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/string.h>
#include <asm/memory.h>
#include <asm/domain.h>
#include <asm/unaligned.h>
#include <asm/unified.h>
#include <asm/compiler.h>

@@ -497,7 +498,10 @@ do { \
	}								\
	default: __err = __get_user_bad(); break;			\
	}								\
	*(type *)(dst) = __val;						\
	if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))		\
		put_unaligned(__val, (type *)(dst));			\
	else								\
		*(type *)(dst) = __val; /* aligned by caller */		\
	if (__err)							\
		goto err_label;						\
} while (0)
@@ -507,7 +511,9 @@ do { \
	const type *__pk_ptr = (dst);					\
	unsigned long __dst = (unsigned long)__pk_ptr;			\
	int __err = 0;							\
	type __val = *(type *)src;					\
	type __val = IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)	\
		     ? get_unaligned((type *)(src))			\
		     : *(type *)(src);	/* aligned by caller */		\
	switch (sizeof(type)) {						\
	case 1: __put_user_asm_byte(__val, __dst, __err, ""); break;	\
	case 2:	__put_user_asm_half(__val, __dst, __err, ""); break;	\