aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-01-12 10:01:28 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-25 20:24:54 -0500
commit8bd8442fec18284924e17a0fa8ef89d98b0a6d71 (patch)
tree94cd21d75673e85efc4442bc639ce15cb12c4aa6
parent3b8373b85c761b2a12bdaf9fcee4c7a3eefa8459 (diff)
block: fail SCSI passthrough ioctls on partition devices
commit 0bfc96cb77224736dfa35c3c555d37b3646ef35e upstream. [ Changes with respect to 3.3: return -ENOTTY from scsi_verify_blk_ioctl and -ENOIOCTLCMD from sd_compat_ioctl. ] 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>
-rw-r--r--block/scsi_ioctl.c45
-rw-r--r--drivers/scsi/sd.c11
-rw-r--r--include/linux/blkdev.h1
3 files changed, 55 insertions, 2 deletions
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 57ac9375484..5ef1f4c17e6 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -24,6 +24,7 @@
24#include <linux/capability.h> 24#include <linux/capability.h>
25#include <linux/completion.h> 25#include <linux/completion.h>
26#include <linux/cdrom.h> 26#include <linux/cdrom.h>
27#include <linux/ratelimit.h>
27#include <linux/slab.h> 28#include <linux/slab.h>
28#include <linux/times.h> 29#include <linux/times.h>
29#include <asm/uaccess.h> 30#include <asm/uaccess.h>
@@ -691,9 +692,53 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod
691} 692}
692EXPORT_SYMBOL(scsi_cmd_ioctl); 693EXPORT_SYMBOL(scsi_cmd_ioctl);
693 694
695int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd)
696{
697 if (bd && bd == bd->bd_contains)
698 return 0;
699
700 /* Actually none of these is particularly useful on a partition,
701 * but they are safe.
702 */
703 switch (cmd) {
704 case SCSI_IOCTL_GET_IDLUN:
705 case SCSI_IOCTL_GET_BUS_NUMBER:
706 case SCSI_IOCTL_GET_PCI:
707 case SCSI_IOCTL_PROBE_HOST:
708 case SG_GET_VERSION_NUM:
709 case SG_SET_TIMEOUT:
710 case SG_GET_TIMEOUT:
711 case SG_GET_RESERVED_SIZE:
712 case SG_SET_RESERVED_SIZE:
713 case SG_EMULATED_HOST:
714 return 0;
715 case CDROM_GET_CAPABILITY:
716 /* Keep this until we remove the printk below. udev sends it
717 * and we do not want to spam dmesg about it. CD-ROMs do
718 * not have partitions, so we get here only for disks.
719 */
720 return -ENOTTY;
721 default:
722 break;
723 }
724
725 /* In particular, rule out all resets and host-specific ioctls. */
726 printk_ratelimited(KERN_WARNING
727 "%s: sending ioctl %x to a partition!\n", current->comm, cmd);
728
729 return capable(CAP_SYS_RAWIO) ? 0 : -ENOTTY;
730}
731EXPORT_SYMBOL(scsi_verify_blk_ioctl);
732
694int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode, 733int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode,
695 unsigned int cmd, void __user *arg) 734 unsigned int cmd, void __user *arg)
696{ 735{
736 int ret;
737
738 ret = scsi_verify_blk_ioctl(bd, cmd);
739 if (ret < 0)
740 return ret;
741
697 return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg); 742 return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg);
698} 743}
699EXPORT_SYMBOL(scsi_cmd_blk_ioctl); 744EXPORT_SYMBOL(scsi_cmd_blk_ioctl);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index c88885d9132..7d8b5d8d749 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1073,6 +1073,10 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
1073 SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n", 1073 SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n",
1074 disk->disk_name, cmd)); 1074 disk->disk_name, cmd));
1075 1075
1076 error = scsi_verify_blk_ioctl(bdev, cmd);
1077 if (error < 0)
1078 return error;
1079
1076 /* 1080 /*
1077 * If we are in the middle of error recovery, don't let anyone 1081 * If we are in the middle of error recovery, don't let anyone
1078 * else try and use this device. Also, if error recovery fails, it 1082 * else try and use this device. Also, if error recovery fails, it
@@ -1265,6 +1269,11 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
1265 unsigned int cmd, unsigned long arg) 1269 unsigned int cmd, unsigned long arg)
1266{ 1270{
1267 struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; 1271 struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
1272 int ret;
1273
1274 ret = scsi_verify_blk_ioctl(bdev, cmd);
1275 if (ret < 0)
1276 return -ENOIOCTLCMD;
1268 1277
1269 /* 1278 /*
1270 * If we are in the middle of error recovery, don't let anyone 1279 * If we are in the middle of error recovery, don't let anyone
@@ -1276,8 +1285,6 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
1276 return -ENODEV; 1285 return -ENODEV;
1277 1286
1278 if (sdev->host->hostt->compat_ioctl) { 1287 if (sdev->host->hostt->compat_ioctl) {
1279 int ret;
1280
1281 ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); 1288 ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
1282 1289
1283 return ret; 1290 return ret;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 0eca8080bb6..1b130216ccd 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -670,6 +670,7 @@ extern int blk_insert_cloned_request(struct request_queue *q,
670 struct request *rq); 670 struct request *rq);
671extern void blk_delay_queue(struct request_queue *, unsigned long); 671extern void blk_delay_queue(struct request_queue *, unsigned long);
672extern void blk_recount_segments(struct request_queue *, struct bio *); 672extern void blk_recount_segments(struct request_queue *, struct bio *);
673extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int);
673extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t, 674extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t,
674 unsigned int, void __user *); 675 unsigned int, void __user *);
675extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, 676extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,