Commit 0b07de85a76e1346e675f0e98437378932473df7

Authored by Adel Gadllah
Committed by Jens Axboe
1 parent 6e2401ad6f

allow userspace to modify scsi command filter on per device basis

This patch exports the per-gendisk command filter to user space through
sysfs, so it can be changed by the system administrator.
All users of the old cmd filter have been converted to use the new one.

Original patch from Peter Jones.

Signed-off-by: Adel Gadllah <adel.gadllah@gmail.com>
Signed-off-by: Peter Jones <pjones@redhat.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

Showing 8 changed files with 389 additions and 159 deletions Side-by-side Diff

... ... @@ -4,7 +4,8 @@
4 4  
5 5 obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
6 6 blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \
7   - blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o
  7 + blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o \
  8 + cmd-filter.o
8 9  
9 10 obj-$(CONFIG_BLK_DEV_BSG) += bsg.o
10 11 obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
... ... @@ -44,11 +44,12 @@
44 44 char name[BUS_ID_SIZE];
45 45 int max_queue;
46 46 unsigned long flags;
  47 + struct blk_scsi_cmd_filter *cmd_filter;
  48 + mode_t *f_mode;
47 49 };
48 50  
49 51 enum {
50 52 BSG_F_BLOCK = 1,
51   - BSG_F_WRITE_PERM = 2,
52 53 };
53 54  
54 55 #define BSG_DEFAULT_CMDS 64
... ... @@ -172,7 +173,7 @@
172 173 }
173 174  
174 175 static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
175   - struct sg_io_v4 *hdr, int has_write_perm)
  176 + struct sg_io_v4 *hdr, struct bsg_device *bd)
176 177 {
177 178 if (hdr->request_len > BLK_MAX_CDB) {
178 179 rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
... ... @@ -185,7 +186,8 @@
185 186 return -EFAULT;
186 187  
187 188 if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
188   - if (blk_verify_command(rq->cmd, has_write_perm))
  189 + if (blk_cmd_filter_verify_command(bd->cmd_filter, rq->cmd,
  190 + bd->f_mode))
189 191 return -EPERM;
190 192 } else if (!capable(CAP_SYS_RAWIO))
191 193 return -EPERM;
... ... @@ -263,8 +265,7 @@
263 265 rq = blk_get_request(q, rw, GFP_KERNEL);
264 266 if (!rq)
265 267 return ERR_PTR(-ENOMEM);
266   - ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM,
267   - &bd->flags));
  268 + ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd);
268 269 if (ret)
269 270 goto out;
270 271  
271 272  
... ... @@ -566,12 +567,23 @@
566 567 set_bit(BSG_F_BLOCK, &bd->flags);
567 568 }
568 569  
569   -static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file)
  570 +static void bsg_set_cmd_filter(struct bsg_device *bd,
  571 + struct file *file)
