summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-06-09 10:14:24 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2024-06-19 12:33:38 -0700
commitd31e86ef6377cbd7e4bbf1e8ff472ff48e04c5d8 (patch)
tree34924cf3fe4054596e236ef053ead3106ac6b18e
parent7fd298d4b39d8d5fe99d56811a7ed78c7a5377d5 (diff)
downloadlinux-arm64-uaccess.tar.gz
linux-arm64-uaccess.tar.bz2
linux-arm64-uaccess.zip
arm64: access_ok() optimizationarm64-uaccess
The TBI setup on arm64 is very strange: HW is set up to always do TBI, but the kernel enforcement for system calls is purely a software contract, and user space is supposed to mask off the top bits before the system call. Except all the actual brk/mmap/etc() system calls then mask it in kernel space anyway, and accept any TBI address. This basically unifies things and makes access_ok() also ignore it. This is an ABI change, but the current situation is very odd, and this change avoids the current mess and makes the kernel more permissive, and as such is unlikely to break anything. The way forward - for some possible future situation when people want to use more bits - is probably to introduce a new "I actually want the full 64-bit address space" prctl. But we should make sure that the software and hardware rules actually match at that point. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/arm64/include/asm/uaccess.h23
1 files changed, 10 insertions, 13 deletions
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 28f665e0975a..1f21190d4db5 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -30,23 +30,20 @@ static inline int __access_ok(const void __user *ptr, unsigned long size);
/*
* Test whether a block of memory is a valid user space address.
- * Returns 1 if the range is valid, 0 otherwise.
*
- * This is equivalent to the following test:
- * (u65)addr + (u65)size <= (u65)TASK_SIZE_MAX
+ * We only care that the address cannot reach the kernel mapping, and
+ * that an invalid address will fault.
*/
-static inline int access_ok(const void __user *addr, unsigned long size)
+static inline int access_ok(const void __user *p, unsigned long size)
{
- /*
- * Asynchronous I/O running in a kernel thread does not have the
- * TIF_TAGGED_ADDR flag of the process owning the mm, so always untag
- * the user address before checking.
- */
- if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI) &&
- (current->flags & PF_KTHREAD || test_thread_flag(TIF_TAGGED_ADDR)))
- addr = untagged_addr(addr);
+ unsigned long addr = (unsigned long)p;
+
+ /* Only bit 55 of the address matters */
+ addr |= addr+size;
+ addr = (addr >> 55) & 1;
+ size >>= 55;
- return likely(__access_ok(addr, size));
+ return !(addr | size);
}
#define access_ok access_ok