at v2.6.28-rc1 232 lines 5.6 kB view raw
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/capability.h> 24#include <linux/bitops.h> 25 26#include <scsi/scsi.h> 27#include <linux/cdrom.h> 28 29int blk_verify_command(struct blk_cmd_filter *filter, 30 unsigned char *cmd, fmode_t has_write_perm) 31{ 32 /* root can do any command. */ 33 if (capable(CAP_SYS_RAWIO)) 34 return 0; 35 36 /* if there's no filter set, assume we're filtering everything out */ 37 if (!filter) 38 return -EPERM; 39 40 /* Anybody who can open the device can do a read-safe command */ 41 if (test_bit(cmd[0], filter->read_ok)) 42 return 0; 43 44 /* Write-safe commands require a writable open */ 45 if (test_bit(cmd[0], filter->write_ok) && has_write_perm) 46 return 0; 47 48 return -EPERM; 49} 50EXPORT_SYMBOL(blk_verify_command); 51 52#if 0 53/* and now, the sysfs stuff */ 54static ssize_t rcf_cmds_show(struct blk_cmd_filter *filter, char *page, 55 int rw) 56{ 57 char *npage = page; 58 unsigned long *okbits; 59 int i; 60 61 if (rw == READ) 62 okbits = filter->read_ok; 63 else 64 okbits = filter->write_ok; 65 66 for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) { 67 if (test_bit(i, okbits)) { 68 npage += sprintf(npage, "0x%02x", i); 69 if (i < BLK_SCSI_MAX_CMDS - 1) 70 sprintf(npage++, " "); 71 } 72 } 73 74 if (npage != page) 75 npage += sprintf(npage, "\n"); 76 77 return npage - page; 78} 79 80static ssize_t rcf_readcmds_show(struct blk_cmd_filter *filter, char *page) 81{ 82 return rcf_cmds_show(filter, page, READ); 83} 84 85static ssize_t rcf_writecmds_show(struct blk_cmd_filter *filter, 86 char *page) 87{ 88 return rcf_cmds_show(filter, page, WRITE); 89} 90 91static ssize_t rcf_cmds_store(struct blk_cmd_filter *filter, 92 const char *page, size_t count, int rw) 93{ 94 unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits; 95 int cmd, set; 96 char *p, *status; 97 98 if (rw == READ) { 99 memcpy(&okbits, filter->read_ok, sizeof(okbits)); 100 target_okbits = filter->read_ok; 101 } else { 102 memcpy(&okbits, filter->write_ok, sizeof(okbits)); 103 target_okbits = filter->write_ok; 104 } 105 106 while ((p = strsep((char **)&page, " ")) != NULL) { 107 set = 1; 108 109 if (p[0] == '+') { 110 p++; 111 } else if (p[0] == '-') { 112 set = 0; 113 p++; 114 } 115 116 cmd = simple_strtol(p, &status, 16); 117 118 /* either of these cases means invalid input, so do nothing. */ 119 if ((status == p) || cmd >= BLK_SCSI_MAX_CMDS) 120 return -EINVAL; 121 122 if (set) 123 __set_bit(cmd, okbits); 124 else 125 __clear_bit(cmd, okbits); 126 } 127 128 memcpy(target_okbits, okbits, sizeof(okbits)); 129 return count; 130} 131 132static ssize_t rcf_readcmds_store(struct blk_cmd_filter *filter, 133 const char *page, size_t count) 134{ 135 return rcf_cmds_store(filter, page, count, READ); 136} 137 138static ssize_t rcf_writecmds_store(struct blk_cmd_filter *filter, 139 const char *page, size_t count) 140{ 141 return rcf_cmds_store(filter, page, count, WRITE); 142} 143 144struct rcf_sysfs_entry { 145 struct attribute attr; 146 ssize_t (*show)(struct blk_cmd_filter *, char *); 147 ssize_t (*store)(struct blk_cmd_filter *, const char *, size_t); 148}; 149 150static struct rcf_sysfs_entry rcf_readcmds_entry = { 151 .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR }, 152 .show = rcf_readcmds_show, 153 .store = rcf_readcmds_store, 154}; 155 156static struct rcf_sysfs_entry rcf_writecmds_entry = { 157 .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR }, 158 .show = rcf_writecmds_show, 159 .store = rcf_writecmds_store, 160}; 161 162static struct attribute *default_attrs[] = { 163 &rcf_readcmds_entry.attr, 164 &rcf_writecmds_entry.attr, 165 NULL, 166}; 167 168#define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr) 169 170static ssize_t 171rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page) 172{ 173 struct rcf_sysfs_entry *entry = to_rcf(attr); 174 struct blk_cmd_filter *filter; 175 176 filter = container_of(kobj, struct blk_cmd_filter, kobj); 177 if (entry->show) 178 return entry->show(filter, page); 179 180 return 0; 181} 182 183static ssize_t 184rcf_attr_store(struct kobject *kobj, struct attribute *attr, 185 const char *page, size_t length) 186{ 187 struct rcf_sysfs_entry *entry = to_rcf(attr); 188 struct blk_cmd_filter *filter; 189 190 if (!capable(CAP_SYS_RAWIO)) 191 return -EPERM; 192 193 if (!entry->store) 194 return -EINVAL; 195 196 filter = container_of(kobj, struct blk_cmd_filter, kobj); 197 return entry->store(filter, page, length); 198} 199 200static struct sysfs_ops rcf_sysfs_ops = { 201 .show = rcf_attr_show, 202 .store = rcf_attr_store, 203}; 204 205static struct kobj_type rcf_ktype = { 206 .sysfs_ops = &rcf_sysfs_ops, 207 .default_attrs = default_attrs, 208}; 209 210int blk_register_filter(struct gendisk *disk) 211{ 212 int ret; 213 struct blk_cmd_filter *filter = &disk->queue->cmd_filter; 214 215 ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, 216 &disk_to_dev(disk)->kobj, 217 "%s", "cmd_filter"); 218 if (ret < 0) 219 return ret; 220 221 return 0; 222} 223EXPORT_SYMBOL(blk_register_filter); 224 225void blk_unregister_filter(struct gendisk *disk) 226{ 227 struct blk_cmd_filter *filter = &disk->queue->cmd_filter; 228 229 kobject_put(&filter->kobj); 230} 231EXPORT_SYMBOL(blk_unregister_filter); 232#endif