diff options
-rw-r--r-- | block/Makefile | 3 | ||||
-rw-r--r-- | block/bsg.c | 38 | ||||
-rw-r--r-- | block/cmd-filter.c | 325 | ||||
-rw-r--r-- | block/genhd.c | 2 | ||||
-rw-r--r-- | block/scsi_ioctl.c | 121 | ||||
-rw-r--r-- | drivers/scsi/sg.c | 40 | ||||
-rw-r--r-- | include/linux/blkdev.h | 10 | ||||
-rw-r--r-- | include/linux/genhd.h | 9 |
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 | ||
5 | obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \ | 5 | obj-$(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 | ||
9 | obj-$(CONFIG_BLK_DEV_BSG) += bsg.o | 10 | obj-$(CONFIG_BLK_DEV_BSG) += bsg.o |
10 | obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o | 11 | obj-$(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 | ||
49 | enum { | 51 | enum { |
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 | ||
174 | static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, | 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 | 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 | ||
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) | 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 | |||
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 | } | ||
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 | ||
201 | void unlink_gendisk(struct gendisk *disk) | 202 | void 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 | |||
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 | static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, | 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 | 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); |
183 | static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, | 183 | static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, |
184 | Sg_request * srp); | 184 | Sg_request * srp); |
185 | static ssize_t sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, | 185 | static 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); | ||
187 | static int sg_common_write(Sg_fd * sfp, Sg_request * srp, | 188 | static 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); |
189 | static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind, | 190 | static 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); | |||
204 | static Sg_request *sg_add_request(Sg_fd * sfp); | 205 | static Sg_request *sg_add_request(Sg_fd * sfp); |
205 | static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); | 206 | static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); |
206 | static int sg_res_in_use(Sg_fd * sfp); | 207 | static int sg_res_in_use(Sg_fd * sfp); |
207 | static int sg_allow_access(unsigned char opcode, char dev_type); | ||
208 | static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len); | 208 | static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len); |
209 | static Sg_device *sg_get_dev(int dev); | 209 | static 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 | ||
623 | static ssize_t | 623 | static ssize_t |
624 | sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, | 624 | sg_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 | ||
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 | |||
2529 | #ifdef CONFIG_SCSI_PROC_FS | 2509 | #ifdef CONFIG_SCSI_PROC_FS |
2530 | static int | 2510 | static int |
2531 | sg_idr_max_id(int id, void *p, void *data) | 2511 | sg_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); |
672 | extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *, | 672 | extern 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 *); |
674 | extern int blk_verify_command(unsigned char *, int); | ||
675 | extern void blk_unplug(struct request_queue *q); | 674 | extern void blk_unplug(struct request_queue *q); |
676 | 675 | ||
677 | static inline struct request_queue *bdev_get_queue(struct block_device *bdev) | 676 | static 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 | ||
798 | extern int blkdev_issue_flush(struct block_device *, sector_t *); | 797 | extern int blkdev_issue_flush(struct block_device *, sector_t *); |
799 | 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); | ||
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 | |||
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 | }; | ||
113 | 121 | ||
114 | struct gendisk { | 122 | struct 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 | ||