loop: Don't change loop device under exclusive opener
authorJan Kara <jack@suse.cz>
Thu, 16 May 2019 14:01:27 +0000 (16:01 +0200)
committerJens Axboe <axboe@kernel.dk>
Mon, 27 May 2019 13:34:04 +0000 (07:34 -0600)
commit33ec3e53e7b1869d7851e59e126bdb0fe0bd1982
treec6f6599a2a13a0bf456854d291a942cc5297e090
parenta278682dad37fd2f8d2f30d8e84e376a856ab472
loop: Don't change loop device under exclusive opener

Loop module allows calling LOOP_SET_FD while there are other openers of
the loop device. Even exclusive ones. This can lead to weird
consequences such as kernel deadlocks like:

mount_bdev() lo_ioctl()
  udf_fill_super()
    udf_load_vrs()
      sb_set_blocksize() - sets desired block size B
      udf_tread()
        sb_bread()
          __bread_gfp(bdev, block, B)
  loop_set_fd()
    set_blocksize()
            - now __getblk_slow() indefinitely loops because B != bdev
              block size

Fix the problem by disallowing LOOP_SET_FD ioctl when there are
exclusive openers of a loop device.

[Deliberately chosen not to CC stable as a user with priviledges to
trigger this race has other means of taking the system down and this
has a potential of breaking some weird userspace setup]

Reported-and-tested-by: syzbot+10007d66ca02b08f0e60@syzkaller.appspotmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/loop.c