diff options
Diffstat (limited to 'block/scsi_ioctl.c')
-rw-r--r-- | block/scsi_ioctl.c | 43 |
1 files changed, 38 insertions, 5 deletions
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 5f8e798ede4e..f0e0ce0a607d 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c | |||
@@ -32,6 +32,11 @@ | |||
32 | #include <scsi/scsi_ioctl.h> | 32 | #include <scsi/scsi_ioctl.h> |
33 | #include <scsi/scsi_cmnd.h> | 33 | #include <scsi/scsi_cmnd.h> |
34 | 34 | ||
35 | struct blk_cmd_filter { | ||
36 | unsigned long read_ok[BLK_SCSI_CMD_PER_LONG]; | ||
37 | unsigned long write_ok[BLK_SCSI_CMD_PER_LONG]; | ||
38 | } blk_default_cmd_filter; | ||
39 | |||
35 | /* Command group 3 is reserved and should never be used. */ | 40 | /* Command group 3 is reserved and should never be used. */ |
36 | const unsigned char scsi_command_size_tbl[8] = | 41 | const unsigned char scsi_command_size_tbl[8] = |
37 | { | 42 | { |
@@ -105,7 +110,7 @@ static int sg_emulated_host(struct request_queue *q, int __user *p) | |||
105 | return put_user(1, p); | 110 | return put_user(1, p); |
106 | } | 111 | } |
107 | 112 | ||
108 | void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) | 113 | static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) |
109 | { | 114 | { |
110 | /* Basic read-only commands */ | 115 | /* Basic read-only commands */ |
111 | __set_bit(TEST_UNIT_READY, filter->read_ok); | 116 | __set_bit(TEST_UNIT_READY, filter->read_ok); |
@@ -187,14 +192,37 @@ void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) | |||
187 | __set_bit(GPCMD_SET_STREAMING, filter->write_ok); | 192 | __set_bit(GPCMD_SET_STREAMING, filter->write_ok); |
188 | __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok); | 193 | __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok); |
189 | } | 194 | } |
190 | EXPORT_SYMBOL_GPL(blk_set_cmd_filter_defaults); | 195 | |
196 | int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm) | ||
197 | { | ||
198 | struct blk_cmd_filter *filter = &blk_default_cmd_filter; | ||
199 | |||
200 | /* root can do any command. */ | ||
201 | if (capable(CAP_SYS_RAWIO)) | ||
202 | return 0; | ||
203 | |||
204 | /* if there's no filter set, assume we're filtering everything out */ | ||
205 | if (!filter) | ||
206 | return -EPERM; | ||
207 | |||
208 | /* Anybody who can open the device can do a read-safe command */ | ||
209 | if (test_bit(cmd[0], filter->read_ok)) | ||
210 | return 0; | ||
211 | |||
212 | /* Write-safe commands require a writable open */ | ||
213 | if (test_bit(cmd[0], filter->write_ok) && has_write_perm) | ||
214 | return 0; | ||
215 | |||
216 | return -EPERM; | ||
217 | } | ||
218 | EXPORT_SYMBOL(blk_verify_command); | ||
191 | 219 | ||
192 | static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, | 220 | static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, |
193 | struct sg_io_hdr *hdr, fmode_t mode) | 221 | struct sg_io_hdr *hdr, fmode_t mode) |
194 | { | 222 | { |
195 | if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) | 223 | if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) |
196 | return -EFAULT; | 224 | return -EFAULT; |
197 | if (blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE)) | 225 | if (blk_verify_command(rq->cmd, mode & FMODE_WRITE)) |
198 | return -EPERM; | 226 | return -EPERM; |
199 | 227 | ||
200 | /* | 228 | /* |
@@ -427,7 +455,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, | |||
427 | if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) | 455 | if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) |
428 | goto error; | 456 | goto error; |
429 | 457 | ||
430 | err = blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE); | 458 | err = blk_verify_command(rq->cmd, mode & FMODE_WRITE); |
431 | if (err) | 459 | if (err) |
432 | goto error; | 460 | goto error; |
433 | 461 | ||
@@ -645,5 +673,10 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod | |||
645 | blk_put_queue(q); | 673 | blk_put_queue(q); |
646 | return err; | 674 | return err; |
647 | } | 675 | } |
648 | |||
649 | EXPORT_SYMBOL(scsi_cmd_ioctl); | 676 | EXPORT_SYMBOL(scsi_cmd_ioctl); |
677 | |||
678 | int __init blk_scsi_ioctl_init(void) | ||
679 | { | ||
680 | blk_set_cmd_filter_defaults(&blk_default_cmd_filter); | ||
681 | return 0; | ||
682 | } | ||