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