Re: Patch "loop: prevent bdev freeing while device in use" has been added to the 3.0-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I clearly can reproduce the issue on 3.3 and 3.8, but not on 3.0.  I
think the issue appeared around v3.2 time. I am trying to bisect it
and give you more info later.

On Mon, Apr 1, 2013 at 5:26 PM,  <gregkh@xxxxxxxxxxxxxxxxxxx> wrote:
>
> This is a note to let you know that I've just added the patch titled
>
>     loop: prevent bdev freeing while device in use
>
> to the 3.0-stable tree which can be found at:
>     http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
>
> The filename of the patch is:
>      loop-prevent-bdev-freeing-while-device-in-use.patch
> and it can be found in the queue-3.0 subdirectory.
>
> If you, or anyone else, feels it should not be added to the stable tree,
> please let <stable@xxxxxxxxxxxxxxx> know about it.
>
>
> From c1681bf8a7b1b98edee8b862a42c19c4e53205fd Mon Sep 17 00:00:00 2001
> From: Anatol Pomozov <anatol.pomozov@xxxxxxxxx>
> Date: Mon, 1 Apr 2013 09:47:56 -0700
> Subject: loop: prevent bdev freeing while device in use
>
> From: Anatol Pomozov <anatol.pomozov@xxxxxxxxx>
>
> commit c1681bf8a7b1b98edee8b862a42c19c4e53205fd upstream.
>
> struct block_device lifecycle is defined by its inode (see fs/block_dev.c) -
> block_device allocated first time we access /dev/loopXX and deallocated on
> bdev_destroy_inode. When we create the device "losetup /dev/loopXX afile"
> we want that block_device stay alive until we destroy the loop device
> with "losetup -d".
>
> But because we do not hold /dev/loopXX inode its counter goes 0, and
> inode/bdev can be destroyed at any moment. Usually it happens at memory
> pressure or when user drops inode cache (like in the test below). When later in
> loop_clr_fd() we want to use bdev we have use-after-free error with following
> stack:
>
> BUG: unable to handle kernel NULL pointer dereference at 0000000000000280
>   bd_set_size+0x10/0xa0
>   loop_clr_fd+0x1f8/0x420 [loop]
>   lo_ioctl+0x200/0x7e0 [loop]
>   lo_compat_ioctl+0x47/0xe0 [loop]
>   compat_blkdev_ioctl+0x341/0x1290
>   do_filp_open+0x42/0xa0
>   compat_sys_ioctl+0xc1/0xf20
>   do_sys_open+0x16e/0x1d0
>   sysenter_dispatch+0x7/0x1a
>
> To prevent use-after-free we need to grab the device in loop_set_fd()
> and put it later in loop_clr_fd().
>
> The issue is reprodusible on current Linus head and v3.3. Here is the test:
>
>   dd if=/dev/zero of=loop.file bs=1M count=1
>   while [ true ]; do
>     losetup /dev/loop0 loop.file
>     echo 2 > /proc/sys/vm/drop_caches
>     losetup -d /dev/loop0
>   done
>
> [ Doing bdgrab/bput in loop_set_fd/loop_clr_fd is safe, because every
>   time we call loop_set_fd() we check that loop_device->lo_state is
>   Lo_unbound and set it to Lo_bound If somebody will try to set_fd again
>   it will get EBUSY.  And if we try to loop_clr_fd() on unbound loop
>   device we'll get ENXIO.
>
>   loop_set_fd/loop_clr_fd (and any other loop ioctl) is called under
>   loop_device->lo_ctl_mutex. ]
>
> Signed-off-by: Anatol Pomozov <anatol.pomozov@xxxxxxxxx>
> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
> Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
>
> ---
>  drivers/block/loop.c |    9 ++++++++-
>  fs/block_dev.c       |    1 +
>  2 files changed, 9 insertions(+), 1 deletion(-)
>
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -928,6 +928,11 @@ static int loop_set_fd(struct loop_devic
>         wake_up_process(lo->lo_thread);
>         if (max_part > 0)
>                 ioctl_by_bdev(bdev, BLKRRPART, 0);
> +
> +       /* Grab the block_device to prevent its destruction after we
> +        * put /dev/loopXX inode. Later in loop_clr_fd() we bdput(bdev).
> +        */
> +       bdgrab(bdev);
>         return 0;
>
>  out_clr:
> @@ -1024,8 +1029,10 @@ static int loop_clr_fd(struct loop_devic
>         memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
>         memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
>         memset(lo->lo_file_name, 0, LO_NAME_SIZE);
> -       if (bdev)
> +       if (bdev) {
> +               bdput(bdev);
>                 invalidate_bdev(bdev);
> +       }
>         set_capacity(lo->lo_disk, 0);
>         loop_sysfs_exit(lo);
>         if (bdev) {
> --- a/fs/block_dev.c
> +++ b/fs/block_dev.c
> @@ -576,6 +576,7 @@ struct block_device *bdgrab(struct block
>         ihold(bdev->bd_inode);
>         return bdev;
>  }
> +EXPORT_SYMBOL(bdgrab);
>
>  long nr_blockdev_pages(void)
>  {
>
>
> Patches currently in stable-queue which might be from anatol.pomozov@xxxxxxxxx are
>
> queue-3.0/loop-prevent-bdev-freeing-while-device-in-use.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]