570 572 {
571   - if (file->f_mode & FMODE_WRITE)
572   - set_bit(BSG_F_WRITE_PERM, &bd->flags);
573   - else
574   - clear_bit(BSG_F_WRITE_PERM, &bd->flags);
  573 + struct inode *inode;
  574 + struct gendisk *disk;
  575 +
  576 + if (!file)
  577 + return;
  578 +
  579 + inode = file->f_dentry->d_inode;
  580 + if (!inode)
  581 + return;
  582 +
  583 + disk = inode->i_bdev->bd_disk;
  584 +
  585 + bd->cmd_filter = &disk->cmd_filter;
  586 + bd->f_mode = &file->f_mode;
575 587 }
576 588  
577 589 /*
... ... @@ -595,6 +607,8 @@
595 607 dprintk("%s: read %Zd bytes\n", bd->name, count);
596 608  
597 609 bsg_set_block(bd, file);
  610 + bsg_set_cmd_filter(bd, file);
  611 +
598 612 bytes_read = 0;
599 613 ret = __bsg_read(buf, count, bd, NULL, &bytes_read);
600 614 *ppos = bytes_read;
... ... @@ -668,7 +682,7 @@
668 682 dprintk("%s: write %Zd bytes\n", bd->name, count);
669 683  
670 684 bsg_set_block(bd, file);
671   - bsg_set_write_perm(bd, file);
  685 + bsg_set_cmd_filter(bd, file);
672 686  
673 687 bytes_written = 0;
674 688 ret = __bsg_write(bd, buf, count, &bytes_written);
675 689  
... ... @@ -771,7 +785,9 @@
771 785 }
772 786  
773 787 bd->queue = rq;
  788 +
774 789 bsg_set_block(bd, file);
  790 + bsg_set_cmd_filter(bd, file);
775 791  
776 792 atomic_set(&bd->ref_count, 1);
777 793 mutex_lock(&bsg_mutex);
  1 +/*
  2 + * Copyright 2004 Peter M. Jones <pjones@redhat.com>
  3 + *
  4 + * This program is free software; you can redistribute it and/or modify
  5 + * it under the terms of the GNU General Public License version 2 as
  6 + * published by the Free Software Foundation.
  7 + *
  8 + * This program is distributed in the hope that it will be useful,
  9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 + *
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 + * GNU General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU General Public Licens
  15 + * along with this program; if not, write to the Free Software
  16 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
  17 + *
  18 + */
  19 +
  20 +#include <linux/list.h>
  21 +#include <linux/genhd.h>
  22 +#include <linux/spinlock.h>
  23 +#include <linux/parser.h>
  24 +#include <linux/capability.h>
  25 +#include <linux/bitops.h>
  26 +
  27 +#include <scsi/scsi.h>
  28 +#include <linux/cdrom.h>
  29 +
  30 +int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter,
  31 + unsigned char *cmd, mode_t *f_mode)
  32 +{
  33 + /* root can do any command. */
  34 + if (capable(CAP_SYS_RAWIO))
  35 + return 0;
  36 +
  37 + /* if there's no filter set, assume we're filtering everything out */
  38 + if (!filter)
  39 + return -EPERM;
  40 +
  41 + /* Anybody who can open the device can do a read-safe command */
  42 + if (test_bit(cmd[0], filter->read_ok))
  43 + return 0;
  44 +
  45 + /* Write-safe commands require a writable open */
  46 + if (test_bit(cmd[0], filter->write_ok) && (*f_mode & FMODE_WRITE))
  47 + return 0;
  48 +
  49 + return -EPERM;
  50 +}
  51 +EXPORT_SYMBOL(blk_cmd_filter_verify_command);
  52 +
  53 +int blk_verify_command(struct file *file, unsigned char *cmd)
  54 +{
  55 + struct gendisk *disk;
  56 + struct inode *inode;
  57 +
  58 + if (!file)
  59 + return -EINVAL;
  60 +
  61 + inode = file->f_dentry->d_inode;
  62 + if (!inode)
  63 + return -EINVAL;
  64 +
  65 + disk = inode->i_bdev->bd_disk;
  66 +
  67 + return blk_cmd_filter_verify_command(&disk->cmd_filter,
  68 + cmd, &file->f_mode);
  69 +}
  70 +EXPORT_SYMBOL(blk_verify_command);
  71 +
  72 +/* and now, the sysfs stuff */
  73 +static ssize_t rcf_cmds_show(struct blk_scsi_cmd_filter *filter, char *page,
  74 + int rw)
  75 +{
  76 + char *npage = page;
  77 + unsigned long *okbits;
  78 + int i;
  79 +
  80 + if (rw == READ)
  81 + okbits = filter->read_ok;
  82 + else
  83 + okbits = filter->write_ok;
  84 +
  85 + for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) {
  86 + if (test_bit(i, okbits)) {
  87 + sprintf(npage, "%02x", i);
  88 + npage += 2;
  89 + if (i < BLK_SCSI_MAX_CMDS - 1)
  90 + sprintf(npage++, " ");
  91 + }
  92 + }
  93 +
  94 + if (npage != page)
  95 + npage += sprintf(npage, "\n");
  96 +
  97 + return npage - page;
  98 +}
  99 +
  100 +static ssize_t rcf_readcmds_show(struct blk_scsi_cmd_filter *filter, char *page)
  101 +{
  102 + return rcf_cmds_show(filter, page, READ);
  103 +}
  104 +
  105 +static ssize_t rcf_writecmds_show(struct blk_scsi_cmd_filter *filter,
  106 + char *page)
  107 +{
  108 + return rcf_cmds_show(filter, page, WRITE);
  109 +}
  110 +
  111 +static ssize_t rcf_cmds_store(struct blk_scsi_cmd_filter *filter,
  112 + const char *page, size_t count, int rw)
  113 +{
  114 + ssize_t ret = 0;
  115 + unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits;
  116 + int cmd, status, len;
  117 + substring_t ss;
  118 +
  119 + memset(&okbits, 0, sizeof(okbits));
  120 +
  121 + for (len = strlen(page); len > 0; len -= 3) {
  122 + if (len < 2)
  123 + break;
  124 + ss.from = (char *) page + ret;
  125 + ss.to = (char *) page + ret + 2;
  126 + ret += 3;
  127 + status = match_hex(&ss, &cmd);
  128 + /* either of these cases means invalid input, so do nothing. */
  129 + if (status || cmd >= BLK_SCSI_MAX_CMDS)
  130 + return -EINVAL;
  131 +
  132 + __set_bit(cmd, okbits);
  133 + }
  134 +
  135 + if (rw == READ)
  136 + target_okbits = filter->read_ok;
  137 + else
  138 + target_okbits = filter->write_ok;
  139 +
  140 + memmove(target_okbits, okbits, sizeof(okbits));
  141 + return count;
  142 +}
  143 +
  144 +static ssize_t rcf_readcmds_store(struct blk_scsi_cmd_filter *filter,
  145 + const char *page, size_t count)
  146 +{
  147 + return rcf_cmds_store(filter, page, count, READ);
  148 +}
  149 +
  150 +static ssize_t rcf_writecmds_store(struct blk_scsi_cmd_filter *filter,
  151 + const char *page, size_t count)
  152 +{
  153 + return rcf_cmds_store(filter, page, count, WRITE);
  154 +}
  155 +
  156 +struct rcf_sysfs_entry {
  157 + struct attribute attr;
  158 + ssize_t (*show)(struct blk_scsi_cmd_filter *, char *);
  159 + ssize_t (*store)(struct blk_scsi_cmd_filter *, const char *, size_t);
  160 +};
  161 +
  162 +static struct rcf_sysfs_entry rcf_readcmds_entry = {
  163 + .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR },
  164 + .show = rcf_readcmds_show,
  165 + .store = rcf_readcmds_store,
  166 +};
  167 +
  168 +static struct rcf_sysfs_entry rcf_writecmds_entry = {
  169 + .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR },
  170 + .show = rcf_writecmds_show,
  171 + .store = rcf_writecmds_store,
  172 +};
  173 +
  174 +static struct attribute *default_attrs[] = {
  175 + &rcf_readcmds_entry.attr,
  176 + &rcf_writecmds_entry.attr,
  177 + NULL,
  178 +};
  179 +
  180 +#define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr)
  181 +
  182 +static ssize_t
  183 +rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
  184 +{
  185 + struct rcf_sysfs_entry *entry = to_rcf(attr);
  186 + struct blk_scsi_cmd_filter *filter;
  187 +
  188 + filter = container_of(kobj, struct blk_scsi_cmd_filter, kobj);
  189 + if (entry->show)
  190 + return entry->show(filter, page);
  191 +
  192 + return 0;
  193 +}
  194 +
  195 +static ssize_t
  196 +rcf_attr_store(struct kobject *kobj, struct attribute *attr,
  197 + const char *page, size_t length)
  198 +{
  199 + struct rcf_sysfs_entry *entry = to_rcf(attr);
  200 + struct blk_scsi_cmd_filter *filter;
  201 +
  202 + if (!capable(CAP_SYS_RAWIO))
  203 + return -EPERM;
  204 +
  205 + if (!entry->store)
  206 + return -EINVAL;
  207 +
  208 + filter = container_of(kobj, struct blk_scsi_cmd_filter, kobj);
  209 + return entry->store(filter, page, length);
  210 +}
  211 +
  212 +static struct sysfs_ops rcf_sysfs_ops = {
  213 + .show = rcf_attr_show,
  214 + .store = rcf_attr_store,
  215 +};
  216 +
  217 +static struct kobj_type rcf_ktype = {
  218 + .sysfs_ops = &rcf_sysfs_ops,
  219 + .default_attrs = default_attrs,
  220 +};
  221 +
  222 +static void rcf_set_defaults(struct blk_scsi_cmd_filter *filter)
  223 +{
  224 + /* Basic read-only commands */
  225 + __set_bit(TEST_UNIT_READY, filter->read_ok);
  226 + __set_bit(REQUEST_SENSE, filter->read_ok);
  227 + __set_bit(READ_6, filter->read_ok);
  228 + __set_bit(READ_10, filter->read_ok);
  229 + __set_bit(READ_12, filter->read_ok);
  230 + __set_bit(READ_16, filter->read_ok);
  231 + __set_bit(READ_BUFFER, filter->read_ok);
  232 + __set_bit(READ_DEFECT_DATA, filter->read_ok);
  233 + __set_bit(READ_LONG, filter->read_ok);
  234 + __set_bit(INQUIRY, filter->read_ok);
  235 + __set_bit(MODE_SENSE, filter->read_ok);
  236 + __set_bit(MODE_SENSE_10, filter->read_ok);
  237 + __set_bit(LOG_SENSE, filter->read_ok);
  238 + __set_bit(START_STOP, filter->read_ok);
  239 + __set_bit(GPCMD_VERIFY_10, filter->read_ok);
  240 + __set_bit(VERIFY_16, filter->read_ok);
  241 + __set_bit(GPCMD_READ_BUFFER_CAPACITY, filter->read_ok);
  242 +
  243 + /* Audio CD commands */
  244 + __set_bit(GPCMD_PLAY_CD, filter->read_ok);
  245 + __set_bit(GPCMD_PLAY_AUDIO_10, filter->read_ok);
  246 + __set_bit(GPCMD_PLAY_AUDIO_MSF, filter->read_ok);
  247 + __set_bit(GPCMD_PLAY_AUDIO_TI, filter->read_ok);
  248 + __set_bit(GPCMD_PAUSE_RESUME, filter->read_ok);
  249 +
  250 + /* CD/DVD data reading */
  251 + __set_bit(GPCMD_READ_CD, filter->read_ok);
  252 + __set_bit(GPCMD_READ_CD_MSF, filter->read_ok);
  253 + __set_bit(GPCMD_READ_DISC_INFO, filter->read_ok);
  254 + __set_bit(GPCMD_READ_CDVD_CAPACITY, filter->read_ok);
  255 + __set_bit(GPCMD_READ_DVD_STRUCTURE, filter->read_ok);
  256 + __set_bit(GPCMD_READ_HEADER, filter->read_ok);
  257 + __set_bit(GPCMD_READ_TRACK_RZONE_INFO, filter->read_ok);
  258 + __set_bit(GPCMD_READ_SUBCHANNEL, filter->read_ok);
  259 + __set_bit(GPCMD_READ_TOC_PMA_ATIP, filter->read_ok);
  260 + __set_bit(GPCMD_REPORT_KEY, filter->read_ok);
  261 + __set_bit(GPCMD_SCAN, filter->read_ok);
  262 + __set_bit(GPCMD_GET_CONFIGURATION, filter->read_ok);
  263 + __set_bit(GPCMD_READ_FORMAT_CAPACITIES, filter->read_ok);
  264 + __set_bit(GPCMD_GET_EVENT_STATUS_NOTIFICATION, filter->read_ok);
  265 + __set_bit(GPCMD_GET_PERFORMANCE, filter->read_ok);
  266 + __set_bit(GPCMD_SEEK, filter->read_ok);
  267 + __set_bit(GPCMD_STOP_PLAY_SCAN, filter->read_ok);
  268 +
  269 + /* Basic writing commands */
  270 + __set_bit(WRITE_6, filter->write_ok);
  271 + __set_bit(WRITE_10, filter->write_ok);
  272 + __set_bit(WRITE_VERIFY, filter->write_ok);
  273 + __set_bit(WRITE_12, filter->write_ok);
  274 + __set_bit(WRITE_VERIFY_12, filter->write_ok);
  275 + __set_bit(WRITE_16, filter->write_ok);
  276 + __set_bit(WRITE_LONG, filter->write_ok);
  277 + __set_bit(WRITE_LONG_2, filter->write_ok);
  278 + __set_bit(ERASE, filter->write_ok);
  279 + __set_bit(GPCMD_MODE_SELECT_10, filter->write_ok);
  280 + __set_bit(MODE_SELECT, filter->write_ok);
  281 + __set_bit(LOG_SELECT, filter->write_ok);
  282 + __set_bit(GPCMD_BLANK, filter->write_ok);
  283 + __set_bit(GPCMD_CLOSE_TRACK, filter->write_ok);
  284 + __set_bit(GPCMD_FLUSH_CACHE, filter->write_ok);
  285 + __set_bit(GPCMD_FORMAT_UNIT, filter->write_ok);
  286 + __set_bit(GPCMD_REPAIR_RZONE_TRACK, filter->write_ok);
  287 + __set_bit(GPCMD_RESERVE_RZONE_TRACK, filter->write_ok);
  288 + __set_bit(GPCMD_SEND_DVD_STRUCTURE, filter->write_ok);
  289 + __set_bit(GPCMD_SEND_EVENT, filter->write_ok);
  290 + __set_bit(GPCMD_SEND_KEY, filter->write_ok);
  291 + __set_bit(GPCMD_SEND_OPC, filter->write_ok);
  292 + __set_bit(GPCMD_SEND_CUE_SHEET, filter->write_ok);
  293 + __set_bit(GPCMD_SET_SPEED, filter->write_ok);
  294 + __set_bit(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, filter->write_ok);
  295 + __set_bit(GPCMD_LOAD_UNLOAD, filter->write_ok);
  296 + __set_bit(GPCMD_SET_STREAMING, filter->write_ok);
  297 +}
  298 +
  299 +int blk_register_filter(struct gendisk *disk)
  300 +{
  301 + int ret;
  302 + struct blk_scsi_cmd_filter *filter = &disk->cmd_filter;
  303 + struct kobject *parent = kobject_get(disk->holder_dir->parent);
  304 +
  305 + if (!parent)
  306 + return -ENODEV;
  307 +
  308 + ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, parent,
  309 + "%s", "cmd_filter");
  310 +
  311 + if (ret < 0)
  312 + return ret;
  313 +
  314 + rcf_set_defaults(filter);
  315 + return 0;
  316 +}
  317 +
  318 +void blk_unregister_filter(struct gendisk *disk)
  319 +{
  320 + struct blk_scsi_cmd_filter *filter = &disk->cmd_filter;
  321 +
  322 + kobject_put(&filter->kobj);
  323 + kobject_put(disk->holder_dir->parent);
  324 +}
... ... @@ -189,6 +189,7 @@
189 189 disk->minors, NULL, exact_match, exact_lock, disk);
190 190 register_disk(disk);
191 191 blk_register_queue(disk);
  192 + blk_register_filter(disk);
192 193  
193 194 bdi = &disk->queue->backing_dev_info;
194 195 bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor));
... ... @@ -200,6 +201,7 @@
200 201  
201 202 void unlink_gendisk(struct gendisk *disk)
202 203 {
  204 + blk_unregister_filter(disk);
203 205 sysfs_remove_link(&disk->dev.kobj, "bdi");
204 206 bdi_unregister(&disk->queue->backing_dev_info);
205 207 blk_unregister_queue(disk);
... ... @@ -105,120 +105,12 @@
105 105 return put_user(1, p);
106 106 }
107 107  
108   -#define CMD_READ_SAFE 0x01
109   -#define CMD_WRITE_SAFE 0x02
110   -#define CMD_WARNED 0x04
111   -#define safe_for_read(cmd) [cmd] = CMD_READ_SAFE
112   -#define safe_for_write(cmd) [cmd] = CMD_WRITE_SAFE
113   -
114   -int blk_verify_command(unsigned char *cmd, int has_write_perm)
115   -{
116   - static unsigned char cmd_type[256] = {
117   -
118   - /* Basic read-only commands */
119   - safe_for_read(TEST_UNIT_READY),
120   - safe_for_read(REQUEST_SENSE),
121   - safe_for_read(READ_6),
122   - safe_for_read(READ_10),
123   - safe_for_read(READ_12),
124   - safe_for_read(READ_16),
125   - safe_for_read(READ_BUFFER),
126   - safe_for_read(READ_DEFECT_DATA),
127   - safe_for_read(READ_LONG),
128   - safe_for_read(INQUIRY),
129   - safe_for_read(MODE_SENSE),
130   - safe_for_read(MODE_SENSE_10),
131   - safe_for_read(LOG_SENSE),
132   - safe_for_read(START_STOP),
133   - safe_for_read(GPCMD_VERIFY_10),
134   - safe_for_read(VERIFY_16),
135   -
136   - /* Audio CD commands */
137   - safe_for_read(GPCMD_PLAY_CD),
138   - safe_for_read(GPCMD_PLAY_AUDIO_10),
139   - safe_for_read(GPCMD_PLAY_AUDIO_MSF),
140   - safe_for_read(GPCMD_PLAY_AUDIO_TI),
141   - safe_for_read(GPCMD_PAUSE_RESUME),
142   -
143   - /* CD/DVD data reading */
144   - safe_for_read(GPCMD_READ_BUFFER_CAPACITY),
145   - safe_for_read(GPCMD_READ_CD),
146   - safe_for_read(GPCMD_READ_CD_MSF),
147   - safe_for_read(GPCMD_READ_DISC_INFO),
148   - safe_for_read(GPCMD_READ_CDVD_CAPACITY),
149   - safe_for_read(GPCMD_READ_DVD_STRUCTURE),
150   - safe_for_read(GPCMD_READ_HEADER),
151   - safe_for_read(GPCMD_READ_TRACK_RZONE_INFO),
152   - safe_for_read(GPCMD_READ_SUBCHANNEL),
153   - safe_for_read(GPCMD_READ_TOC_PMA_ATIP),
154   - safe_for_read(GPCMD_REPORT_KEY),
155   - safe_for_read(GPCMD_SCAN),
156   - safe_for_read(GPCMD_GET_CONFIGURATION),
157   - safe_for_read(GPCMD_READ_FORMAT_CAPACITIES),
158   - safe_for_read(GPCMD_GET_EVENT_STATUS_NOTIFICATION),
159   - safe_for_read(GPCMD_GET_PERFORMANCE),
160   - safe_for_read(GPCMD_SEEK),
161   - safe_for_read(GPCMD_STOP_PLAY_SCAN),
162   -
163   - /* Basic writing commands */
164   - safe_for_write(WRITE_6),
165   - safe_for_write(WRITE_10),
166   - safe_for_write(WRITE_VERIFY),
167   - safe_for_write(WRITE_12),
168   - safe_for_write(WRITE_VERIFY_12),
169   - safe_for_write(WRITE_16),
170   - safe_for_write(WRITE_LONG),
171   - safe_for_write(WRITE_LONG_2),
172   - safe_for_write(ERASE),
173   - safe_for_write(GPCMD_MODE_SELECT_10),
174   - safe_for_write(MODE_SELECT),
175   - safe_for_write(LOG_SELECT),
176   - safe_for_write(GPCMD_BLANK),
177   - safe_for_write(GPCMD_CLOSE_TRACK),
178   - safe_for_write(GPCMD_FLUSH_CACHE),
179   - safe_for_write(GPCMD_FORMAT_UNIT),
180   - safe_for_write(GPCMD_REPAIR_RZONE_TRACK),
181   - safe_for_write(GPCMD_RESERVE_RZONE_TRACK),
182   - safe_for_write(GPCMD_SEND_DVD_STRUCTURE),
183   - safe_for_write(GPCMD_SEND_EVENT),
184   - safe_for_write(GPCMD_SEND_KEY),
185   - safe_for_write(GPCMD_SEND_OPC),
186   - safe_for_write(GPCMD_SEND_CUE_SHEET),
187   - safe_for_write(GPCMD_SET_SPEED),
188   - safe_for_write(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL),
189   - safe_for_write(GPCMD_LOAD_UNLOAD),
190   - safe_for_write(GPCMD_SET_STREAMING),
191   - };
192   - unsigned char type = cmd_type[cmd[0]];
193   -
194   - /* Anybody who can open the device can do a read-safe command */
195   - if (type & CMD_READ_SAFE)
196   - return 0;
197   -
198   - /* Write-safe commands just require a writable open.. */
199   - if ((type & CMD_WRITE_SAFE) && has_write_perm)
200   - return 0;
201   -
202   - /* And root can do any command.. */
203   - if (capable(CAP_SYS_RAWIO))
204   - return 0;
205   -
206   - if (!type) {
207   - cmd_type[cmd[0]] = CMD_WARNED;
208   - printk(KERN_WARNING "scsi: unknown opcode 0x%02x\n", cmd[0]);
209   - }
210   -
211   - /* Otherwise fail it with an "Operation not permitted" */
212   - return -EPERM;
213   -}
214   -EXPORT_SYMBOL_GPL(blk_verify_command);
215   -
216 108 static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
217   - struct sg_io_hdr *hdr, int has_write_perm)
  109 + struct sg_io_hdr *hdr, struct file *file)
218 110 {
219 111 if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
220 112 return -EFAULT;
221   - if (blk_verify_command(rq->cmd, has_write_perm))
  113 + if (blk_verify_command(file, rq->cmd))
222 114 return -EPERM;
223 115  
224 116 /*
... ... @@ -287,7 +179,7 @@
287 179 struct gendisk *bd_disk, struct sg_io_hdr *hdr)
288 180 {
289 181 unsigned long start_time;
290   - int writing = 0, ret = 0, has_write_perm = 0;
  182 + int writing = 0, ret = 0;
291 183 struct request *rq;
292 184 char sense[SCSI_SENSE_BUFFERSIZE];
293 185 struct bio *bio;
... ... @@ -316,10 +208,7 @@
316 208 if (!rq)
317 209 return -ENOMEM;
318 210  
319   - if (file)
320   - has_write_perm = file->f_mode & FMODE_WRITE;
321   -
322   - if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) {
  211 + if (blk_fill_sghdr_rq(q, rq, hdr, file)) {
323 212 blk_put_request(rq);
324 213 return -EFAULT;
325 214 }
... ... @@ -451,7 +340,7 @@
451 340 if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
452 341 goto error;
453 342  
454   - err = blk_verify_command(rq->cmd, file->f_mode & FMODE_WRITE);
  343 + err = blk_verify_command(file, rq->cmd);
455 344 if (err)
456 345 goto error;
457 346  
... ... @@ -182,8 +182,9 @@
182 182 int tablesize);
183 183 static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
184 184 Sg_request * srp);
185   -static ssize_t sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
186   - int blocking, int read_only, Sg_request ** o_srp);
  185 +static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
  186 + const char __user *buf, size_t count, int blocking,
  187 + int read_only, Sg_request **o_srp);
187 188 static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
188 189 unsigned char *cmnd, int timeout, int blocking);
189 190 static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
... ... @@ -204,7 +205,6 @@
204 205 static Sg_request *sg_add_request(Sg_fd * sfp);
205 206 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
206 207 static int sg_res_in_use(Sg_fd * sfp);
207   -static int sg_allow_access(unsigned char opcode, char dev_type);
208 208 static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
209 209 static Sg_device *sg_get_dev(int dev);
210 210 #ifdef CONFIG_SCSI_PROC_FS
... ... @@ -544,7 +544,7 @@
544 544 return -EFAULT;
545 545 blocking = !(filp->f_flags & O_NONBLOCK);
546 546 if (old_hdr.reply_len < 0)
547   - return sg_new_write(sfp, buf, count, blocking, 0, NULL);
  547 + return sg_new_write(sfp, filp, buf, count, blocking, 0, NULL);
548 548 if (count < (SZ_SG_HEADER + 6))
549 549 return -EIO; /* The minimum scsi command length is 6 bytes. */
550 550  
... ... @@ -621,8 +621,9 @@
621 621 }
622 622  
623 623 static ssize_t
624   -sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
625   - int blocking, int read_only, Sg_request ** o_srp)
  624 +sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
  625 + size_t count, int blocking, int read_only,
  626 + Sg_request **o_srp)
