aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdel Gadllah <adel.gadllah@gmail.com>2008-06-26 07:48:27 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-07-03 07:21:14 -0400
commit0b07de85a76e1346e675f0e98437378932473df7 (patch)
treeb86e5e0be27679c408ab525534c76162754129b9
parent6e2401ad6f33de15ff00f78b88159f00a14f3b35 (diff)
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>
-rw-r--r--block/Makefile3
-rw-r--r--block/bsg.c38
-rw-r--r--block/cmd-filter.c325
-rw-r--r--block/genhd.c2
-rw-r--r--block/scsi_ioctl.c121
-rw-r--r--drivers/scsi/sg.c40
-rw-r--r--include/linux/blkdev.h10
-rw-r--r--include/linux/genhd.h9
8 files changed, 389 insertions, 159 deletions
diff --git a/block/Makefile b/block/Makefile
index 045f7b62e4bb..208000b0750d 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -4,7 +4,8 @@
4 4
5obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \ 5obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
6 blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \ 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
9obj-$(CONFIG_BLK_DEV_BSG) += bsg.o 10obj-$(CONFIG_BLK_DEV_BSG) += bsg.o
10obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o 11obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
diff --git a/block/bsg.c b/block/bsg.c
index f0b7cd343216..439940c3a1ff 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -44,11 +44,12 @@ struct bsg_device {
44 char name[BUS_ID_SIZE]; 44 char name[BUS_ID_SIZE];
45 int max_queue; 45 int max_queue;
46 unsigned long flags; 46 unsigned long flags;
47 struct blk_scsi_cmd_filter *cmd_filter;
48 mode_t *f_mode;
47}; 49};
48 50
49enum { 51enum {
50 BSG_F_BLOCK = 1, 52 BSG_F_BLOCK = 1,
51 BSG_F_WRITE_PERM = 2,
52}; 53};
53 54
54#define BSG_DEFAULT_CMDS 64 55#define BSG_DEFAULT_CMDS 64
@@ -172,7 +173,7 @@ unlock:
172} 173}
173 174
174static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, 175static 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 if (hdr->request_len > BLK_MAX_CDB) { 178 if (hdr->request_len > BLK_MAX_CDB) {
178 rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL); 179 rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
@@ -185,7 +186,8 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
185 return -EFAULT; 186 return -EFAULT;
186 187
187 if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) { 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 return -EPERM; 191 return -EPERM;
190 } else if (!capable(CAP_SYS_RAWIO)) 192 } else if (!capable(CAP_SYS_RAWIO))
191 return -EPERM; 193 return -EPERM;
@@ -263,8 +265,7 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr)
263 rq = blk_get_request(q, rw, GFP_KERNEL); 265 rq = blk_get_request(q, rw, GFP_KERNEL);
264 if (!rq) 266 if (!rq)
265 return ERR_PTR(-ENOMEM); 267 return ERR_PTR(-ENOMEM);
266 ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM, 268 ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd);
267 &bd->flags));
268 if (ret) 269 if (ret)
269 goto out; 270 goto out;
270 271
@@ -566,12 +567,23 @@ static inline void bsg_set_block(struct bsg_device *bd, struct file *file)
566 set_bit(BSG_F_BLOCK, &bd->flags); 567 set_bit(BSG_F_BLOCK, &bd->flags);
567} 568}
568 569
569static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file) 570static void bsg_set_cmd_filter(struct bsg_device *bd,
571 struct file *file)
570{ 572{
571 if (file->f_mode & FMODE_WRITE) 573 struct inode *inode;
572 set_bit(BSG_F_WRITE_PERM, &bd->flags); 574 struct gendisk *disk;
573 else 575
574 clear_bit(BSG_F_WRITE_PERM, &bd->flags); 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 @@ bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
595 dprintk("%s: read %Zd bytes\n", bd->name, count); 607 dprintk("%s: read %Zd bytes\n", bd->name, count);
596 608
597 bsg_set_block(bd, file); 609 bsg_set_block(bd, file);
610 bsg_set_cmd_filter(bd, file);
611
598 bytes_read = 0; 612 bytes_read = 0;
599 ret = __bsg_read(buf, count, bd, NULL, &bytes_read); 613 ret = __bsg_read(buf, count, bd, NULL, &bytes_read);
600 *ppos = bytes_read; 614 *ppos = bytes_read;
@@ -668,7 +682,7 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
668 dprintk("%s: write %Zd bytes\n", bd->name, count); 682 dprintk("%s: write %Zd bytes\n", bd->name, count);
669 683
670 bsg_set_block(bd, file); 684 bsg_set_block(bd, file);
671 bsg_set_write_perm(bd, file); 685 bsg_set_cmd_filter(bd, file);
672 686
673 bytes_written = 0; 687 bytes_written = 0;
674 ret = __bsg_write(bd, buf, count, &bytes_written); 688 ret = __bsg_write(bd, buf, count, &bytes_written);
@@ -771,7 +785,9 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
771 } 785 }
772 786
773 bd->queue = rq; 787 bd->queue = rq;
788
774 bsg_set_block(bd, file); 789 bsg_set_block(bd, file);
790 bsg_set_cmd_filter(bd, file);
775 791
776 atomic_set(&bd->ref_count, 1); 792 atomic_set(&bd->ref_count, 1);
777 mutex_lock(&bsg_mutex); 793 mutex_lock(&bsg_mutex);
diff --git a/block/cmd-filter.c b/block/cmd-filter.c
new file mode 100644
index 000000000000..35e327ceaa97
--- /dev/null
+++ b/block/cmd-filter.c
@@ -0,0 +1,325 @@
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
30int 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}
51EXPORT_SYMBOL(blk_cmd_filter_verify_command);
52
53int 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}
70EXPORT_SYMBOL(blk_verify_command);
71
72/* and now, the sysfs stuff */
73static 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
100static ssize_t rcf_readcmds_show(struct blk_scsi_cmd_filter *filter, char *page)
101{
102 return rcf_cmds_show(filter, page, READ);
103}
104
105static 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
111static 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
144static 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
150static 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
156struct 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
162static 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
168static 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
174static 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
182static ssize_t
183rcf_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
195static ssize_t
196rcf_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
212static struct sysfs_ops rcf_sysfs_ops = {
213 .show = rcf_attr_show,
214 .store = rcf_attr_store,
215};
216
217static struct kobj_type rcf_ktype = {
218 .sysfs_ops = &rcf_sysfs_ops,
219 .default_attrs = default_attrs,
220};
221
222static 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
299int 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
318void 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}
325
diff --git a/block/genhd.c b/block/genhd.c
index 43e468ee5993..9074f384b097 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -189,6 +189,7 @@ void add_disk(struct gendisk *disk)
189 disk->minors, NULL, exact_match, exact_lock, disk); 189 disk->minors, NULL, exact_match, exact_lock, disk);
190 register_disk(disk); 190 register_disk(disk);
191 blk_register_queue(disk); 191 blk_register_queue(disk);
192 blk_register_filter(disk);
192 193
193 bdi = &disk->queue->backing_dev_info; 194 bdi = &disk->queue->backing_dev_info;
194 bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor)); 195 bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor));
@@ -200,6 +201,7 @@ EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */
200 201
201void unlink_gendisk(struct gendisk *disk) 202void unlink_gendisk(struct gendisk *disk)
202{ 203{
204 blk_unregister_filter(disk);
203 sysfs_remove_link(&disk->dev.kobj, "bdi"); 205 sysfs_remove_link(&disk->dev.kobj, "bdi");
204 bdi_unregister(&disk->queue->backing_dev_info); 206 bdi_unregister(&disk->queue->backing_dev_info);
205 blk_unregister_queue(disk); 207 blk_unregister_queue(disk);
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 78199c08ec92..c5b9bcfc0a6d 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -105,120 +105,12 @@ static int sg_emulated_host(struct request_queue *q, int __user *p)
105 return put_user(1, p); 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
114int 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}
214EXPORT_SYMBOL_GPL(blk_verify_command);
215
216static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, 108static 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 if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) 111 if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
220 return -EFAULT; 112 return -EFAULT;
221 if (blk_verify_command(rq->cmd, has_write_perm)) 113 if (blk_verify_command(file, rq->cmd))
222 return -EPERM; 114 return -EPERM;
223 115
224 /* 116 /*
@@ -287,7 +179,7 @@ static int sg_io(struct file *file, struct request_queue *q,
287 struct gendisk *bd_disk, struct sg_io_hdr *hdr) 179 struct gendisk *bd_disk, struct sg_io_hdr *hdr)
288{ 180{
289 unsigned long start_time; 181 unsigned long start_time;
290 int writing = 0, ret = 0, has_write_perm = 0; 182 int writing = 0, ret = 0;
291 struct request *rq; 183 struct request *rq;
292 char sense[SCSI_SENSE_BUFFERSIZE]; 184 char sense[SCSI_SENSE_BUFFERSIZE];
293 struct bio *bio; 185 struct bio *bio;
@@ -316,10 +208,7 @@ static int sg_io(struct file *file, struct request_queue *q,
316 if (!rq) 208 if (!rq)
317 return -ENOMEM; 209 return -ENOMEM;
318 210
319 if (file) 211 if (blk_fill_sghdr_rq(q, rq, hdr, file)) {
320 has_write_perm = file->f_mode & FMODE_WRITE;
321
322 if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) {
323 blk_put_request(rq); 212 blk_put_request(rq);
324 return -EFAULT; 213 return -EFAULT;
325 } 214 }
@@ -451,7 +340,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
451 if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) 340 if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
452 goto error; 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 if (err) 344 if (err)
456 goto error; 345 goto error;
457 346
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index ea0edd1b2e76..f7abccaffaec 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -182,8 +182,9 @@ static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
182 int tablesize); 182 int tablesize);
183static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, 183static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
184 Sg_request * srp); 184 Sg_request * srp);
185static ssize_t sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, 185static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
186 int blocking, int read_only, Sg_request ** o_srp); 186 const char __user *buf, size_t count, int blocking,
187 int read_only, Sg_request **o_srp);
187static int sg_common_write(Sg_fd * sfp, Sg_request * srp, 188static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
188 unsigned char *cmnd, int timeout, int blocking); 189 unsigned char *cmnd, int timeout, int blocking);
189static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind, 190static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
@@ -204,7 +205,6 @@ static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
204static Sg_request *sg_add_request(Sg_fd * sfp); 205static Sg_request *sg_add_request(Sg_fd * sfp);
205static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); 206static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
206static int sg_res_in_use(Sg_fd * sfp); 207static int sg_res_in_use(Sg_fd * sfp);
207static int sg_allow_access(unsigned char opcode, char dev_type);
208static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len); 208static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
209static Sg_device *sg_get_dev(int dev); 209static Sg_device *sg_get_dev(int dev);
210#ifdef CONFIG_SCSI_PROC_FS 210#ifdef CONFIG_SCSI_PROC_FS
@@ -544,7 +544,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
544 return -EFAULT; 544 return -EFAULT;
545 blocking = !(filp->f_flags & O_NONBLOCK); 545 blocking = !(filp->f_flags & O_NONBLOCK);
546 if (old_hdr.reply_len < 0) 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 if (count < (SZ_SG_HEADER + 6)) 548 if (count < (SZ_SG_HEADER + 6))
549 return -EIO; /* The minimum scsi command length is 6 bytes. */ 549 return -EIO; /* The minimum scsi command length is 6 bytes. */
550 550
@@ -621,8 +621,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
621} 621}
622 622
623static ssize_t 623static ssize_t
624sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, 624sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
625 int blocking, int read_only, Sg_request ** o_srp) 625 size_t count, int blocking, int read_only,
626 Sg_request **o_srp)
626{ 627{
627 int k; 628 int k;
628 Sg_request *srp; 629 Sg_request *srp;
@@ -678,8 +679,7 @@ sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
678 sg_remove_request(sfp, srp); 679 sg_remove_request(sfp, srp);
679 return -EFAULT; 680 return -EFAULT;
680 } 681 }
681 if (read_only && 682 if (read_only && (!blk_verify_command(file, cmnd))) {
682 (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
683 sg_remove_request(sfp, srp); 683 sg_remove_request(sfp, srp);
684 return -EPERM; 684 return -EPERM;
685 } 685 }
@@ -799,7 +799,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
799 if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) 799 if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
800 return -EFAULT; 800 return -EFAULT;
801 result = 801 result =
802 sg_new_write(sfp, p, SZ_SG_IO_HDR, 802 sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
803 blocking, read_only, &srp); 803 blocking, read_only, &srp);
804 if (result < 0) 804 if (result < 0)
805 return result; 805 return result;
@@ -1048,7 +1048,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
1048 1048
1049 if (copy_from_user(&opcode, siocp->data, 1)) 1049 if (copy_from_user(&opcode, siocp->data, 1))
1050 return -EFAULT; 1050 return -EFAULT;
1051 if (!sg_allow_access(opcode, sdp->device->type)) 1051 if (!blk_verify_command(filp, &opcode))
1052 return -EPERM; 1052 return -EPERM;
1053 } 1053 }
1054 return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p); 1054 return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p);
@@ -2506,26 +2506,6 @@ sg_page_free(struct page *page, int size)
2506#define MAINTENANCE_IN_CMD 0xa3 2506#define MAINTENANCE_IN_CMD 0xa3
2507#endif 2507#endif
2508 2508
2509static 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
2515static int
2516sg_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
2529#ifdef CONFIG_SCSI_PROC_FS 2509#ifdef CONFIG_SCSI_PROC_FS
2530static int 2510static int
2531sg_idr_max_id(int id, void *p, void *data) 2511sg_idr_max_id(int id, void *p, void *data)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index d3ae9ad97213..a842b776d099 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -671,7 +671,6 @@ extern int blk_execute_rq(struct request_queue *, struct gendisk *,
671 struct request *, int); 671 struct request *, int);
672extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *, 672extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
673 struct request *, int, rq_end_io_fn *); 673 struct request *, int, rq_end_io_fn *);
674extern int blk_verify_command(unsigned char *, int);
675extern void blk_unplug(struct request_queue *q); 674extern void blk_unplug(struct request_queue *q);
676 675
677static inline struct request_queue *bdev_get_queue(struct block_device *bdev) 676static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
@@ -797,6 +796,15 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
797 796
798extern int blkdev_issue_flush(struct block_device *, sector_t *); 797extern int blkdev_issue_flush(struct block_device *, sector_t *);
799 798
799/*
800* command filter functions
801*/
802extern int blk_verify_command(struct file *file, unsigned char *cmd);
803extern int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter,
804 unsigned char *cmd, mode_t *f_mode);
805extern int blk_register_filter(struct gendisk *disk);
806extern void blk_unregister_filter(struct gendisk *disk);
807
800#define MAX_PHYS_SEGMENTS 128 808#define MAX_PHYS_SEGMENTS 128
801#define MAX_HW_SEGMENTS 128 809#define MAX_HW_SEGMENTS 128
802#define SAFE_MAX_SECTORS 255 810#define SAFE_MAX_SECTORS 255
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 524ec96f5a23..e8787417f65a 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -110,6 +110,14 @@ struct hd_struct {
110#define GENHD_FL_SUPPRESS_PARTITION_INFO 32 110#define GENHD_FL_SUPPRESS_PARTITION_INFO 32
111#define GENHD_FL_FAIL 64 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))
115
116struct 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};
113 121
114struct gendisk { 122struct gendisk {
115 int major; /* major number of driver */ 123 int major; /* major number of driver */
@@ -120,6 +128,7 @@ struct gendisk {
120 struct hd_struct **part; /* [indexed by minor] */ 128 struct hd_struct **part; /* [indexed by minor] */
121 struct block_device_operations *fops; 129 struct block_device_operations *fops;
122 struct request_queue *queue; 130 struct request_queue *queue;
131 struct blk_scsi_cmd_filter cmd_filter;
123 void *private_data; 132 void *private_data;
124 sector_t capacity; 133 sector_t capacity;
125 134