]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 2 Apr 2013 00:26:18 +0000 (17:26 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 2 Apr 2013 00:26:18 +0000 (17:26 -0700)
added patches:
loop-prevent-bdev-freeing-while-device-in-use.patch

queue-3.4/loop-prevent-bdev-freeing-while-device-in-use.patch [new file with mode: 0644]
queue-3.4/series

diff --git a/queue-3.4/loop-prevent-bdev-freeing-while-device-in-use.patch b/queue-3.4/loop-prevent-bdev-freeing-while-device-in-use.patch
new file mode 100644 (file)
index 0000000..5d3e760
--- /dev/null
@@ -0,0 +1,99 @@
+From c1681bf8a7b1b98edee8b862a42c19c4e53205fd Mon Sep 17 00:00:00 2001
+From: Anatol Pomozov <anatol.pomozov@gmail.com>
+Date: Mon, 1 Apr 2013 09:47:56 -0700
+Subject: loop: prevent bdev freeing while device in use
+
+From: Anatol Pomozov <anatol.pomozov@gmail.com>
+
+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@gmail.com>
+Cc: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -908,6 +908,11 @@ static int loop_set_fd(struct loop_devic
+               lo->lo_flags |= LO_FLAGS_PARTSCAN;
+       if (lo->lo_flags & LO_FLAGS_PARTSCAN)
+               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:
+@@ -1004,8 +1009,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
+@@ -604,6 +604,7 @@ struct block_device *bdgrab(struct block
+       ihold(bdev->bd_inode);
+       return bdev;
+ }
++EXPORT_SYMBOL(bdgrab);
+ long nr_blockdev_pages(void)
+ {
index 260f16debf99dcfff399437d729d6e40c0e73b06..9662220626b8eaf06330d7c0337932fab9eee321 100644 (file)
@@ -31,3 +31,4 @@ btrfs-don-t-drop-path-when-printing-out-tree-errors-in-scrub.patch
 usb-gadget-udc-core-fix-a-regression-during-gadget-driver-unbinding.patch
 signal-define-__arch_has_sa_restorer-so-we-know-whether-to-clear-3.0-3.2-3.4.patch
 kernel-signal.c-use-__arch_has_sa_restorer-instead-of-sa_restorer.patch
+loop-prevent-bdev-freeing-while-device-in-use.patch