• Qu Wenruo's avatar
    btrfs: fix a out-of-bound access in copy_compressed_data_to_page() · 6f019c0e
    Qu Wenruo authored
    [BUG]
    The following script can cause btrfs to crash:
    
      $ mount -o compress-force=lzo $DEV /mnt
      $ dd if=/dev/urandom of=/mnt/foo bs=4k count=1
      $ sync
    
    The call trace looks like this:
    
      general protection fault, probably for non-canonical address 0xe04b37fccce3b000: 0000 [#1] PREEMPT SMP NOPTI
      CPU: 5 PID: 164 Comm: kworker/u20:3 Not tainted 5.15.0-rc7-custom+ #4
      Workqueue: btrfs-delalloc btrfs_work_helper [btrfs]
      RIP: 0010:__memcpy+0x12/0x20
      Call Trace:
       lzo_compress_pages+0x236/0x540 [btrfs]
       btrfs_compress_pages+0xaa/0xf0 [btrfs]
       compress_file_range+0x431/0x8e0 [btrfs]
       async_cow_start+0x12/0x30 [btrfs]
       btrfs_work_helper+0xf6/0x3e0 [btrfs]
       process_one_work+0x294/0x5d0
       worker_thread+0x55/0x3c0
       kthread+0x140/0x170
       ret_from_fork+0x22/0x30
      ---[ end trace 63c3c0f131e61982 ]---
    
    [CAUSE]
    In lzo_compress_pages(), parameter @out_pages is not only an output
    parameter (for the number of compressed pages), but also an input
    parameter, as the upper limit of compressed pages we can utilize.
    
    In commit d4088803 ("btrfs: subpage: make lzo_compress_pages()
    compatible"), the refactoring doesn't take @out_pages as an input, thus
    completely ignoring the limit.
    
    And for compress-force case, we could hit incompressible data that
    compressed size would go beyond the page limit, and cause the above
    crash.
    
    [FIX]
    Save @out_pages as @max_nr_page, and pass it to lzo_compress_pages(),
    and check if we're beyond the limit before accessing the pages.
    
    Note: this also fixes crash on 32bit architectures that was suspected to
    be caused by merge of btrfs patches to 5.16-rc1. Reported in
    https://lore.kernel.org/all/20211104115001.GU20319@twin.jikos.cz/ .
    Reported-by: default avatarOmar Sandoval <osandov@fb.com>
    Fixes: d4088803 ("btrfs: subpage: make lzo_compress_pages() compatible")
    Reviewed-by: default avatarOmar Sandoval <osandov@fb.com>
    Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    [ add note ]
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    6f019c0e
lzo.c 12 KB