summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorMikhail Kurinnoi <viewizard@viewizard.com>2017-01-27 11:23:01 -0500
committerMimi Zohar <zohar@linux.vnet.ibm.com>2017-03-13 07:01:24 -0400
commit3dd0c8d06511c7c61c62305fcf431ca28884d263 (patch)
tree53dd75846d5bc3ac098bd9fdd08c94ae804c22a2 /security
parent1ac202e978e18f045006d75bd549612620c6ec3a (diff)
ima: provide ">" and "<" operators for fowner/uid/euid rules.
For now we have only "=" operator for fowner/uid/euid rules. This patch provide two more operators - ">" and "<" in order to make fowner/uid/euid rules more flexible. Examples of usage. Appraise all files owned by special and system users (SYS_UID_MAX 999): appraise fowner<1000 Don't appraise files owned by normal users (UID_MIN 1000): dont_appraise fowner>999 Appraise all files owned by users with UID 1000-1010: dont_appraise fowner>1010 appraise fowner>999 Changelog v3: - Removed code duplication in ima_parse_rule(). - Fix ima_policy_show() - (Mimi) Changelog v2: - Fixed default policy rules. Signed-off-by: Mikhail Kurinnoi <viewizard@viewizard.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com> security/integrity/ima/ima_policy.c | 115 +++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 28 deletions(-)
Diffstat (limited to 'security')
-rw-r--r--security/integrity/ima/ima_policy.c115
1 files changed, 87 insertions, 28 deletions
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index e8498a3f4887..3ab1067db624 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -64,6 +64,8 @@ struct ima_rule_entry {
64 u8 fsuuid[16]; 64 u8 fsuuid[16];
65 kuid_t uid; 65 kuid_t uid;
66 kuid_t fowner; 66 kuid_t fowner;
67 bool (*uid_op)(kuid_t, kuid_t); /* Handlers for operators */
68 bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */
67 int pcr; 69 int pcr;
68 struct { 70 struct {
69 void *rule; /* LSM file metadata specific */ 71 void *rule; /* LSM file metadata specific */
@@ -103,7 +105,8 @@ static struct ima_rule_entry original_measurement_rules[] __ro_after_init = {
103 {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, 105 {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
104 .flags = IMA_FUNC | IMA_MASK}, 106 .flags = IMA_FUNC | IMA_MASK},
105 {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 107 {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
106 .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, 108 .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq,
109 .flags = IMA_FUNC | IMA_MASK | IMA_UID},
107 {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, 110 {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
108 {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, 111 {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
109}; 112};
@@ -114,9 +117,11 @@ static struct ima_rule_entry default_measurement_rules[] __ro_after_init = {
114 {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, 117 {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
115 .flags = IMA_FUNC | IMA_MASK}, 118 .flags = IMA_FUNC | IMA_MASK},
116 {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 119 {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
117 .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, 120 .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq,
121 .flags = IMA_FUNC | IMA_INMASK | IMA_EUID},
118 {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 122 {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
119 .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, 123 .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq,
124 .flags = IMA_FUNC | IMA_INMASK | IMA_UID},
120 {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, 125 {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
121 {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, 126 {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
122 {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, 127 {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC},
@@ -139,10 +144,11 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
139 .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 144 .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
140#endif 145#endif
141#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT 146#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
142 {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, 147 {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq,
148 .flags = IMA_FOWNER},
143#else 149#else
144 /* force signature */ 150 /* force signature */
145 {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, 151 {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq,
146 .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, 152 .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED},
147#endif 153#endif
148}; 154};
@@ -240,19 +246,20 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
240 if ((rule->flags & IMA_FSUUID) && 246 if ((rule->flags & IMA_FSUUID) &&
241 memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid))) 247 memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid)))
242 return false; 248 return false;
243 if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) 249 if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid))
244 return false; 250 return false;
245 if (rule->flags & IMA_EUID) { 251 if (rule->flags & IMA_EUID) {
246 if (has_capability_noaudit(current, CAP_SETUID)) { 252 if (has_capability_noaudit(current, CAP_SETUID)) {
247 if (!uid_eq(rule->uid, cred->euid) 253 if (!rule->uid_op(cred->euid, rule->uid)
248 && !uid_eq(rule->uid, cred->suid) 254 && !rule->uid_op(cred->suid, rule->uid)
249 && !uid_eq(rule->uid, cred->uid)) 255 && !rule->uid_op(cred->uid, rule->uid))
250 return false; 256 return false;
251 } else if (!uid_eq(rule->uid, cred->euid)) 257 } else if (!rule->uid_op(cred->euid, rule->uid))
252 return false; 258 return false;
253 } 259 }
254 260
255 if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid)) 261 if ((rule->flags & IMA_FOWNER) &&
262 !rule->fowner_op(inode->i_uid, rule->fowner))
256 return false; 263 return false;
257 for (i = 0; i < MAX_LSM_RULES; i++) { 264 for (i = 0; i < MAX_LSM_RULES; i++) {
258 int rc = 0; 265 int rc = 0;
@@ -486,7 +493,9 @@ enum {
486 Opt_obj_user, Opt_obj_role, Opt_obj_type, 493 Opt_obj_user, Opt_obj_role, Opt_obj_type,
487 Opt_subj_user, Opt_subj_role, Opt_subj_type, 494 Opt_subj_user, Opt_subj_role, Opt_subj_type,
488 Opt_func, Opt_mask, Opt_fsmagic, 495 Opt_func, Opt_mask, Opt_fsmagic,
489 Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner, 496 Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
497 Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
498 Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
490 Opt_appraise_type, Opt_permit_directio, 499 Opt_appraise_type, Opt_permit_directio,
491 Opt_pcr 500 Opt_pcr
492}; 501};
@@ -507,9 +516,15 @@ static match_table_t policy_tokens = {
507 {Opt_mask, "mask=%s"}, 516 {Opt_mask, "mask=%s"},
508 {Opt_fsmagic, "fsmagic=%s"}, 517 {Opt_fsmagic, "fsmagic=%s"},
509 {Opt_fsuuid, "fsuuid=%s"}, 518 {Opt_fsuuid, "fsuuid=%s"},
510 {Opt_uid, "uid=%s"}, 519 {Opt_uid_eq, "uid=%s"},
511 {Opt_euid, "euid=%s"}, 520 {Opt_euid_eq, "euid=%s"},
512 {Opt_fowner, "fowner=%s"}, 521 {Opt_fowner_eq, "fowner=%s"},
522 {Opt_uid_gt, "uid>%s"},
523 {Opt_euid_gt, "euid>%s"},
524 {Opt_fowner_gt, "fowner>%s"},
525 {Opt_uid_lt, "uid<%s"},
526 {Opt_euid_lt, "euid<%s"},
527 {Opt_fowner_lt, "fowner<%s"},
513 {Opt_appraise_type, "appraise_type=%s"}, 528 {Opt_appraise_type, "appraise_type=%s"},
514 {Opt_permit_directio, "permit_directio"}, 529 {Opt_permit_directio, "permit_directio"},
515 {Opt_pcr, "pcr=%s"}, 530 {Opt_pcr, "pcr=%s"},
@@ -541,24 +556,37 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
541 return result; 556 return result;
542} 557}
543 558
544static void ima_log_string(struct audit_buffer *ab, char *key, char *value) 559static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value,
560 bool (*rule_operator)(kuid_t, kuid_t))
545{ 561{
546 audit_log_format(ab, "%s=", key); 562 if (rule_operator == &uid_gt)
563 audit_log_format(ab, "%s>", key);
564 else if (rule_operator == &uid_lt)
565 audit_log_format(ab, "%s<", key);
566 else
567 audit_log_format(ab, "%s=", key);
547 audit_log_untrustedstring(ab, value); 568 audit_log_untrustedstring(ab, value);
548 audit_log_format(ab, " "); 569 audit_log_format(ab, " ");
549} 570}
571static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
572{
573 ima_log_string_op(ab, key, value, NULL);
574}
550 575
551static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) 576static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
552{ 577{
553 struct audit_buffer *ab; 578 struct audit_buffer *ab;
554 char *from; 579 char *from;
555 char *p; 580 char *p;
581 bool uid_token;
556 int result = 0; 582 int result = 0;
557 583
558 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); 584 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
559 585
560 entry->uid = INVALID_UID; 586 entry->uid = INVALID_UID;
561 entry->fowner = INVALID_UID; 587 entry->fowner = INVALID_UID;
588 entry->uid_op = &uid_eq;
589 entry->fowner_op = &uid_eq;
562 entry->action = UNKNOWN; 590 entry->action = UNKNOWN;
563 while ((p = strsep(&rule, " \t")) != NULL) { 591 while ((p = strsep(&rule, " \t")) != NULL) {
564 substring_t args[MAX_OPT_ARGS]; 592 substring_t args[MAX_OPT_ARGS];
@@ -694,11 +722,21 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
694 if (!result) 722 if (!result)
695 entry->flags |= IMA_FSUUID; 723 entry->flags |= IMA_FSUUID;
696 break; 724 break;
697 case Opt_uid: 725 case Opt_uid_gt:
698 ima_log_string(ab, "uid", args[0].from); 726 case Opt_euid_gt:
699 case Opt_euid: 727 entry->uid_op = &uid_gt;
700 if (token == Opt_euid) 728 case Opt_uid_lt:
701 ima_log_string(ab, "euid", args[0].from); 729 case Opt_euid_lt:
730 if ((token == Opt_uid_lt) || (token == Opt_euid_lt))
731 entry->uid_op = &uid_lt;
732 case Opt_uid_eq:
733 case Opt_euid_eq:
734 uid_token = (token == Opt_uid_eq) ||
735 (token == Opt_uid_gt) ||
736 (token == Opt_uid_lt);
737
738 ima_log_string_op(ab, uid_token ? "uid" : "euid",
739 args[0].from, entry->uid_op);
702 740
703 if (uid_valid(entry->uid)) { 741 if (uid_valid(entry->uid)) {
704 result = -EINVAL; 742 result = -EINVAL;
@@ -713,12 +751,18 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
713 (uid_t)lnum != lnum) 751 (uid_t)lnum != lnum)
714 result = -EINVAL; 752 result = -EINVAL;
715 else 753 else
716 entry->flags |= (token == Opt_uid) 754 entry->flags |= uid_token
717 ? IMA_UID : IMA_EUID; 755 ? IMA_UID : IMA_EUID;
718 } 756 }
719 break; 757 break;
720 case Opt_fowner: 758 case Opt_fowner_gt:
721 ima_log_string(ab, "fowner", args[0].from); 759 entry->fowner_op = &uid_gt;
760 case Opt_fowner_lt:
761 if (token == Opt_fowner_lt)
762 entry->fowner_op = &uid_lt;
763 case Opt_fowner_eq:
764 ima_log_string_op(ab, "fowner", args[0].from,
765 entry->fowner_op);
722 766
723 if (uid_valid(entry->fowner)) { 767 if (uid_valid(entry->fowner)) {
724 result = -EINVAL; 768 result = -EINVAL;
@@ -1049,19 +1093,34 @@ int ima_policy_show(struct seq_file *m, void *v)
1049 1093
1050 if (entry->flags & IMA_UID) { 1094 if (entry->flags & IMA_UID) {
1051 snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); 1095 snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
1052 seq_printf(m, pt(Opt_uid), tbuf); 1096 if (entry->uid_op == &uid_gt)
1097 seq_printf(m, pt(Opt_uid_gt), tbuf);
1098 else if (entry->uid_op == &uid_lt)
1099 seq_printf(m, pt(Opt_uid_lt), tbuf);
1100 else
1101 seq_printf(m, pt(Opt_uid_eq), tbuf);
1053 seq_puts(m, " "); 1102 seq_puts(m, " ");
1054 } 1103 }
1055 1104
1056 if (entry->flags & IMA_EUID) { 1105 if (entry->flags & IMA_EUID) {
1057 snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); 1106 snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
1058 seq_printf(m, pt(Opt_euid), tbuf); 1107 if (entry->uid_op == &uid_gt)
1108 seq_printf(m, pt(Opt_euid_gt), tbuf);
1109 else if (entry->uid_op == &uid_lt)
1110 seq_printf(m, pt(Opt_euid_lt), tbuf);
1111 else
1112 seq_printf(m, pt(Opt_euid_eq), tbuf);
1059 seq_puts(m, " "); 1113 seq_puts(m, " ");
1060 } 1114 }
1061 1115
1062 if (entry->flags & IMA_FOWNER) { 1116 if (entry->flags & IMA_FOWNER) {
1063 snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); 1117 snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
1064 seq_printf(m, pt(Opt_fowner), tbuf); 1118 if (entry->fowner_op == &uid_gt)
1119 seq_printf(m, pt(Opt_fowner_gt), tbuf);
1120 else if (entry->fowner_op == &uid_lt)
1121 seq_printf(m, pt(Opt_fowner_lt), tbuf);
1122 else
1123 seq_printf(m, pt(Opt_fowner_eq), tbuf);
1065 seq_puts(m, " "); 1124 seq_puts(m, " ");
1066 } 1125 }
1067 1126