uaccess: fix integer overflow on access_ok()
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:da55128194
("csky: User access") Fixes:f663b60f52
("microblaze: Fix uaccess_ok macro") Fixes:7567746e1c
("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>
This commit is contained in:
parent
dfd42facf1
commit
222ca305c9
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue