Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4504c5cc authored by Mark Rutland's avatar Mark Rutland Committed by Greg Kroah-Hartman
Browse files

arm64: uaccess: Mask __user pointers for __arch_{clear, copy_*}_user




From: Will Deacon <will.deacon@arm.com>

commit f71c2ffcb20dd8626880747557014bb9a61eb90e upstream.

Like we've done for get_user and put_user, ensure that user pointers
are masked before invoking the underlying __arch_{clear,copy_*}_user
operations.

Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
[v4.9: fixup for v4.9-style uaccess primitives]
Signed-off-by: Mark Rutland <mark.rutland@arm.com> [v4.9 backport]
Tested-by: default avatarGreg Hackmann <ghackmann@google.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4c03928f
Loading
Loading
Loading
Loading
+10 −8
Original line number Original line Diff line number Diff line
@@ -313,21 +313,20 @@ do { \


extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n);
extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n);
extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n);
extern unsigned long __must_check __arch_copy_in_user(void __user *to, const void __user *from, unsigned long n);
extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);


static inline unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n)
static inline unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n)
{
{
	kasan_check_write(to, n);
	kasan_check_write(to, n);
	check_object_size(to, n, false);
	check_object_size(to, n, false);
	return __arch_copy_from_user(to, from, n);
	return __arch_copy_from_user(to, __uaccess_mask_ptr(from), n);
}
}


static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n)
static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n)
{
{
	kasan_check_read(from, n);
	kasan_check_read(from, n);
	check_object_size(from, n, true);
	check_object_size(from, n, true);
	return __arch_copy_to_user(to, from, n);
	return __arch_copy_to_user(__uaccess_mask_ptr(to), from, n);
}
}


static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
@@ -355,22 +354,25 @@ static inline unsigned long __must_check copy_to_user(void __user *to, const voi
	return n;
	return n;
}
}


static inline unsigned long __must_check copy_in_user(void __user *to, const void __user *from, unsigned long n)
static inline unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n)
{
{
	if (access_ok(VERIFY_READ, from, n) && access_ok(VERIFY_WRITE, to, n))
	if (access_ok(VERIFY_READ, from, n) && access_ok(VERIFY_WRITE, to, n))
		n = __copy_in_user(to, from, n);
		n = __arch_copy_in_user(__uaccess_mask_ptr(to), __uaccess_mask_ptr(from), n);
	return n;
	return n;
}
}
#define copy_in_user __copy_in_user


#define __copy_to_user_inatomic __copy_to_user
#define __copy_to_user_inatomic __copy_to_user
#define __copy_from_user_inatomic __copy_from_user
#define __copy_from_user_inatomic __copy_from_user


static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
extern unsigned long __must_check __arch_clear_user(void __user *to, unsigned long n);
static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n)
{
{
	if (access_ok(VERIFY_WRITE, to, n))
	if (access_ok(VERIFY_WRITE, to, n))
		n = __clear_user(__uaccess_mask_ptr(to), n);
		n = __arch_clear_user(__uaccess_mask_ptr(to), n);
	return n;
	return n;
}
}
#define clear_user	__clear_user


extern long strncpy_from_user(char *dest, const char __user *src, long count);
extern long strncpy_from_user(char *dest, const char __user *src, long count);


+2 −2
Original line number Original line Diff line number Diff line
@@ -37,8 +37,8 @@ EXPORT_SYMBOL(clear_page);
	/* user mem (segment) */
	/* user mem (segment) */
EXPORT_SYMBOL(__arch_copy_from_user);
EXPORT_SYMBOL(__arch_copy_from_user);
EXPORT_SYMBOL(__arch_copy_to_user);
EXPORT_SYMBOL(__arch_copy_to_user);
EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(__arch_clear_user);
EXPORT_SYMBOL(__copy_in_user);
EXPORT_SYMBOL(__arch_copy_in_user);


	/* physical memory */
	/* physical memory */
EXPORT_SYMBOL(memstart_addr);
EXPORT_SYMBOL(memstart_addr);
+3 −3
Original line number Original line Diff line number Diff line
@@ -24,7 +24,7 @@


	.text
	.text


/* Prototype: int __clear_user(void *addr, size_t sz)
/* Prototype: int __arch_clear_user(void *addr, size_t sz)
 * Purpose  : clear some user memory
 * Purpose  : clear some user memory
 * Params   : addr - user memory address to clear
 * Params   : addr - user memory address to clear
 *          : sz   - number of bytes to clear
 *          : sz   - number of bytes to clear
@@ -32,7 +32,7 @@
 *
 *
 * Alignment fixed up by hardware.
 * Alignment fixed up by hardware.
 */
 */
ENTRY(__clear_user)
ENTRY(__arch_clear_user)
ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
	    CONFIG_ARM64_PAN)
	    CONFIG_ARM64_PAN)
	mov	x2, x1			// save the size for fixup return
	mov	x2, x1			// save the size for fixup return
@@ -57,7 +57,7 @@ uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
	    CONFIG_ARM64_PAN)
	    CONFIG_ARM64_PAN)
	ret
	ret
ENDPROC(__clear_user)
ENDPROC(__arch_clear_user)


	.section .fixup,"ax"
	.section .fixup,"ax"
	.align	2
	.align	2
+2 −2
Original line number Original line Diff line number Diff line
@@ -67,7 +67,7 @@
	.endm
	.endm


end	.req	x5
end	.req	x5
ENTRY(__copy_in_user)
ENTRY(__arch_copy_in_user)
ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
	    CONFIG_ARM64_PAN)
	    CONFIG_ARM64_PAN)
	add	end, x0, x2
	add	end, x0, x2
@@ -76,7 +76,7 @@ ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
	    CONFIG_ARM64_PAN)
	    CONFIG_ARM64_PAN)
	mov	x0, #0
	mov	x0, #0
	ret
	ret
ENDPROC(__copy_in_user)
ENDPROC(__arch_copy_in_user)


	.section .fixup,"ax"
	.section .fixup,"ax"
	.align	2
	.align	2