Skip to content

Commit e65d28d

Browse files
arndbgregkh
authored andcommitted
uaccess: fix integer overflow on access_ok()
commit 222ca30 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: 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 058d62a commit e65d28d

3 files changed

Lines changed: 16 additions & 28 deletions

File tree

arch/csky/include/asm/uaccess.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
#ifndef __ASM_CSKY_UACCESS_H
44
#define __ASM_CSKY_UACCESS_H
55

6-
#define user_addr_max() \
7-
(uaccess_kernel() ? KERNEL_DS.seg : get_fs().seg)
6+
#define user_addr_max() (current_thread_info()->addr_limit.seg)
87

98
static inline int __access_ok(unsigned long addr, unsigned long size)
109
{
11-
unsigned long limit = current_thread_info()->addr_limit.seg;
10+
unsigned long limit = user_addr_max();
1211

13-
return ((addr < limit) && ((addr + size) < limit));
12+
return (size <= limit) && (addr <= (limit - size));
1413
}
1514
#define __access_ok __access_ok
1615

arch/hexagon/include/asm/uaccess.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@
2525
* Returns true (nonzero) if the memory block *may* be valid, false (zero)
2626
* if it is definitely invalid.
2727
*
28-
* User address space in Hexagon, like x86, goes to 0xbfffffff, so the
29-
* simple MSB-based tests used by MIPS won't work. Some further
30-
* optimization is probably possible here, but for now, keep it
31-
* reasonably simple and not *too* slow. After all, we've got the
32-
* MMU for backup.
3328
*/
29+
#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
30+
#define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE)
3431

35-
#define __access_ok(addr, size) \
36-
((get_fs().seg == KERNEL_DS.seg) || \
37-
(((unsigned long)addr < get_fs().seg) && \
38-
(unsigned long)size < (get_fs().seg - (unsigned long)addr)))
32+
static inline int __access_ok(unsigned long addr, unsigned long size)
33+
{
34+
unsigned long limit = TASK_SIZE;
35+
36+
return (size <= limit) && (addr <= (limit - size));
37+
}
38+
#define __access_ok __access_ok
3939

4040
/*
4141
* When a kernel-mode page fault is taken, the faulting instruction

arch/microblaze/include/asm/uaccess.h

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,13 @@
3939

4040
# define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
4141

42-
static inline int access_ok(const void __user *addr, unsigned long size)
42+
static inline int __access_ok(unsigned long addr, unsigned long size)
4343
{
44-
if (!size)
45-
goto ok;
44+
unsigned long limit = user_addr_max();
4645

47-
if ((get_fs().seg < ((unsigned long)addr)) ||
48-
(get_fs().seg < ((unsigned long)addr + size - 1))) {
49-
pr_devel("ACCESS fail at 0x%08x (size 0x%x), seg 0x%08x\n",
50-
(__force u32)addr, (u32)size,
51-
(u32)get_fs().seg);
52-
return 0;
53-
}
54-
ok:
55-
pr_devel("ACCESS OK at 0x%08x (size 0x%x), seg 0x%08x\n",
56-
(__force u32)addr, (u32)size,
57-
(u32)get_fs().seg);
58-
return 1;
46+
return (size <= limit) && (addr <= (limit - size));
5947
}
48+
#define access_ok(addr, size) __access_ok((unsigned long)addr, size)
6049

6150
# define __FIXUP_SECTION ".section .fixup,\"ax\"\n"
6251
# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"

0 commit comments

Comments
 (0)