uaccess: fix integer overflow on access_ok()
authorArnd Bergmann <arnd@arndb.de>
Thu, 10 Feb 2022 15:24:30 +0000 (16:24 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 28 Mar 2022 07:58:45 +0000 (09:58 +0200)
commit 222ca305c9fd39e5ed8104da25c09b2b79a516a8 upstream.

Three architectures check the end of a user access against the
address limit without taking a possible overflow into account.
Passing a negative length or another overflow in here returns
success when it should not.

Use the most common correct implementation here, which optimizes
for a constant 'size' argument, and turns the common case into a
single comparison.

Cc: stable@vger.kernel.org
Fixes: da551281947c ("csky: User access")
Fixes: f663b60f5215 ("microblaze: Fix uaccess_ok macro")
Fixes: 7567746e1c0d ("Hexagon: Add user access functions")
Reported-by: David Laight <David.Laight@aculab.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/csky/include/asm/uaccess.h
arch/hexagon/include/asm/uaccess.h
arch/microblaze/include/asm/uaccess.h

index c40f06e..ac5a54f 100644 (file)
@@ -3,14 +3,13 @@
 #ifndef __ASM_CSKY_UACCESS_H
 #define __ASM_CSKY_UACCESS_H
 
-#define user_addr_max() \
-       (uaccess_kernel() ? KERNEL_DS.seg : get_fs().seg)
+#define user_addr_max() (current_thread_info()->addr_limit.seg)
 
 static inline int __access_ok(unsigned long addr, unsigned long size)
 {
-       unsigned long limit = current_thread_info()->addr_limit.seg;
+       unsigned long limit = user_addr_max();
 
-       return ((addr < limit) && ((addr + size) < limit));
+       return (size <= limit) && (addr <= (limit - size));
 }
 #define __access_ok __access_ok
 
index ef5bfef..719ba3f 100644 (file)
  * Returns true (nonzero) if the memory block *may* be valid, false (zero)
  * if it is definitely invalid.
  *
- * User address space in Hexagon, like x86, goes to 0xbfffffff, so the
- * simple MSB-based tests used by MIPS won't work.  Some further
- * optimization is probably possible here, but for now, keep it
- * reasonably simple and not *too* slow.  After all, we've got the
- * MMU for backup.
  */
+#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
+#define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE)
 
-#define __access_ok(addr, size) \
-       ((get_fs().seg == KERNEL_DS.seg) || \
-       (((unsigned long)addr < get_fs().seg) && \
-         (unsigned long)size < (get_fs().seg - (unsigned long)addr)))
+static inline int __access_ok(unsigned long addr, unsigned long size)
+{
+       unsigned long limit = TASK_SIZE;
+
+       return (size <= limit) && (addr <= (limit - size));
+}
+#define __access_ok __access_ok
 
 /*
  * When a kernel-mode page fault is taken, the faulting instruction
index d2a8ef9..5b6e0e7 100644 (file)
 
 # define uaccess_kernel()      (get_fs().seg == KERNEL_DS.seg)
 
-static inline int access_ok(const void __user *addr, unsigned long size)
+static inline int __access_ok(unsigned long addr, unsigned long size)
 {
-       if (!size)
-               goto ok;
+       unsigned long limit = user_addr_max();
 
-       if ((get_fs().seg < ((unsigned long)addr)) ||
-                       (get_fs().seg < ((unsigned long)addr + size - 1))) {
-               pr_devel("ACCESS fail at 0x%08x (size 0x%x), seg 0x%08x\n",
-                       (__force u32)addr, (u32)size,
-                       (u32)get_fs().seg);
-               return 0;
-       }
-ok:
-       pr_devel("ACCESS OK at 0x%08x (size 0x%x), seg 0x%08x\n",
-                       (__force u32)addr, (u32)size,
-                       (u32)get_fs().seg);
-       return 1;
+       return (size <= limit) && (addr <= (limit - size));
 }
+#define access_ok(addr, size) __access_ok((unsigned long)addr, size)
 
 # define __FIXUP_SECTION       ".section .fixup,\"ax\"\n"
 # define __EX_TABLE_SECTION    ".section __ex_table,\"a\"\n"