aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smackfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r--security/smack/smackfs.c254
1 files changed, 172 insertions, 82 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 76a5dca46404..53a08b85bda4 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -26,6 +26,7 @@
26#include <linux/seq_file.h> 26#include <linux/seq_file.h>
27#include <linux/ctype.h> 27#include <linux/ctype.h>
28#include <linux/audit.h> 28#include <linux/audit.h>
29#include <linux/magic.h>
29#include "smack.h" 30#include "smack.h"
30 31
31/* 32/*
@@ -50,12 +51,12 @@ enum smk_inos {
50 SMK_ACCESS2 = 16, /* make an access check with long labels */ 51 SMK_ACCESS2 = 16, /* make an access check with long labels */
51 SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ 52 SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
52 SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ 53 SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
54 SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
53}; 55};
54 56
55/* 57/*
56 * List locks 58 * List locks
57 */ 59 */
58static DEFINE_MUTEX(smack_list_lock);
59static DEFINE_MUTEX(smack_cipso_lock); 60static DEFINE_MUTEX(smack_cipso_lock);
60static DEFINE_MUTEX(smack_ambient_lock); 61static DEFINE_MUTEX(smack_ambient_lock);
61static DEFINE_MUTEX(smk_netlbladdr_lock); 62static DEFINE_MUTEX(smk_netlbladdr_lock);
@@ -110,6 +111,13 @@ struct smack_master_list {
110 111
111LIST_HEAD(smack_rule_list); 112LIST_HEAD(smack_rule_list);
112 113
114struct smack_parsed_rule {
115 char *smk_subject;
116 char *smk_object;
117 int smk_access1;
118 int smk_access2;
119};
120
113static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; 121static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
114 122
115const char *smack_cipso_option = SMACK_CIPSO_OPTION; 123const char *smack_cipso_option = SMACK_CIPSO_OPTION;
@@ -167,25 +175,28 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
167#define SMK_NETLBLADDRMIN 9 175#define SMK_NETLBLADDRMIN 9
168 176
169/** 177/**
170 * smk_set_access - add a rule to the rule list 178 * smk_set_access - add a rule to the rule list or replace an old rule
171 * @srp: the new rule to add 179 * @srp: the rule to add or replace
172 * @rule_list: the list of rules 180 * @rule_list: the list of rules
173 * @rule_lock: the rule list lock 181 * @rule_lock: the rule list lock
182 * @global: if non-zero, indicates a global rule
174 * 183 *
175 * Looks through the current subject/object/access list for 184 * Looks through the current subject/object/access list for
176 * the subject/object pair and replaces the access that was 185 * the subject/object pair and replaces the access that was
177 * there. If the pair isn't found add it with the specified 186 * there. If the pair isn't found add it with the specified
178 * access. 187 * access.
179 * 188 *
180 * Returns 1 if a rule was found to exist already, 0 if it is new
181 * Returns 0 if nothing goes wrong or -ENOMEM if it fails 189 * Returns 0 if nothing goes wrong or -ENOMEM if it fails
182 * during the allocation of the new pair to add. 190 * during the allocation of the new pair to add.
183 */ 191 */
184static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, 192static int smk_set_access(struct smack_parsed_rule *srp,
185 struct mutex *rule_lock) 193 struct list_head *rule_list,
194 struct mutex *rule_lock, int global)
186{ 195{
187 struct smack_rule *sp; 196 struct smack_rule *sp;
197 struct smack_master_list *smlp;
188 int found = 0; 198 int found = 0;
199 int rc = 0;
189 200
190 mutex_lock(rule_lock); 201 mutex_lock(rule_lock);
191 202
@@ -197,23 +208,89 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
197 if (sp->smk_object == srp->smk_object && 208 if (sp->smk_object == srp->smk_object &&
198 sp->smk_subject == srp->smk_subject) { 209 sp->smk_subject == srp->smk_subject) {
199 found = 1; 210 found = 1;
200 sp->smk_access = srp->smk_access; 211 sp->smk_access |= srp->smk_access1;
212 sp->smk_access &= ~srp->smk_access2;
201 break; 213 break;
202 } 214 }
203 } 215 }
204 if (found == 0)
205 list_add_rcu(&srp->list, rule_list);
206 216
217 if (found == 0) {
218 sp = kzalloc(sizeof(*sp), GFP_KERNEL);
219 if (sp == NULL) {
220 rc = -ENOMEM;
221 goto out;
222 }
223
224 sp->smk_subject = srp->smk_subject;
225 sp->smk_object = srp->smk_object;
226 sp->smk_access = srp->smk_access1 & ~srp->smk_access2;
227
228 list_add_rcu(&sp->list, rule_list);
229 /*
230 * If this is a global as opposed to self and a new rule
231 * it needs to get added for reporting.
232 */
233 if (global) {
234 smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
235 if (smlp != NULL) {
236 smlp->smk_rule = sp;
237 list_add_rcu(&smlp->list, &smack_rule_list);
238 } else
239 rc = -ENOMEM;
240 }
241 }
242
243out:
207 mutex_unlock(rule_lock); 244 mutex_unlock(rule_lock);
245 return rc;
246}
247
248/**
249 * smk_perm_from_str - parse smack accesses from a text string
250 * @string: a text string that contains a Smack accesses code
251 *
252 * Returns an integer with respective bits set for specified accesses.
253 */
254static int smk_perm_from_str(const char *string)
255{
256 int perm = 0;
257 const char *cp;
208 258
209 return found; 259 for (cp = string; ; cp++)
260 switch (*cp) {
261 case '-':
262 break;
263 case 'r':
264 case 'R':
265 perm |= MAY_READ;
266 break;
267 case 'w':
268 case 'W':
269 perm |= MAY_WRITE;
270 break;
271 case 'x':
272 case 'X':
273 perm |= MAY_EXEC;
274 break;
275 case 'a':
276 case 'A':
277 perm |= MAY_APPEND;
278 break;
279 case 't':
280 case 'T':
281 perm |= MAY_TRANSMUTE;
282 break;
283 default:
284 return perm;
285 }
210} 286}
211 287
212/** 288/**
213 * smk_fill_rule - Fill Smack rule from strings 289 * smk_fill_rule - Fill Smack rule from strings
214 * @subject: subject label string 290 * @subject: subject label string
215 * @object: object label string 291 * @object: object label string
216 * @access: access string 292 * @access1: access string
293 * @access2: string with permissions to be removed
217 * @rule: Smack rule 294 * @rule: Smack rule
218 * @import: if non-zero, import labels 295 * @import: if non-zero, import labels
219 * @len: label length limit 296 * @len: label length limit
@@ -221,8 +298,9 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
221 * Returns 0 on success, -1 on failure 298 * Returns 0 on success, -1 on failure
222 */ 299 */
223static int smk_fill_rule(const char *subject, const char *object, 300static int smk_fill_rule(const char *subject, const char *object,
224 const char *access, struct smack_rule *rule, 301 const char *access1, const char *access2,
225 int import, int len) 302 struct smack_parsed_rule *rule, int import,
303 int len)
226{ 304{
227 const char *cp; 305 const char *cp;
228 struct smack_known *skp; 306 struct smack_known *skp;
@@ -255,36 +333,11 @@ static int smk_fill_rule(const char *subject, const char *object,
255 rule->smk_object = skp->smk_known; 333 rule->smk_object = skp->smk_known;
256 } 334 }
257 335
258 rule->smk_access = 0; 336 rule->smk_access1 = smk_perm_from_str(access1);
259 337 if (access2)
260 for (cp = access; *cp != '\0'; cp++) { 338 rule->smk_access2 = smk_perm_from_str(access2);
261 switch (*cp) { 339 else
262 case '-': 340 rule->smk_access2 = ~rule->smk_access1;
263 break;
264 case 'r':
265 case 'R':
266 rule->smk_access |= MAY_READ;
267 break;
268 case 'w':
269 case 'W':
270 rule->smk_access |= MAY_WRITE;
271 break;
272 case 'x':
273 case 'X':
274 rule->smk_access |= MAY_EXEC;
275 break;
276 case 'a':
277 case 'A':
278 rule->smk_access |= MAY_APPEND;
279 break;
280 case 't':
281 case 'T':
282 rule->smk_access |= MAY_TRANSMUTE;
283 break;
284 default:
285 return 0;
286 }
287 }
288 341
289 return 0; 342 return 0;
290} 343}
@@ -297,30 +350,33 @@ static int smk_fill_rule(const char *subject, const char *object,
297 * 350 *
298 * Returns 0 on success, -1 on errors. 351 * Returns 0 on success, -1 on errors.
299 */ 352 */
300static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) 353static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
354 int import)
301{ 355{
302 int rc; 356 int rc;
303 357
304 rc = smk_fill_rule(data, data + SMK_LABELLEN, 358 rc = smk_fill_rule(data, data + SMK_LABELLEN,
305 data + SMK_LABELLEN + SMK_LABELLEN, rule, import, 359 data + SMK_LABELLEN + SMK_LABELLEN, NULL, rule,
306 SMK_LABELLEN); 360 import, SMK_LABELLEN);
307 return rc; 361 return rc;
308} 362}
309 363
310/** 364/**
311 * smk_parse_long_rule - parse Smack rule from rule string 365 * smk_parse_long_rule - parse Smack rule from rule string
312 * @data: string to be parsed, null terminated 366 * @data: string to be parsed, null terminated
313 * @rule: Smack rule 367 * @rule: Will be filled with Smack parsed rule
314 * @import: if non-zero, import labels 368 * @import: if non-zero, import labels
369 * @change: if non-zero, data is from /smack/change-rule
315 * 370 *
316 * Returns 0 on success, -1 on failure 371 * Returns 0 on success, -1 on failure
317 */ 372 */
318static int smk_parse_long_rule(const char *data, struct smack_rule *rule, 373static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule,
319 int import) 374 int import, int change)
320{ 375{
321 char *subject; 376 char *subject;
322 char *object; 377 char *object;
323 char *access; 378 char *access1;
379 char *access2;
324 int datalen; 380 int datalen;
325 int rc = -1; 381 int rc = -1;
326 382
@@ -334,14 +390,27 @@ static int smk_parse_long_rule(const char *data, struct smack_rule *rule,
334 object = kzalloc(datalen, GFP_KERNEL); 390 object = kzalloc(datalen, GFP_KERNEL);
335 if (object == NULL) 391 if (object == NULL)
336 goto free_out_s; 392 goto free_out_s;
337 access = kzalloc(datalen, GFP_KERNEL); 393 access1 = kzalloc(datalen, GFP_KERNEL);
338 if (access == NULL) 394 if (access1 == NULL)
339 goto free_out_o; 395 goto free_out_o;
396 access2 = kzalloc(datalen, GFP_KERNEL);
397 if (access2 == NULL)
398 goto free_out_a;
399
400 if (change) {
401 if (sscanf(data, "%s %s %s %s",
402 subject, object, access1, access2) == 4)
403 rc = smk_fill_rule(subject, object, access1, access2,
404 rule, import, 0);
405 } else {
406 if (sscanf(data, "%s %s %s", subject, object, access1) == 3)
407 rc = smk_fill_rule(subject, object, access1, NULL,
408 rule, import, 0);
409 }
340 410
341 if (sscanf(data, "%s %s %s", subject, object, access) == 3) 411 kfree(access2);
342 rc = smk_fill_rule(subject, object, access, rule, import, 0); 412free_out_a:
343 413 kfree(access1);
344 kfree(access);
345free_out_o: 414free_out_o:
346 kfree(object); 415 kfree(object);
347free_out_s: 416free_out_s:
@@ -351,6 +420,7 @@ free_out_s:
351 420
352#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ 421#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
353#define SMK_LONG_FMT 1 /* Variable long label format */ 422#define SMK_LONG_FMT 1 /* Variable long label format */
423#define SMK_CHANGE_FMT 2 /* Rule modification format */
354/** 424/**
355 * smk_write_rules_list - write() for any /smack rule file 425 * smk_write_rules_list - write() for any /smack rule file
356 * @file: file pointer, not actually used 426 * @file: file pointer, not actually used
@@ -359,22 +429,24 @@ free_out_s:
359 * @ppos: where to start - must be 0 429 * @ppos: where to start - must be 0
360 * @rule_list: the list of rules to write to 430 * @rule_list: the list of rules to write to
361 * @rule_lock: lock for the rule list 431 * @rule_lock: lock for the rule list
362 * @format: /smack/load or /smack/load2 format. 432 * @format: /smack/load or /smack/load2 or /smack/change-rule format.
363 * 433 *
364 * Get one smack access rule from above. 434 * Get one smack access rule from above.
365 * The format for SMK_LONG_FMT is: 435 * The format for SMK_LONG_FMT is:
366 * "subject<whitespace>object<whitespace>access[<whitespace>...]" 436 * "subject<whitespace>object<whitespace>access[<whitespace>...]"
367 * The format for SMK_FIXED24_FMT is exactly: 437 * The format for SMK_FIXED24_FMT is exactly:
368 * "subject object rwxat" 438 * "subject object rwxat"
439 * The format for SMK_CHANGE_FMT is:
440 * "subject<whitespace>object<whitespace>
441 * acc_enable<whitespace>acc_disable[<whitespace>...]"
369 */ 442 */
370static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, 443static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
371 size_t count, loff_t *ppos, 444 size_t count, loff_t *ppos,
372 struct list_head *rule_list, 445 struct list_head *rule_list,
373 struct mutex *rule_lock, int format) 446 struct mutex *rule_lock, int format)
374{ 447{
375 struct smack_master_list *smlp;
376 struct smack_known *skp; 448 struct smack_known *skp;
377 struct smack_rule *rule; 449 struct smack_parsed_rule *rule;
378 char *data; 450 char *data;
379 int datalen; 451 int datalen;
380 int rc = -EINVAL; 452 int rc = -EINVAL;
@@ -417,7 +489,11 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
417 * Be sure the data string is terminated. 489 * Be sure the data string is terminated.
418 */ 490 */
419 data[count] = '\0'; 491 data[count] = '\0';
420 if (smk_parse_long_rule(data, rule, 1)) 492 if (smk_parse_long_rule(data, rule, 1, 0))
493 goto out_free_rule;
494 } else if (format == SMK_CHANGE_FMT) {
495 data[count] = '\0';
496 if (smk_parse_long_rule(data, rule, 1, 1))
421 goto out_free_rule; 497 goto out_free_rule;
422 } else { 498 } else {
423 /* 499 /*
@@ -437,22 +513,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
437 rule_lock = &skp->smk_rules_lock; 513 rule_lock = &skp->smk_rules_lock;
438 } 514 }
439 515
440 rc = count; 516 rc = smk_set_access(rule, rule_list, rule_lock, load);
441 /* 517 if (rc == 0) {
442 * If this is a global as opposed to self and a new rule 518 rc = count;
443 * it needs to get added for reporting.
444 * smk_set_access returns true if there was already a rule
445 * for the subject/object pair, and false if it was new.
446 */
447 if (!smk_set_access(rule, rule_list, rule_lock)) {
448 if (load) {
449 smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
450 if (smlp != NULL) {
451 smlp->smk_rule = rule;
452 list_add_rcu(&smlp->list, &smack_rule_list);
453 } else
454 rc = -ENOMEM;
455 }
456 goto out; 519 goto out;
457 } 520 }
458 521
@@ -1774,7 +1837,7 @@ static const struct file_operations smk_load_self_ops = {
1774static ssize_t smk_user_access(struct file *file, const char __user *buf, 1837static ssize_t smk_user_access(struct file *file, const char __user *buf,
1775 size_t count, loff_t *ppos, int format) 1838 size_t count, loff_t *ppos, int format)
1776{ 1839{
1777 struct smack_rule rule; 1840 struct smack_parsed_rule rule;
1778 char *data; 1841 char *data;
1779 char *cod; 1842 char *cod;
1780 int res; 1843 int res;
@@ -1796,14 +1859,14 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
1796 return -ENOMEM; 1859 return -ENOMEM;
1797 memcpy(cod, data, count); 1860 memcpy(cod, data, count);
1798 cod[count] = '\0'; 1861 cod[count] = '\0';
1799 res = smk_parse_long_rule(cod, &rule, 0); 1862 res = smk_parse_long_rule(cod, &rule, 0, 0);
1800 kfree(cod); 1863 kfree(cod);
1801 } 1864 }
1802 1865
1803 if (res) 1866 if (res)
1804 return -EINVAL; 1867 return -EINVAL;
1805 1868
1806 res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, 1869 res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access1,
1807 NULL); 1870 NULL);
1808 data[0] = res == 0 ? '1' : '0'; 1871 data[0] = res == 0 ? '1' : '0';
1809 data[1] = '\0'; 1872 data[1] = '\0';
@@ -2035,10 +2098,8 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
2035 } 2098 }
2036 2099
2037 skp = smk_find_entry(cp); 2100 skp = smk_find_entry(cp);
2038 if (skp == NULL) { 2101 if (skp == NULL)
2039 rc = -EINVAL;
2040 goto free_out; 2102 goto free_out;
2041 }
2042 2103
2043 rule_list = &skp->smk_rules; 2104 rule_list = &skp->smk_rules;
2044 rule_lock = &skp->smk_rules_lock; 2105 rule_lock = &skp->smk_rules_lock;
@@ -2077,6 +2138,33 @@ static int smk_init_sysfs(void)
2077} 2138}
2078 2139
2079/** 2140/**
2141 * smk_write_change_rule - write() for /smack/change-rule
2142 * @file: file pointer
2143 * @buf: data from user space
2144 * @count: bytes sent
2145 * @ppos: where to start - must be 0
2146 */
2147static ssize_t smk_write_change_rule(struct file *file, const char __user *buf,
2148 size_t count, loff_t *ppos)
2149{
2150 /*
2151 * Must have privilege.
2152 */
2153 if (!capable(CAP_MAC_ADMIN))
2154 return -EPERM;
2155
2156 return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,
2157 SMK_CHANGE_FMT);
2158}
2159
2160static const struct file_operations smk_change_rule_ops = {
2161 .write = smk_write_change_rule,
2162 .read = simple_transaction_read,
2163 .release = simple_transaction_release,
2164 .llseek = generic_file_llseek,
2165};
2166
2167/**
2080 * smk_fill_super - fill the /smackfs superblock 2168 * smk_fill_super - fill the /smackfs superblock
2081 * @sb: the empty superblock 2169 * @sb: the empty superblock
2082 * @data: unused 2170 * @data: unused
@@ -2125,6 +2213,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
2125 [SMK_REVOKE_SUBJ] = { 2213 [SMK_REVOKE_SUBJ] = {
2126 "revoke-subject", &smk_revoke_subj_ops, 2214 "revoke-subject", &smk_revoke_subj_ops,
2127 S_IRUGO|S_IWUSR}, 2215 S_IRUGO|S_IWUSR},
2216 [SMK_CHANGE_RULE] = {
2217 "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
2128 /* last one */ 2218 /* last one */
2129 {""} 2219 {""}
2130 }; 2220 };