--- /dev/null
+From 0bfc96cb77224736dfa35c3c555d37b3646ef35e Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Thu, 12 Jan 2012 16:01:28 +0100
+Subject: block: fail SCSI passthrough ioctls on partition devices
+
+From: Paolo Bonzini <pbonzini@redhat.com>
+
+commit 0bfc96cb77224736dfa35c3c555d37b3646ef35e upstream.
+
+Linux allows executing the SG_IO ioctl on a partition or LVM volume, and
+will pass the command to the underlying block device. This is
+well-known, but it is also a large security problem when (via Unix
+permissions, ACLs, SELinux or a combination thereof) a program or user
+needs to be granted access only to part of the disk.
+
+This patch lets partitions forward a small set of harmless ioctls;
+others are logged with printk so that we can see which ioctls are
+actually sent. In my tests only CDROM_GET_CAPABILITY actually occurred.
+Of course it was being sent to a (partition on a) hard disk, so it would
+have failed with ENOTTY and the patch isn't changing anything in
+practice. Still, I'm treating it specially to avoid spamming the logs.
+
+In principle, this restriction should include programs running with
+CAP_SYS_RAWIO. If for example I let a program access /dev/sda2 and
+/dev/sdb, it still should not be able to read/write outside the
+boundaries of /dev/sda2 independent of the capabilities. However, for
+now programs with CAP_SYS_RAWIO will still be allowed to send the
+ioctls. Their actions will still be logged.
+
+This patch does not affect the non-libata IDE driver. That driver
+however already tests for bd != bd->bd_contains before issuing some
+ioctl; it could be restricted further to forbid these ioctls even for
+programs running with CAP_SYS_ADMIN/CAP_SYS_RAWIO.
+
+Cc: linux-scsi@vger.kernel.org
+Cc: Jens Axboe <axboe@kernel.dk>
+Cc: James Bottomley <JBottomley@parallels.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+[ Make it also print the command name when warning - Linus ]
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ block/scsi_ioctl.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ drivers/scsi/sd.c | 11 +++++++++--
+ include/linux/blkdev.h | 1 +
+ 3 files changed, 55 insertions(+), 2 deletions(-)
+
+--- a/block/scsi_ioctl.c
++++ b/block/scsi_ioctl.c
+@@ -24,6 +24,7 @@
+ #include <linux/capability.h>
+ #include <linux/completion.h>
+ #include <linux/cdrom.h>
++#include <linux/ratelimit.h>
+ #include <linux/slab.h>
+ #include <linux/times.h>
+ #include <asm/uaccess.h>
+@@ -690,9 +691,53 @@ int scsi_cmd_ioctl(struct request_queue
+ }
+ EXPORT_SYMBOL(scsi_cmd_ioctl);
+
++int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd)
++{
++ if (bd && bd == bd->bd_contains)
++ return 0;
++
++ /* Actually none of these is particularly useful on a partition,
++ * but they are safe.
++ */
++ switch (cmd) {
++ case SCSI_IOCTL_GET_IDLUN:
++ case SCSI_IOCTL_GET_BUS_NUMBER:
++ case SCSI_IOCTL_GET_PCI:
++ case SCSI_IOCTL_PROBE_HOST:
++ case SG_GET_VERSION_NUM:
++ case SG_SET_TIMEOUT:
++ case SG_GET_TIMEOUT:
++ case SG_GET_RESERVED_SIZE:
++ case SG_SET_RESERVED_SIZE:
++ case SG_EMULATED_HOST:
++ return 0;
++ case CDROM_GET_CAPABILITY:
++ /* Keep this until we remove the printk below. udev sends it
++ * and we do not want to spam dmesg about it. CD-ROMs do
++ * not have partitions, so we get here only for disks.
++ */
++ return -ENOIOCTLCMD;
++ default:
++ break;
++ }
++
++ /* In particular, rule out all resets and host-specific ioctls. */
++ printk_ratelimited(KERN_WARNING
++ "%s: sending ioctl %x to a partition!\n", current->comm, cmd);
++
++ return capable(CAP_SYS_RAWIO) ? 0 : -ENOIOCTLCMD;
++}
++EXPORT_SYMBOL(scsi_verify_blk_ioctl);
++
+ int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode,
+ unsigned int cmd, void __user *arg)
+ {
++ int ret;
++
++ ret = scsi_verify_blk_ioctl(bd, cmd);
++ if (ret < 0)
++ return ret;
++
+ return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg);
+ }
+ EXPORT_SYMBOL(scsi_cmd_blk_ioctl);
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -1074,6 +1074,10 @@ static int sd_ioctl(struct block_device
+ SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
+ "cmd=0x%x\n", disk->disk_name, cmd));
+
++ error = scsi_verify_blk_ioctl(bdev, cmd);
++ if (error < 0)
++ return error;
++
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+@@ -1266,6 +1270,11 @@ static int sd_compat_ioctl(struct block_
+ unsigned int cmd, unsigned long arg)
+ {
+ struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
++ int ret;
++
++ ret = scsi_verify_blk_ioctl(bdev, cmd);
++ if (ret < 0)
++ return ret;
+
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+@@ -1277,8 +1286,6 @@ static int sd_compat_ioctl(struct block_
+ return -ENODEV;
+
+ if (sdev->host->hostt->compat_ioctl) {
+- int ret;
+-
+ ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
+
+ return ret;
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -675,6 +675,7 @@ extern int blk_insert_cloned_request(str
+ struct request *rq);
+ extern void blk_delay_queue(struct request_queue *, unsigned long);
+ extern void blk_recount_segments(struct request_queue *, struct bio *);
++extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int);
+ extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t,
+ unsigned int, void __user *);
+ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
--- /dev/null
+From ec8013beddd717d1740cfefb1a9b900deef85462 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Thu, 12 Jan 2012 16:01:29 +0100
+Subject: dm: do not forward ioctls from logical volumes to the
+ underlying device
+
+From: Paolo Bonzini <pbonzini@redhat.com>
+
+commit ec8013beddd717d1740cfefb1a9b900deef85462 upstream.
+
+A logical volume can map to just part of underlying physical volume.
+In this case, it must be treated like a partition.
+
+Based on a patch from Alasdair G Kergon.
+
+Cc: Alasdair G Kergon <agk@redhat.com>
+Cc: dm-devel@redhat.com
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-flakey.c | 11 ++++++++++-
+ drivers/md/dm-linear.c | 12 +++++++++++-
+ drivers/md/dm-mpath.c | 6 ++++++
+ 3 files changed, 27 insertions(+), 2 deletions(-)
+
+--- a/drivers/md/dm-flakey.c
++++ b/drivers/md/dm-flakey.c
+@@ -368,8 +368,17 @@ static int flakey_status(struct dm_targe
+ static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg)
+ {
+ struct flakey_c *fc = ti->private;
++ struct dm_dev *dev = fc->dev;
++ int r = 0;
+
+- return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg);
++ /*
++ * Only pass ioctls through if the device sizes match exactly.
++ */
++ if (fc->start ||
++ ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
++ r = scsi_verify_blk_ioctl(NULL, cmd);
++
++ return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
+ }
+
+ static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
+--- a/drivers/md/dm-linear.c
++++ b/drivers/md/dm-linear.c
+@@ -116,7 +116,17 @@ static int linear_ioctl(struct dm_target
+ unsigned long arg)
+ {
+ struct linear_c *lc = (struct linear_c *) ti->private;
+- return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg);
++ struct dm_dev *dev = lc->dev;
++ int r = 0;
++
++ /*
++ * Only pass ioctls through if the device sizes match exactly.
++ */
++ if (lc->start ||
++ ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
++ r = scsi_verify_blk_ioctl(NULL, cmd);
++
++ return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
+ }
+
+ static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
+--- a/drivers/md/dm-mpath.c
++++ b/drivers/md/dm-mpath.c
+@@ -1520,6 +1520,12 @@ static int multipath_ioctl(struct dm_tar
+
+ spin_unlock_irqrestore(&m->lock, flags);
+
++ /*
++ * Only pass ioctls through if the device sizes match exactly.
++ */
++ if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
++ r = scsi_verify_blk_ioctl(NULL, cmd);
++
+ return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+ }
+