summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will@kernel.org>2019-10-16 00:04:18 -0400
committerWill Deacon <will@kernel.org>2019-10-16 13:11:38 -0400
commit597399d0cb91d049fcb78fb45c7694771b583bb7 (patch)
tree3cb46f903b734e7bae7a63e3cde1f0872398efdc
parent3813733595c0c7c0674d106309b04e871d54dc1c (diff)
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: Jan Stancek <jstancek@redhat.com> Tested-by: Jan Stancek <jstancek@redhat.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Tested-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com> Tested-by: Vincenzo Frascino <vincenzo.frascino@arm.com> Reviewed-by: Andrey Konovalov <andreyknvl@google.com> Signed-off-by: Will Deacon <will@kernel.org>
-rw-r--r--arch/arm64/include/asm/asm-uaccess.h7
-rw-r--r--arch/arm64/include/asm/memory.h10
-rw-r--r--arch/arm64/kernel/entry.S4
3 files changed, 13 insertions, 8 deletions
diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h
index f74909ba29bd..5bf963830b17 100644
--- a/arch/arm64/include/asm/asm-uaccess.h
+++ b/arch/arm64/include/asm/asm-uaccess.h
@@ -78,10 +78,9 @@ alternative_else_nop_endif
78/* 78/*
79 * Remove the address tag from a virtual address, if present. 79 * Remove the address tag from a virtual address, if present.
80 */ 80 */
81 .macro clear_address_tag, dst, addr 81 .macro untagged_addr, dst, addr
82 tst \addr, #(1 << 55) 82 sbfx \dst, \addr, #0, #56
83 bic \dst, \addr, #(0xff << 56) 83 and \dst, \dst, \addr
84 csel \dst, \dst, \addr, eq
85 .endm 84 .endm
86 85
87#endif 86#endif
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index b61b50bf68b1..c23c47360664 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -215,12 +215,18 @@ static inline unsigned long kaslr_offset(void)
215 * up with a tagged userland pointer. Clear the tag to get a sane pointer to 215 * up with a tagged userland pointer. Clear the tag to get a sane pointer to
216 * pass on to access_ok(), for instance. 216 * pass on to access_ok(), for instance.
217 */ 217 */
218#define untagged_addr(addr) \ 218#define __untagged_addr(addr) \
219 ((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55)) 219 ((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55))
220 220
221#define untagged_addr(addr) ({ \
222 u64 __addr = (__force u64)addr; \
223 __addr &= __untagged_addr(__addr); \
224 (__force __typeof__(addr))__addr; \
225})
226
221#ifdef CONFIG_KASAN_SW_TAGS 227#ifdef CONFIG_KASAN_SW_TAGS
222#define __tag_shifted(tag) ((u64)(tag) << 56) 228#define __tag_shifted(tag) ((u64)(tag) << 56)
223#define __tag_reset(addr) untagged_addr(addr) 229#define __tag_reset(addr) __untagged_addr(addr)
224#define __tag_get(addr) (__u8)((u64)(addr) >> 56) 230#define __tag_get(addr) (__u8)((u64)(addr) >> 56)
225#else 231#else
226#define __tag_shifted(tag) 0UL 232#define __tag_shifted(tag) 0UL
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index e1859e010c5f..a3a63092eba9 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -604,7 +604,7 @@ el1_da:
604 */ 604 */
605 mrs x3, far_el1 605 mrs x3, far_el1
606 inherit_daif pstate=x23, tmp=x2 606 inherit_daif pstate=x23, tmp=x2
607 clear_address_tag x0, x3 607 untagged_addr x0, x3
608 mov x2, sp // struct pt_regs 608 mov x2, sp // struct pt_regs
609 bl do_mem_abort 609 bl do_mem_abort
610 610
@@ -808,7 +808,7 @@ el0_da:
808 mrs x26, far_el1 808 mrs x26, far_el1
809 ct_user_exit_irqoff 809 ct_user_exit_irqoff
810 enable_daif 810 enable_daif
811 clear_address_tag x0, x26 811 untagged_addr x0, x26
812 mov x1, x25 812 mov x1, x25
813 mov x2, sp 813 mov x2, sp
814 bl do_mem_abort 814 bl do_mem_abort