626 627 {
627 628 int k;
628 629 Sg_request *srp;
... ... @@ -678,8 +679,7 @@
678 679 sg_remove_request(sfp, srp);
679 680 return -EFAULT;
680 681 }
681   - if (read_only &&
682   - (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
  682 + if (read_only && (!blk_verify_command(file, cmnd))) {
683 683 sg_remove_request(sfp, srp);
684 684 return -EPERM;
685 685 }
... ... @@ -799,7 +799,7 @@
799 799 if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
800 800 return -EFAULT;
801 801 result =
802   - sg_new_write(sfp, p, SZ_SG_IO_HDR,
  802 + sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
803 803 blocking, read_only, &srp);
804 804 if (result < 0)
805 805 return result;
... ... @@ -1048,7 +1048,7 @@
1048 1048  
1049 1049 if (copy_from_user(&opcode, siocp->data, 1))
1050 1050 return -EFAULT;
1051   - if (!sg_allow_access(opcode, sdp->device->type))
  1051 + if (!blk_verify_command(filp, &opcode))
1052 1052 return -EPERM;
1053 1053 }
1054 1054 return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p);
... ... @@ -2505,26 +2505,6 @@
2505 2505 #ifndef MAINTENANCE_IN_CMD
2506 2506 #define MAINTENANCE_IN_CMD 0xa3
2507 2507 #endif
2508   -
2509   -static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE,
2510   - INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
2511   - READ_16, MODE_SENSE, MODE_SENSE_10, LOG_SENSE, REPORT_LUNS,
2512   - SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG, MAINTENANCE_IN_CMD
2513   -};
2514   -
2515   -static int
2516   -sg_allow_access(unsigned char opcode, char dev_type)
2517   -{
2518   - int k;
2519   -
2520   - if (TYPE_SCANNER == dev_type) /* TYPE_ROM maybe burner */
2521   - return 1;
2522   - for (k = 0; k < sizeof (allow_ops); ++k) {
2523   - if (opcode == allow_ops[k])
2524   - return 1;
2525   - }
2526   - return 0;
2527   -}
2528 2508  
2529 2509 #ifdef CONFIG_SCSI_PROC_FS
2530 2510 static int
include/linux/blkdev.h
... ... @@ -671,7 +671,6 @@
671 671 struct request *, int);
672 672 extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
673 673 struct request *, int, rq_end_io_fn *);
674   -extern int blk_verify_command(unsigned char *, int);
675 674 extern void blk_unplug(struct request_queue *q);
676 675  
677 676 static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
... ... @@ -796,6 +795,15 @@
796 795 }
797 796  
798 797 extern int blkdev_issue_flush(struct block_device *, sector_t *);
  798 +
  799 +/*
  800 +* command filter functions
  801 +*/
  802 +extern int blk_verify_command(struct file *file, unsigned char *cmd);
  803 +extern int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter,
  804 + unsigned char *cmd, mode_t *f_mode);
  805 +extern int blk_register_filter(struct gendisk *disk);
  806 +extern void blk_unregister_filter(struct gendisk *disk);
799 807  
800 808 #define MAX_PHYS_SEGMENTS 128
801 809 #define MAX_HW_SEGMENTS 128
include/linux/genhd.h
... ... @@ -110,7 +110,15 @@
110 110 #define GENHD_FL_SUPPRESS_PARTITION_INFO 32
111 111 #define GENHD_FL_FAIL 64
112 112  
  113 +#define BLK_SCSI_MAX_CMDS (256)
  114 +#define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
113 115  
  116 +struct blk_scsi_cmd_filter {
  117 + unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
  118 + unsigned long write_ok[BLK_SCSI_CMD_PER_LONG];
  119 + struct kobject kobj;
  120 +};
  121 +
114 122 struct gendisk {
115 123 int major; /* major number of driver */
116 124 int first_minor;
... ... @@ -120,6 +128,7 @@
120 128 struct hd_struct **part; /* [indexed by minor] */
121 129 struct block_device_operations *fops;
122 130 struct request_queue *queue;
  131 + struct blk_scsi_cmd_filter cmd_filter;
123 132 void *private_data;
124 133 sector_t capacity;
125 134