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
|
#ifndef __ASM_CSKY_UACCESS_H
|
||||||
#define __ASM_CSKY_UACCESS_H
|
#define __ASM_CSKY_UACCESS_H
|
||||||
|
|
||||||
#define user_addr_max() \
|
#define user_addr_max() (current_thread_info()->addr_limit.seg)
|
||||||
(uaccess_kernel() ? KERNEL_DS.seg : get_fs().seg)
|
|
||||||
|
|
||||||
static inline int __access_ok(unsigned long addr, unsigned long size)
|
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
|
#define __access_ok __access_ok
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,17 @@
|
||||||
* Returns true (nonzero) if the memory block *may* be valid, false (zero)
|
* Returns true (nonzero) if the memory block *may* be valid, false (zero)
|
||||||
* if it is definitely invalid.
|
* 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) \
|
static inline int __access_ok(unsigned long addr, unsigned long size)
|
||||||
((get_fs().seg == KERNEL_DS.seg) || \
|
{
|
||||||
(((unsigned long)addr < get_fs().seg) && \
|
unsigned long limit = TASK_SIZE;
|
||||||
(unsigned long)size < (get_fs().seg - (unsigned long)addr)))
|
|
||||||
|
return (size <= limit) && (addr <= (limit - size));
|
||||||
|
}
|
||||||
|
#define __access_ok __access_ok
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When a kernel-mode page fault is taken, the faulting instruction
|
* When a kernel-mode page fault is taken, the faulting instruction
|
||||||
|
|
|
@ -39,24 +39,13 @@
|
||||||
|
|
||||||
# define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
|
# 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)
|
unsigned long limit = user_addr_max();
|
||||||
goto ok;
|
|
||||||
|
|
||||||
if ((get_fs().seg < ((unsigned long)addr)) ||
|
return (size <= limit) && (addr <= (limit - size));
|
||||||
(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;
|
|
||||||
}
|
}
|
||||||
|
#define access_ok(addr, size) __access_ok((unsigned long)addr, size)
|
||||||
|
|
||||||
# define __FIXUP_SECTION ".section .fixup,\"ax\"\n"
|
# define __FIXUP_SECTION ".section .fixup,\"ax\"\n"
|
||||||
# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"
|
# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"
|
||||||
|
|
Loading…
Reference in New Issue