diff options
| -rw-r--r-- | security/smack/smackfs.c | 180 | 
1 files changed, 117 insertions, 63 deletions
| diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index f93460156dce..f4c28eeba1b1 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -44,6 +44,7 @@ enum smk_inos { | |||
| 44 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 44 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 
| 45 | SMK_LOGGING = 10, /* logging */ | 45 | SMK_LOGGING = 10, /* logging */ | 
| 46 | SMK_LOAD_SELF = 11, /* task specific rules */ | 46 | SMK_LOAD_SELF = 11, /* task specific rules */ | 
| 47 | SMK_ACCESSES = 12, /* access policy */ | ||
| 47 | }; | 48 | }; | 
| 48 | 49 | ||
| 49 | /* | 50 | /* | 
| @@ -176,71 +177,19 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, | |||
| 176 | } | 177 | } | 
| 177 | 178 | ||
| 178 | /** | 179 | /** | 
| 179 | * smk_write_load_list - write() for any /smack/load | 180 | * smk_parse_rule - parse subject, object and access type | 
| 180 | * @file: file pointer, not actually used | 181 | * @data: string to be parsed whose size is SMK_LOADLEN | 
| 181 | * @buf: where to get the data from | 182 | * @rule: parsed entities are stored in here | 
| 182 | * @count: bytes sent | ||
| 183 | * @ppos: where to start - must be 0 | ||
| 184 | * @rule_list: the list of rules to write to | ||
| 185 | * @rule_lock: lock for the rule list | ||
| 186 | * | ||
| 187 | * Get one smack access rule from above. | ||
| 188 | * The format is exactly: | ||
| 189 | * char subject[SMK_LABELLEN] | ||
| 190 | * char object[SMK_LABELLEN] | ||
| 191 | * char access[SMK_ACCESSLEN] | ||
| 192 | * | ||
| 193 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. | ||
| 194 | */ | 183 | */ | 
| 195 | static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | 184 | static int smk_parse_rule(const char *data, struct smack_rule *rule) | 
| 196 | size_t count, loff_t *ppos, | ||
| 197 | struct list_head *rule_list, | ||
| 198 | struct mutex *rule_lock) | ||
| 199 | { | 185 | { | 
| 200 | struct smack_rule *rule; | ||
| 201 | char *data; | ||
| 202 | int rc = -EINVAL; | ||
| 203 | |||
| 204 | /* | ||
| 205 | * No partial writes. | ||
| 206 | * Enough data must be present. | ||
| 207 | */ | ||
| 208 | if (*ppos != 0) | ||
| 209 | return -EINVAL; | ||
| 210 | /* | ||
| 211 | * Minor hack for backward compatibility | ||
| 212 | */ | ||
| 213 | if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) | ||
| 214 | return -EINVAL; | ||
| 215 | |||
| 216 | data = kzalloc(SMK_LOADLEN, GFP_KERNEL); | ||
| 217 | if (data == NULL) | ||
| 218 | return -ENOMEM; | ||
| 219 | |||
| 220 | if (copy_from_user(data, buf, count) != 0) { | ||
| 221 | rc = -EFAULT; | ||
| 222 | goto out; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* | ||
| 226 | * More on the minor hack for backward compatibility | ||
| 227 | */ | ||
| 228 | if (count == (SMK_OLOADLEN)) | ||
| 229 | data[SMK_OLOADLEN] = '-'; | ||
| 230 | |||
| 231 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); | ||
| 232 | if (rule == NULL) { | ||
| 233 | rc = -ENOMEM; | ||
| 234 | goto out; | ||
| 235 | } | ||
| 236 | |||
| 237 | rule->smk_subject = smk_import(data, 0); | 186 | rule->smk_subject = smk_import(data, 0); | 
| 238 | if (rule->smk_subject == NULL) | 187 | if (rule->smk_subject == NULL) | 
| 239 | goto out_free_rule; | 188 | return -1; | 
| 240 | 189 | ||
| 241 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); | 190 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); | 
| 242 | if (rule->smk_object == NULL) | 191 | if (rule->smk_object == NULL) | 
| 243 | goto out_free_rule; | 192 | return -1; | 
| 244 | 193 | ||
| 245 | rule->smk_access = 0; | 194 | rule->smk_access = 0; | 
| 246 | 195 | ||
| @@ -252,7 +201,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
| 252 | rule->smk_access |= MAY_READ; | 201 | rule->smk_access |= MAY_READ; | 
| 253 | break; | 202 | break; | 
| 254 | default: | 203 | default: | 
| 255 | goto out_free_rule; | 204 | return -1; | 
| 256 | } | 205 | } | 
| 257 | 206 | ||
| 258 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { | 207 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { | 
| @@ -263,7 +212,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
| 263 | rule->smk_access |= MAY_WRITE; | 212 | rule->smk_access |= MAY_WRITE; | 
| 264 | break; | 213 | break; | 
| 265 | default: | 214 | default: | 
| 266 | goto out_free_rule; | 215 | return -1; | 
| 267 | } | 216 | } | 
| 268 | 217 | ||
| 269 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { | 218 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { | 
| @@ -274,7 +223,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
| 274 | rule->smk_access |= MAY_EXEC; | 223 | rule->smk_access |= MAY_EXEC; | 
| 275 | break; | 224 | break; | 
| 276 | default: | 225 | default: | 
| 277 | goto out_free_rule; | 226 | return -1; | 
| 278 | } | 227 | } | 
| 279 | 228 | ||
| 280 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { | 229 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { | 
| @@ -285,7 +234,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
| 285 | rule->smk_access |= MAY_APPEND; | 234 | rule->smk_access |= MAY_APPEND; | 
| 286 | break; | 235 | break; | 
| 287 | default: | 236 | default: | 
| 288 | goto out_free_rule; | 237 | return -1; | 
| 289 | } | 238 | } | 
| 290 | 239 | ||
| 291 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { | 240 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { | 
| @@ -296,9 +245,74 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
| 296 | rule->smk_access |= MAY_TRANSMUTE; | 245 | rule->smk_access |= MAY_TRANSMUTE; | 
| 297 | break; | 246 | break; | 
| 298 | default: | 247 | default: | 
| 299 | goto out_free_rule; | 248 | return -1; | 
| 300 | } | 249 | } | 
| 301 | 250 | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | /** | ||
| 255 | * smk_write_load_list - write() for any /smack/load | ||
| 256 | * @file: file pointer, not actually used | ||
| 257 | * @buf: where to get the data from | ||
| 258 | * @count: bytes sent | ||
| 259 | * @ppos: where to start - must be 0 | ||
| 260 | * @rule_list: the list of rules to write to | ||
| 261 | * @rule_lock: lock for the rule list | ||
| 262 | * | ||
| 263 | * Get one smack access rule from above. | ||
| 264 | * The format is exactly: | ||
| 265 | * char subject[SMK_LABELLEN] | ||
| 266 | * char object[SMK_LABELLEN] | ||
| 267 | * char access[SMK_ACCESSLEN] | ||
| 268 | * | ||
| 269 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. | ||
| 270 | */ | ||
| 271 | static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | ||
| 272 | size_t count, loff_t *ppos, | ||
| 273 | struct list_head *rule_list, | ||
| 274 | struct mutex *rule_lock) | ||
| 275 | { | ||
| 276 | struct smack_rule *rule; | ||
| 277 | char *data; | ||
| 278 | int rc = -EINVAL; | ||
| 279 | |||
| 280 | /* | ||
| 281 | * No partial writes. | ||
| 282 | * Enough data must be present. | ||
| 283 | */ | ||
| 284 | if (*ppos != 0) | ||
| 285 | return -EINVAL; | ||
| 286 | /* | ||
| 287 | * Minor hack for backward compatibility | ||
| 288 | */ | ||
| 289 | if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) | ||
| 290 | return -EINVAL; | ||
| 291 | |||
| 292 | data = kzalloc(SMK_LOADLEN, GFP_KERNEL); | ||
| 293 | if (data == NULL) | ||
| 294 | return -ENOMEM; | ||
| 295 | |||
| 296 | if (copy_from_user(data, buf, count) != 0) { | ||
| 297 | rc = -EFAULT; | ||
| 298 | goto out; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* | ||
| 302 | * More on the minor hack for backward compatibility | ||
| 303 | */ | ||
| 304 | if (count == (SMK_OLOADLEN)) | ||
| 305 | data[SMK_OLOADLEN] = '-'; | ||
| 306 | |||
| 307 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); | ||
| 308 | if (rule == NULL) { | ||
| 309 | rc = -ENOMEM; | ||
| 310 | goto out; | ||
| 311 | } | ||
| 312 | |||
| 313 | if (smk_parse_rule(data, rule)) | ||
| 314 | goto out_free_rule; | ||
| 315 | |||
| 302 | rc = count; | 316 | rc = count; | 
| 303 | /* | 317 | /* | 
| 304 | * smk_set_access returns true if there was already a rule | 318 | * smk_set_access returns true if there was already a rule | 
| @@ -1425,6 +1439,44 @@ static const struct file_operations smk_load_self_ops = { | |||
| 1425 | .write = smk_write_load_self, | 1439 | .write = smk_write_load_self, | 
| 1426 | .release = seq_release, | 1440 | .release = seq_release, | 
| 1427 | }; | 1441 | }; | 
| 1442 | |||
| 1443 | /** | ||
| 1444 | * smk_write_access - handle access check transaction | ||
| 1445 | * @file: file pointer | ||
| 1446 | * @buf: data from user space | ||
| 1447 | * @count: bytes sent | ||
| 1448 | * @ppos: where to start - must be 0 | ||
| 1449 | */ | ||
| 1450 | static ssize_t smk_write_access(struct file *file, const char __user *buf, | ||
| 1451 | size_t count, loff_t *ppos) | ||
| 1452 | { | ||
| 1453 | struct smack_rule rule; | ||
| 1454 | char *data; | ||
| 1455 | |||
| 1456 | if (!capable(CAP_MAC_ADMIN)) | ||
| 1457 | return -EPERM; | ||
| 1458 | |||
| 1459 | data = simple_transaction_get(file, buf, count); | ||
| 1460 | if (IS_ERR(data)) | ||
| 1461 | return PTR_ERR(data); | ||
| 1462 | |||
| 1463 | if (count < SMK_LOADLEN || smk_parse_rule(data, &rule)) | ||
| 1464 | return -EINVAL; | ||
| 1465 | |||
| 1466 | data[0] = smk_access(rule.smk_subject, rule.smk_object, | ||
| 1467 | rule.smk_access, NULL) == 0; | ||
| 1468 | |||
| 1469 | simple_transaction_set(file, 1); | ||
| 1470 | return SMK_LOADLEN; | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | static const struct file_operations smk_access_ops = { | ||
| 1474 | .write = smk_write_access, | ||
| 1475 | .read = simple_transaction_read, | ||
| 1476 | .release = simple_transaction_release, | ||
| 1477 | .llseek = generic_file_llseek, | ||
| 1478 | }; | ||
| 1479 | |||
| 1428 | /** | 1480 | /** | 
| 1429 | * smk_fill_super - fill the /smackfs superblock | 1481 | * smk_fill_super - fill the /smackfs superblock | 
| 1430 | * @sb: the empty superblock | 1482 | * @sb: the empty superblock | 
| @@ -1459,6 +1511,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1459 | "logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, | 1511 | "logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, | 
| 1460 | [SMK_LOAD_SELF] = { | 1512 | [SMK_LOAD_SELF] = { | 
| 1461 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, | 1513 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, | 
| 1514 | [SMK_ACCESSES] = { | ||
| 1515 | "access", &smk_access_ops, S_IRUGO|S_IWUSR}, | ||
| 1462 | /* last one */ | 1516 | /* last one */ | 
| 1463 | {""} | 1517 | {""} | 
| 1464 | }; | 1518 | }; | 
