Skip to content

Commit

Permalink
uaccess: fix integer overflow on access_ok()
Browse files Browse the repository at this point in the history
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: da55128 ("csky: User access")
Fixes: f663b60 ("microblaze: Fix uaccess_ok macro")
Fixes: 7567746 ("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>
  • Loading branch information
Arnd Bergmann committed Feb 14, 2022
1 parent dfd42fa commit 222ca30
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 28 deletions.
7 changes: 3 additions & 4 deletions arch/csky/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
18 changes: 9 additions & 9 deletions arch/hexagon/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@
* 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
Expand Down
19 changes: 4 additions & 15 deletions arch/microblaze/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,13 @@

# 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"
Expand Down

0 comments on commit 222ca30

Please sign in to comment.