diff options
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 151 |
2 files changed, 116 insertions, 40 deletions
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 4865f61f9044..681cb6e72257 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -36,7 +36,10 @@ __setup("ima_appraise=", default_appraise_setup); | |||
36 | */ | 36 | */ |
37 | int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask) | 37 | int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask) |
38 | { | 38 | { |
39 | return 0; | 39 | if (!ima_appraise) |
40 | return 0; | ||
41 | |||
42 | return ima_match_policy(inode, func, mask, IMA_APPRAISE); | ||
40 | } | 43 | } |
41 | 44 | ||
42 | static void ima_fix_xattr(struct dentry *dentry, | 45 | static void ima_fix_xattr(struct dentry *dentry, |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 3e22e17da295..0d6d60b4ba6f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #define IMA_MASK 0x0002 | 24 | #define IMA_MASK 0x0002 |
25 | #define IMA_FSMAGIC 0x0004 | 25 | #define IMA_FSMAGIC 0x0004 |
26 | #define IMA_UID 0x0008 | 26 | #define IMA_UID 0x0008 |
27 | #define IMA_FOWNER 0x0010 | ||
27 | 28 | ||
28 | #define UNKNOWN 0 | 29 | #define UNKNOWN 0 |
29 | #define MEASURE 1 /* same as IMA_MEASURE */ | 30 | #define MEASURE 1 /* same as IMA_MEASURE */ |
@@ -38,7 +39,7 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | |||
38 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | 39 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE |
39 | }; | 40 | }; |
40 | 41 | ||
41 | struct ima_measure_rule_entry { | 42 | struct ima_rule_entry { |
42 | struct list_head list; | 43 | struct list_head list; |
43 | int action; | 44 | int action; |
44 | unsigned int flags; | 45 | unsigned int flags; |
@@ -46,6 +47,7 @@ struct ima_measure_rule_entry { | |||
46 | int mask; | 47 | int mask; |
47 | unsigned long fsmagic; | 48 | unsigned long fsmagic; |
48 | uid_t uid; | 49 | uid_t uid; |
50 | uid_t fowner; | ||
49 | struct { | 51 | struct { |
50 | void *rule; /* LSM file metadata specific */ | 52 | void *rule; /* LSM file metadata specific */ |
51 | int type; /* audit type */ | 53 | int type; /* audit type */ |
@@ -54,7 +56,7 @@ struct ima_measure_rule_entry { | |||
54 | 56 | ||
55 | /* | 57 | /* |
56 | * Without LSM specific knowledge, the default policy can only be | 58 | * Without LSM specific knowledge, the default policy can only be |
57 | * written in terms of .action, .func, .mask, .fsmagic, and .uid | 59 | * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner |
58 | */ | 60 | */ |
59 | 61 | ||
60 | /* | 62 | /* |
@@ -63,7 +65,7 @@ struct ima_measure_rule_entry { | |||
63 | * normal users can easily run the machine out of memory simply building | 65 | * normal users can easily run the machine out of memory simply building |
64 | * and running executables. | 66 | * and running executables. |
65 | */ | 67 | */ |
66 | static struct ima_measure_rule_entry default_rules[] = { | 68 | static struct ima_rule_entry default_rules[] = { |
67 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | 69 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, |
68 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, | 70 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, |
69 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | 71 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, |
@@ -81,19 +83,41 @@ static struct ima_measure_rule_entry default_rules[] = { | |||
81 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | 83 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
82 | }; | 84 | }; |
83 | 85 | ||
84 | static LIST_HEAD(measure_default_rules); | 86 | static struct ima_rule_entry default_appraise_rules[] = { |
85 | static LIST_HEAD(measure_policy_rules); | 87 | {.action = DONT_APPRAISE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, |
86 | static struct list_head *ima_measure; | 88 | {.action = DONT_APPRAISE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, |
89 | {.action = DONT_APPRAISE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
90 | {.action = DONT_APPRAISE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
91 | {.action = DONT_APPRAISE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
92 | {.action = DONT_APPRAISE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | ||
93 | {.action = DONT_APPRAISE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
94 | {.action = DONT_APPRAISE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
95 | {.action = DONT_APPRAISE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, | ||
96 | {.action = DONT_APPRAISE,.fsmagic = CGROUP_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | ||
97 | {.action = APPRAISE,.fowner = 0,.flags = IMA_FOWNER}, | ||
98 | }; | ||
99 | |||
100 | static LIST_HEAD(ima_default_rules); | ||
101 | static LIST_HEAD(ima_policy_rules); | ||
102 | static struct list_head *ima_rules; | ||
87 | 103 | ||
88 | static DEFINE_MUTEX(ima_measure_mutex); | 104 | static DEFINE_MUTEX(ima_rules_mutex); |
89 | 105 | ||
90 | static bool ima_use_tcb __initdata; | 106 | static bool ima_use_tcb __initdata; |
91 | static int __init default_policy_setup(char *str) | 107 | static int __init default_measure_policy_setup(char *str) |
92 | { | 108 | { |
93 | ima_use_tcb = 1; | 109 | ima_use_tcb = 1; |
94 | return 1; | 110 | return 1; |
95 | } | 111 | } |
96 | __setup("ima_tcb", default_policy_setup); | 112 | __setup("ima_tcb", default_measure_policy_setup); |
113 | |||
114 | static bool ima_use_appraise_tcb __initdata; | ||
115 | static int __init default_appraise_policy_setup(char *str) | ||
116 | { | ||
117 | ima_use_appraise_tcb = 1; | ||
118 | return 1; | ||
119 | } | ||
120 | __setup("ima_appraise_tcb", default_appraise_policy_setup); | ||
97 | 121 | ||
98 | /** | 122 | /** |
99 | * ima_match_rules - determine whether an inode matches the measure rule. | 123 | * ima_match_rules - determine whether an inode matches the measure rule. |
@@ -104,7 +128,7 @@ __setup("ima_tcb", default_policy_setup); | |||
104 | * | 128 | * |
105 | * Returns true on rule match, false on failure. | 129 | * Returns true on rule match, false on failure. |
106 | */ | 130 | */ |
107 | static bool ima_match_rules(struct ima_measure_rule_entry *rule, | 131 | static bool ima_match_rules(struct ima_rule_entry *rule, |
108 | struct inode *inode, enum ima_hooks func, int mask) | 132 | struct inode *inode, enum ima_hooks func, int mask) |
109 | { | 133 | { |
110 | struct task_struct *tsk = current; | 134 | struct task_struct *tsk = current; |
@@ -120,6 +144,8 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
120 | return false; | 144 | return false; |
121 | if ((rule->flags & IMA_UID) && rule->uid != cred->uid) | 145 | if ((rule->flags & IMA_UID) && rule->uid != cred->uid) |
122 | return false; | 146 | return false; |
147 | if ((rule->flags & IMA_FOWNER) && rule->fowner != inode->i_uid) | ||
148 | return false; | ||
123 | for (i = 0; i < MAX_LSM_RULES; i++) { | 149 | for (i = 0; i < MAX_LSM_RULES; i++) { |
124 | int rc = 0; | 150 | int rc = 0; |
125 | u32 osid, sid; | 151 | u32 osid, sid; |
@@ -172,10 +198,10 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
172 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | 198 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
173 | int flags) | 199 | int flags) |
174 | { | 200 | { |
175 | struct ima_measure_rule_entry *entry; | 201 | struct ima_rule_entry *entry; |
176 | int action = 0, actmask = flags | (flags << 1); | 202 | int action = 0, actmask = flags | (flags << 1); |
177 | 203 | ||
178 | list_for_each_entry(entry, ima_measure, list) { | 204 | list_for_each_entry(entry, ima_rules, list) { |
179 | 205 | ||
180 | if (!(entry->action & actmask)) | 206 | if (!(entry->action & actmask)) |
181 | continue; | 207 | continue; |
@@ -196,22 +222,31 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | |||
196 | /** | 222 | /** |
197 | * ima_init_policy - initialize the default measure rules. | 223 | * ima_init_policy - initialize the default measure rules. |
198 | * | 224 | * |
199 | * ima_measure points to either the measure_default_rules or the | 225 | * ima_rules points to either the ima_default_rules or the |
200 | * the new measure_policy_rules. | 226 | * the new ima_policy_rules. |
201 | */ | 227 | */ |
202 | void __init ima_init_policy(void) | 228 | void __init ima_init_policy(void) |
203 | { | 229 | { |
204 | int i, entries; | 230 | int i, measure_entries, appraise_entries; |
205 | 231 | ||
206 | /* if !ima_use_tcb set entries = 0 so we load NO default rules */ | 232 | /* if !ima_use_tcb set entries = 0 so we load NO default rules */ |
207 | if (ima_use_tcb) | 233 | measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0; |
208 | entries = ARRAY_SIZE(default_rules); | 234 | appraise_entries = ima_use_appraise_tcb ? |
209 | else | 235 | ARRAY_SIZE(default_appraise_rules) : 0; |
210 | entries = 0; | 236 | |
211 | 237 | for (i = 0; i < measure_entries + appraise_entries; i++) { | |
212 | for (i = 0; i < entries; i++) | 238 | if (i < measure_entries) |
213 | list_add_tail(&default_rules[i].list, &measure_default_rules); | 239 | list_add_tail(&default_rules[i].list, |
214 | ima_measure = &measure_default_rules; | 240 | &ima_default_rules); |
241 | else { | ||
242 | int j = i - measure_entries; | ||
243 | |||
244 | list_add_tail(&default_appraise_rules[j].list, | ||
245 | &ima_default_rules); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | ima_rules = &ima_default_rules; | ||
215 | } | 250 | } |
216 | 251 | ||
217 | /** | 252 | /** |
@@ -228,8 +263,8 @@ void ima_update_policy(void) | |||
228 | int result = 1; | 263 | int result = 1; |
229 | int audit_info = 0; | 264 | int audit_info = 0; |
230 | 265 | ||
231 | if (ima_measure == &measure_default_rules) { | 266 | if (ima_rules == &ima_default_rules) { |
232 | ima_measure = &measure_policy_rules; | 267 | ima_rules = &ima_policy_rules; |
233 | cause = "complete"; | 268 | cause = "complete"; |
234 | result = 0; | 269 | result = 0; |
235 | } | 270 | } |
@@ -240,14 +275,17 @@ void ima_update_policy(void) | |||
240 | enum { | 275 | enum { |
241 | Opt_err = -1, | 276 | Opt_err = -1, |
242 | Opt_measure = 1, Opt_dont_measure, | 277 | Opt_measure = 1, Opt_dont_measure, |
278 | Opt_appraise, Opt_dont_appraise, | ||
243 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | 279 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
244 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | 280 | Opt_subj_user, Opt_subj_role, Opt_subj_type, |
245 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid | 281 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner |
246 | }; | 282 | }; |
247 | 283 | ||
248 | static match_table_t policy_tokens = { | 284 | static match_table_t policy_tokens = { |
249 | {Opt_measure, "measure"}, | 285 | {Opt_measure, "measure"}, |
250 | {Opt_dont_measure, "dont_measure"}, | 286 | {Opt_dont_measure, "dont_measure"}, |
287 | {Opt_appraise, "appraise"}, | ||
288 | {Opt_dont_appraise, "dont_appraise"}, | ||
251 | {Opt_obj_user, "obj_user=%s"}, | 289 | {Opt_obj_user, "obj_user=%s"}, |
252 | {Opt_obj_role, "obj_role=%s"}, | 290 | {Opt_obj_role, "obj_role=%s"}, |
253 | {Opt_obj_type, "obj_type=%s"}, | 291 | {Opt_obj_type, "obj_type=%s"}, |
@@ -258,10 +296,11 @@ static match_table_t policy_tokens = { | |||
258 | {Opt_mask, "mask=%s"}, | 296 | {Opt_mask, "mask=%s"}, |
259 | {Opt_fsmagic, "fsmagic=%s"}, | 297 | {Opt_fsmagic, "fsmagic=%s"}, |
260 | {Opt_uid, "uid=%s"}, | 298 | {Opt_uid, "uid=%s"}, |
299 | {Opt_fowner, "fowner=%s"}, | ||
261 | {Opt_err, NULL} | 300 | {Opt_err, NULL} |
262 | }; | 301 | }; |
263 | 302 | ||
264 | static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | 303 | static int ima_lsm_rule_init(struct ima_rule_entry *entry, |
265 | char *args, int lsm_rule, int audit_type) | 304 | char *args, int lsm_rule, int audit_type) |
266 | { | 305 | { |
267 | int result; | 306 | int result; |
@@ -285,7 +324,7 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value) | |||
285 | audit_log_format(ab, " "); | 324 | audit_log_format(ab, " "); |
286 | } | 325 | } |
287 | 326 | ||
288 | static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | 327 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) |
289 | { | 328 | { |
290 | struct audit_buffer *ab; | 329 | struct audit_buffer *ab; |
291 | char *p; | 330 | char *p; |
@@ -294,6 +333,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
294 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); | 333 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); |
295 | 334 | ||
296 | entry->uid = -1; | 335 | entry->uid = -1; |
336 | entry->fowner = -1; | ||
297 | entry->action = UNKNOWN; | 337 | entry->action = UNKNOWN; |
298 | while ((p = strsep(&rule, " \t")) != NULL) { | 338 | while ((p = strsep(&rule, " \t")) != NULL) { |
299 | substring_t args[MAX_OPT_ARGS]; | 339 | substring_t args[MAX_OPT_ARGS]; |
@@ -322,11 +362,27 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
322 | 362 | ||
323 | entry->action = DONT_MEASURE; | 363 | entry->action = DONT_MEASURE; |
324 | break; | 364 | break; |
365 | case Opt_appraise: | ||
366 | ima_log_string(ab, "action", "appraise"); | ||
367 | |||
368 | if (entry->action != UNKNOWN) | ||
369 | result = -EINVAL; | ||
370 | |||
371 | entry->action = APPRAISE; | ||
372 | break; | ||
373 | case Opt_dont_appraise: | ||
374 | ima_log_string(ab, "action", "dont_appraise"); | ||
375 | |||
376 | if (entry->action != UNKNOWN) | ||
377 | result = -EINVAL; | ||
378 | |||
379 | entry->action = DONT_APPRAISE; | ||
380 | break; | ||
325 | case Opt_func: | 381 | case Opt_func: |
326 | ima_log_string(ab, "func", args[0].from); | 382 | ima_log_string(ab, "func", args[0].from); |
327 | 383 | ||
328 | if (entry->func) | 384 | if (entry->func) |
329 | result = -EINVAL; | 385 | result = -EINVAL; |
330 | 386 | ||
331 | if (strcmp(args[0].from, "FILE_CHECK") == 0) | 387 | if (strcmp(args[0].from, "FILE_CHECK") == 0) |
332 | entry->func = FILE_CHECK; | 388 | entry->func = FILE_CHECK; |
@@ -391,6 +447,23 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
391 | entry->flags |= IMA_UID; | 447 | entry->flags |= IMA_UID; |
392 | } | 448 | } |
393 | break; | 449 | break; |
450 | case Opt_fowner: | ||
451 | ima_log_string(ab, "fowner", args[0].from); | ||
452 | |||
453 | if (entry->fowner != -1) { | ||
454 | result = -EINVAL; | ||
455 | break; | ||
456 | } | ||
457 | |||
458 | result = strict_strtoul(args[0].from, 10, &lnum); | ||
459 | if (!result) { | ||
460 | entry->fowner = (uid_t) lnum; | ||
461 | if (entry->fowner != lnum) | ||
462 | result = -EINVAL; | ||
463 | else | ||
464 | entry->flags |= IMA_FOWNER; | ||
465 | } | ||
466 | break; | ||
394 | case Opt_obj_user: | 467 | case Opt_obj_user: |
395 | ima_log_string(ab, "obj_user", args[0].from); | 468 | ima_log_string(ab, "obj_user", args[0].from); |
396 | result = ima_lsm_rule_init(entry, args[0].from, | 469 | result = ima_lsm_rule_init(entry, args[0].from, |
@@ -442,7 +515,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
442 | } | 515 | } |
443 | 516 | ||
444 | /** | 517 | /** |
445 | * ima_parse_add_rule - add a rule to measure_policy_rules | 518 | * ima_parse_add_rule - add a rule to ima_policy_rules |
446 | * @rule - ima measurement policy rule | 519 | * @rule - ima measurement policy rule |
447 | * | 520 | * |
448 | * Uses a mutex to protect the policy list from multiple concurrent writers. | 521 | * Uses a mutex to protect the policy list from multiple concurrent writers. |
@@ -452,12 +525,12 @@ ssize_t ima_parse_add_rule(char *rule) | |||
452 | { | 525 | { |
453 | const char *op = "update_policy"; | 526 | const char *op = "update_policy"; |
454 | char *p; | 527 | char *p; |
455 | struct ima_measure_rule_entry *entry; | 528 | struct ima_rule_entry *entry; |
456 | ssize_t result, len; | 529 | ssize_t result, len; |
457 | int audit_info = 0; | 530 | int audit_info = 0; |
458 | 531 | ||
459 | /* Prevent installed policy from changing */ | 532 | /* Prevent installed policy from changing */ |
460 | if (ima_measure != &measure_default_rules) { | 533 | if (ima_rules != &ima_default_rules) { |
461 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 534 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
462 | NULL, op, "already exists", | 535 | NULL, op, "already exists", |
463 | -EACCES, audit_info); | 536 | -EACCES, audit_info); |
@@ -490,9 +563,9 @@ ssize_t ima_parse_add_rule(char *rule) | |||
490 | return result; | 563 | return result; |
491 | } | 564 | } |
492 | 565 | ||
493 | mutex_lock(&ima_measure_mutex); | 566 | mutex_lock(&ima_rules_mutex); |
494 | list_add_tail(&entry->list, &measure_policy_rules); | 567 | list_add_tail(&entry->list, &ima_policy_rules); |
495 | mutex_unlock(&ima_measure_mutex); | 568 | mutex_unlock(&ima_rules_mutex); |
496 | 569 | ||
497 | return len; | 570 | return len; |
498 | } | 571 | } |
@@ -500,12 +573,12 @@ ssize_t ima_parse_add_rule(char *rule) | |||
500 | /* ima_delete_rules called to cleanup invalid policy */ | 573 | /* ima_delete_rules called to cleanup invalid policy */ |
501 | void ima_delete_rules(void) | 574 | void ima_delete_rules(void) |
502 | { | 575 | { |
503 | struct ima_measure_rule_entry *entry, *tmp; | 576 | struct ima_rule_entry *entry, *tmp; |
504 | 577 | ||
505 | mutex_lock(&ima_measure_mutex); | 578 | mutex_lock(&ima_rules_mutex); |
506 | list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) { | 579 | list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) { |
507 | list_del(&entry->list); | 580 | list_del(&entry->list); |
508 | kfree(entry); | 581 | kfree(entry); |
509 | } | 582 | } |
510 | mutex_unlock(&ima_measure_mutex); | 583 | mutex_unlock(&ima_rules_mutex); |
511 | } | 584 | } |