forked from Minki/linux
watch_queue: Fix filter limit check
In watch_queue_set_filter(), there are a couple of places where we check
that the filter type value does not exceed what the type_filter bitmap
can hold. One place calculates the number of bits by:
if (tf[i].type >= sizeof(wfilter->type_filter) * 8)
which is fine, but the second does:
if (tf[i].type >= sizeof(wfilter->type_filter) * BITS_PER_LONG)
which is not. This can lead to a couple of out-of-bounds writes due to
a too-large type:
(1) __set_bit() on wfilter->type_filter
(2) Writing more elements in wfilter->filters[] than we allocated.
Fix this by just using the proper WATCH_TYPE__NR instead, which is the
number of types we actually know about.
The bug may cause an oops looking something like:
BUG: KASAN: slab-out-of-bounds in watch_queue_set_filter+0x659/0x740
Write of size 4 at addr ffff88800d2c66bc by task watch_queue_oob/611
...
Call Trace:
<TASK>
dump_stack_lvl+0x45/0x59
print_address_description.constprop.0+0x1f/0x150
...
kasan_report.cold+0x7f/0x11b
...
watch_queue_set_filter+0x659/0x740
...
__x64_sys_ioctl+0x127/0x190
do_syscall_64+0x43/0x90
entry_SYSCALL_64_after_hwframe+0x44/0xae
Allocated by task 611:
kasan_save_stack+0x1e/0x40
__kasan_kmalloc+0x81/0xa0
watch_queue_set_filter+0x23a/0x740
__x64_sys_ioctl+0x127/0x190
do_syscall_64+0x43/0x90
entry_SYSCALL_64_after_hwframe+0x44/0xae
The buggy address belongs to the object at ffff88800d2c66a0
which belongs to the cache kmalloc-32 of size 32
The buggy address is located 28 bytes inside of
32-byte region [ffff88800d2c66a0, ffff88800d2c66c0)
Fixes: c73be61ced
("pipe: Add general notification queue support")
Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
ffb217a13a
commit
c993ee0f9f
@ -28,7 +28,8 @@ struct watch_type_filter {
|
||||
struct watch_filter {
|
||||
union {
|
||||
struct rcu_head rcu;
|
||||
unsigned long type_filter[2]; /* Bitmask of accepted types */
|
||||
/* Bitmask of accepted types */
|
||||
DECLARE_BITMAP(type_filter, WATCH_TYPE__NR);
|
||||
};
|
||||
u32 nr_filters; /* Number of filters */
|
||||
struct watch_type_filter filters[];
|
||||
|
@ -320,7 +320,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe,
|
||||
tf[i].info_mask & WATCH_INFO_LENGTH)
|
||||
goto err_filter;
|
||||
/* Ignore any unknown types */
|
||||
if (tf[i].type >= sizeof(wfilter->type_filter) * 8)
|
||||
if (tf[i].type >= WATCH_TYPE__NR)
|
||||
continue;
|
||||
nr_filter++;
|
||||
}
|
||||
@ -336,7 +336,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe,
|
||||
|
||||
q = wfilter->filters;
|
||||
for (i = 0; i < filter.nr_filters; i++) {
|
||||
if (tf[i].type >= sizeof(wfilter->type_filter) * BITS_PER_LONG)
|
||||
if (tf[i].type >= WATCH_TYPE__NR)
|
||||
continue;
|
||||
|
||||
q->type = tf[i].type;
|
||||
|
Loading…
Reference in New Issue
Block a user