• Wei Fang's avatar
    vfs,mm: fix a dead loop in truncate_inode_pages_range() · 3d549dcf
    Wei Fang authored
    commit c2a9737f45e27d8263ff9643f994bda9bac0b944 upstream.
    
    We triggered a deadloop in truncate_inode_pages_range() on 32 bits
    architecture with the test case bellow:
    
    	...
    	fd = open();
    	write(fd, buf, 4096);
    	preadv64(fd, &iovec, 1, 0xffffffff000);
    	ftruncate(fd, 0);
    	...
    
    Then ftruncate() will not return forever.
    
    The filesystem used in this case is ubifs, but it can be triggered on
    many other filesystems.
    
    When preadv64() is called with offset=0xffffffff000, a page with
    index=0xffffffff will be added to the radix tree of ->mapping.  Then
    this page can be found in ->mapping with pagevec_lookup().  After that,
    truncate_inode_pages_range(), which is called in ftruncate(), will fall
    into an infinite loop:
    
     - find a page with index=0xffffffff, since index>=end, this page won't
       be truncated
    
     - index++, and index become 0
    
     - the page with index=0xffffffff will be found again
    
    The data type of index is unsigned long, so index won't overflow to 0 on
    64 bits architecture in this case, and the dead loop won't happen.
    
    Since truncate_inode_pages_range() is executed with holding lock of
    inode->i_rwsem, any operation related with this lock will be blocked,
    and a hung task will happen, e.g.:
    
      INFO: task truncate_test:3364 blocked for more than 120 seconds.
      ...
         call_rwsem_down_write_failed+0x17/0x30
         generic_file_write_iter+0x32/0x1c0
         ubifs_write_iter+0xcc/0x170
         __vfs_write+0xc4/0x120
         vfs_write+0xb2/0x1b0
         SyS_write+0x46/0xa0
    
    The page with index=0xffffffff added to ->mapping is useless.  Fix this
    by checking the read position before allocating pages.
    
    Link: http://lkml.kernel.org/r/1475151010-40166-1-git-send-email-fangwei1@huawei.comSigned-off-by: default avatarWei Fang <fangwei1@huawei.com>
    Cc: Christoph Hellwig <hch@infradead.org>
    Cc: Dave Chinner <david@fromorbit.com>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    3d549dcf
Name
Last commit
Last update
..
kasan Loading commit data...
Kconfig Loading commit data...
Kconfig.debug Loading commit data...
Makefile Loading commit data...
backing-dev.c Loading commit data...
balloon_compaction.c Loading commit data...
bootmem.c Loading commit data...
cleancache.c Loading commit data...
cma.c Loading commit data...
cma.h Loading commit data...
cma_debug.c Loading commit data...
compaction.c Loading commit data...
debug.c Loading commit data...
debug_page_ref.c Loading commit data...
dmapool.c Loading commit data...
early_ioremap.c Loading commit data...
fadvise.c Loading commit data...
failslab.c Loading commit data...
filemap.c Loading commit data...
frame_vector.c Loading commit data...
frontswap.c Loading commit data...
gup.c Loading commit data...
highmem.c Loading commit data...
huge_memory.c Loading commit data...
hugetlb.c Loading commit data...
hugetlb_cgroup.c Loading commit data...
hwpoison-inject.c Loading commit data...
init-mm.c Loading commit data...
internal.h Loading commit data...
interval_tree.c Loading commit data...
khugepaged.c Loading commit data...
kmemcheck.c Loading commit data...
kmemleak-test.c Loading commit data...
kmemleak.c Loading commit data...
ksm.c Loading commit data...
list_lru.c Loading commit data...
maccess.c Loading commit data...
madvise.c Loading commit data...
memblock.c Loading commit data...
memcontrol.c Loading commit data...
memory-failure.c Loading commit data...
memory.c Loading commit data...
memory_hotplug.c Loading commit data...
mempolicy.c Loading commit data...
mempool.c Loading commit data...
memtest.c Loading commit data...
migrate.c Loading commit data...
mincore.c Loading commit data...
mlock.c Loading commit data...
mm_init.c Loading commit data...
mmap.c Loading commit data...
mmu_context.c Loading commit data...
mmu_notifier.c Loading commit data...
mmzone.c Loading commit data...
mprotect.c Loading commit data...
mremap.c Loading commit data...
msync.c Loading commit data...
nobootmem.c Loading commit data...
nommu.c Loading commit data...
oom_kill.c Loading commit data...
page-writeback.c Loading commit data...
page_alloc.c Loading commit data...
page_counter.c Loading commit data...
page_ext.c Loading commit data...
page_idle.c Loading commit data...
page_io.c Loading commit data...
page_isolation.c Loading commit data...
page_owner.c Loading commit data...
page_poison.c Loading commit data...
pagewalk.c Loading commit data...
percpu-km.c Loading commit data...
percpu-vm.c Loading commit data...
percpu.c Loading commit data...
pgtable-generic.c Loading commit data...
process_vm_access.c Loading commit data...
quicklist.c Loading commit data...
readahead.c Loading commit data...
rmap.c Loading commit data...
shmem.c Loading commit data...
slab.c Loading commit data...
slab.h Loading commit data...
slab_common.c Loading commit data...
slob.c Loading commit data...
slub.c Loading commit data...
sparse-vmemmap.c Loading commit data...
sparse.c Loading commit data...
swap.c Loading commit data...
swap_cgroup.c Loading commit data...
swap_state.c Loading commit data...
swapfile.c Loading commit data...
truncate.c Loading commit data...
usercopy.c Loading commit data...
userfaultfd.c Loading commit data...
util.c Loading commit data...
vmacache.c Loading commit data...
vmalloc.c Loading commit data...
vmpressure.c Loading commit data...
vmscan.c Loading commit data...
vmstat.c Loading commit data...
workingset.c Loading commit data...
z3fold.c Loading commit data...
zbud.c Loading commit data...
zpool.c Loading commit data...
zsmalloc.c Loading commit data...
zswap.c Loading commit data...