diff options
author | Will Deacon <will@kernel.org> | 2019-10-16 00:04:18 -0400 |
---|---|---|
committer | Will Deacon <will@kernel.org> | 2019-10-16 13:11:38 -0400 |
commit | 597399d0cb91d049fcb78fb45c7694771b583bb7 (patch) | |
tree | 3cb46f903b734e7bae7a63e3cde1f0872398efdc | |
parent | 3813733595c0c7c0674d106309b04e871d54dc1c (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.h | 7 | ||||
-rw-r--r-- | arch/arm64/include/asm/memory.h | 10 | ||||
-rw-r--r-- | arch/arm64/kernel/entry.S | 4 |
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 |