forked from Minki/linux
ARM: fix uaccess_with_memcpy() with SW_DOMAIN_PAN
The uaccess_with_memcpy() code is currently incompatible with the SW PAN code: it takes locks within the region that we've changed the DACR, potentially sleeping as a result. As we do not save and restore the DACR across co-operative sleep events, can lead to an incorrect DACR value later in this code path. Reported-by: Peter Rosin <peda@axentia.se> Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
77f1b959b0
commit
c014953d84
@ -510,10 +510,14 @@ __copy_to_user_std(void __user *to, const void *from, unsigned long n);
|
|||||||
static inline unsigned long __must_check
|
static inline unsigned long __must_check
|
||||||
__copy_to_user(void __user *to, const void *from, unsigned long n)
|
__copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||||
{
|
{
|
||||||
|
#ifndef CONFIG_UACCESS_WITH_MEMCPY
|
||||||
unsigned int __ua_flags = uaccess_save_and_enable();
|
unsigned int __ua_flags = uaccess_save_and_enable();
|
||||||
n = arm_copy_to_user(to, from, n);
|
n = arm_copy_to_user(to, from, n);
|
||||||
uaccess_restore(__ua_flags);
|
uaccess_restore(__ua_flags);
|
||||||
return n;
|
return n;
|
||||||
|
#else
|
||||||
|
return arm_copy_to_user(to, from, n);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
extern unsigned long __must_check
|
extern unsigned long __must_check
|
||||||
|
@ -88,6 +88,7 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
|
|||||||
static unsigned long noinline
|
static unsigned long noinline
|
||||||
__copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
|
__copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
|
||||||
{
|
{
|
||||||
|
unsigned long ua_flags;
|
||||||
int atomic;
|
int atomic;
|
||||||
|
|
||||||
if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
|
if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
|
||||||
@ -118,7 +119,9 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
|
|||||||
if (tocopy > n)
|
if (tocopy > n)
|
||||||
tocopy = n;
|
tocopy = n;
|
||||||
|
|
||||||
|
ua_flags = uaccess_save_and_enable();
|
||||||
memcpy((void *)to, from, tocopy);
|
memcpy((void *)to, from, tocopy);
|
||||||
|
uaccess_restore(ua_flags);
|
||||||
to += tocopy;
|
to += tocopy;
|
||||||
from += tocopy;
|
from += tocopy;
|
||||||
n -= tocopy;
|
n -= tocopy;
|
||||||
@ -145,14 +148,21 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n)
|
|||||||
* With frame pointer disabled, tail call optimization kicks in
|
* With frame pointer disabled, tail call optimization kicks in
|
||||||
* as well making this test almost invisible.
|
* as well making this test almost invisible.
|
||||||
*/
|
*/
|
||||||
if (n < 64)
|
if (n < 64) {
|
||||||
return __copy_to_user_std(to, from, n);
|
unsigned long ua_flags = uaccess_save_and_enable();
|
||||||
return __copy_to_user_memcpy(to, from, n);
|
n = __copy_to_user_std(to, from, n);
|
||||||
|
uaccess_restore(ua_flags);
|
||||||
|
} else {
|
||||||
|
n = __copy_to_user_memcpy(to, from, n);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long noinline
|
static unsigned long noinline
|
||||||
__clear_user_memset(void __user *addr, unsigned long n)
|
__clear_user_memset(void __user *addr, unsigned long n)
|
||||||
{
|
{
|
||||||
|
unsigned long ua_flags;
|
||||||
|
|
||||||
if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
|
if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
|
||||||
memset((void *)addr, 0, n);
|
memset((void *)addr, 0, n);
|
||||||
return 0;
|
return 0;
|
||||||
@ -175,7 +185,9 @@ __clear_user_memset(void __user *addr, unsigned long n)
|
|||||||
if (tocopy > n)
|
if (tocopy > n)
|
||||||
tocopy = n;
|
tocopy = n;
|
||||||
|
|
||||||
|
ua_flags = uaccess_save_and_enable();
|
||||||
memset((void *)addr, 0, tocopy);
|
memset((void *)addr, 0, tocopy);
|
||||||
|
uaccess_restore(ua_flags);
|
||||||
addr += tocopy;
|
addr += tocopy;
|
||||||
n -= tocopy;
|
n -= tocopy;
|
||||||
|
|
||||||
@ -193,9 +205,14 @@ out:
|
|||||||
unsigned long arm_clear_user(void __user *addr, unsigned long n)
|
unsigned long arm_clear_user(void __user *addr, unsigned long n)
|
||||||
{
|
{
|
||||||
/* See rational for this in __copy_to_user() above. */
|
/* See rational for this in __copy_to_user() above. */
|
||||||
if (n < 64)
|
if (n < 64) {
|
||||||
return __clear_user_std(addr, n);
|
unsigned long ua_flags = uaccess_save_and_enable();
|
||||||
return __clear_user_memset(addr, n);
|
n = __clear_user_std(addr, n);
|
||||||
|
uaccess_restore(ua_flags);
|
||||||
|
} else {
|
||||||
|
n = __clear_user_memset(addr, n);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
Loading…
Reference in New Issue
Block a user