Commit 597399d0 authored by Will Deacon's avatar Will Deacon

arm64: tags: Preserve tags for addresses translated via TTBR1

Sign-extending TTBR1 addresses when converting to an untagged address
breaks the documented POSIX semantics for mlock() in some obscure error
cases where we end up returning -EINVAL instead of -ENOMEM as a direct
result of rewriting the upper address bits.

Rework the untagged_addr() macro to preserve the upper address bits for
TTBR1 addresses and only clear the tag bits for user addresses. This
matches the behaviour of the 'clear_address_tag' assembly macro, so
rename that and align the implementations at the same time so that they
use the same instruction sequences for the tag manipulation.

Link: https://lore.kernel.org/stable/20191014162651.GF19200@arrakis.emea.arm.com/Reported-by: default avatarJan Stancek <jstancek@redhat.com>
Tested-by: default avatarJan Stancek <jstancek@redhat.com>
Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Tested-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Reviewed-by: default avatarVincenzo Frascino <vincenzo.frascino@arm.com>
Tested-by: default avatarVincenzo Frascino <vincenzo.frascino@arm.com>
Reviewed-by: default avatarAndrey Konovalov <andreyknvl@google.com>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 38137335
...@@ -78,10 +78,9 @@ alternative_else_nop_endif ...@@ -78,10 +78,9 @@ alternative_else_nop_endif
/* /*
* Remove the address tag from a virtual address, if present. * Remove the address tag from a virtual address, if present.
*/ */
.macro clear_address_tag, dst, addr .macro untagged_addr, dst, addr
tst \addr, #(1 << 55) sbfx \dst, \addr, #0, #56
bic \dst, \addr, #(0xff << 56) and \dst, \dst, \addr
csel \dst, \dst, \addr, eq
.endm .endm
#endif #endif
...@@ -215,12 +215,18 @@ static inline unsigned long kaslr_offset(void) ...@@ -215,12 +215,18 @@ static inline unsigned long kaslr_offset(void)
* up with a tagged userland pointer. Clear the tag to get a sane pointer to * up with a tagged userland pointer. Clear the tag to get a sane pointer to
* pass on to access_ok(), for instance. * pass on to access_ok(), for instance.
*/ */
#define untagged_addr(addr) \ #define __untagged_addr(addr) \
((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55)) ((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55))
#define untagged_addr(addr) ({ \
u64 __addr = (__force u64)addr; \
__addr &= __untagged_addr(__addr); \
(__force __typeof__(addr))__addr; \
})
#ifdef CONFIG_KASAN_SW_TAGS #ifdef CONFIG_KASAN_SW_TAGS
#define __tag_shifted(tag) ((u64)(tag) << 56) #define __tag_shifted(tag) ((u64)(tag) << 56)
#define __tag_reset(addr) untagged_addr(addr) #define __tag_reset(addr) __untagged_addr(addr)
#define __tag_get(addr) (__u8)((u64)(addr) >> 56) #define __tag_get(addr) (__u8)((u64)(addr) >> 56)
#else #else
#define __tag_shifted(tag) 0UL #define __tag_shifted(tag) 0UL
......
...@@ -604,7 +604,7 @@ el1_da: ...@@ -604,7 +604,7 @@ el1_da:
*/ */
mrs x3, far_el1 mrs x3, far_el1
inherit_daif pstate=x23, tmp=x2 inherit_daif pstate=x23, tmp=x2
clear_address_tag x0, x3 untagged_addr x0, x3
mov x2, sp // struct pt_regs mov x2, sp // struct pt_regs
bl do_mem_abort bl do_mem_abort
...@@ -808,7 +808,7 @@ el0_da: ...@@ -808,7 +808,7 @@ el0_da:
mrs x26, far_el1 mrs x26, far_el1
ct_user_exit_irqoff ct_user_exit_irqoff
enable_daif enable_daif
clear_address_tag x0, x26 untagged_addr x0, x26
mov x1, x25 mov x1, x25
mov x2, sp mov x2, sp
bl do_mem_abort bl do_mem_abort
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment