diff options
Diffstat (limited to 'kernel/security')
-rw-r--r-- | kernel/security/integrity/evm/evm_main.c | 11 | ||||
-rw-r--r-- | kernel/security/integrity/ima/ima.h | 2 | ||||
-rw-r--r-- | kernel/security/integrity/ima/ima_fs.c | 4 | ||||
-rw-r--r-- | kernel/security/integrity/ima/ima_policy.c | 124 | ||||
-rw-r--r-- | kernel/security/integrity/ima/ima_template_lib.c | 3 | ||||
-rw-r--r-- | kernel/security/keys/keyring.c | 8 | ||||
-rw-r--r-- | kernel/security/selinux/hooks.c | 3 | ||||
-rw-r--r-- | kernel/security/selinux/ss/ebitmap.c | 6 |
8 files changed, 129 insertions, 32 deletions
diff --git a/kernel/security/integrity/evm/evm_main.c b/kernel/security/integrity/evm/evm_main.c index 10f994307..582091498 100644 --- a/kernel/security/integrity/evm/evm_main.c +++ b/kernel/security/integrity/evm/evm_main.c @@ -296,6 +296,17 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, iint = integrity_iint_find(d_backing_inode(dentry)); if (iint && (iint->flags & IMA_NEW_FILE)) return 0; + + /* exception for pseudo filesystems */ + if (dentry->d_inode->i_sb->s_magic == TMPFS_MAGIC + || dentry->d_inode->i_sb->s_magic == SYSFS_MAGIC) + return 0; + + integrity_audit_msg(AUDIT_INTEGRITY_METADATA, + dentry->d_inode, dentry->d_name.name, + "update_metadata", + integrity_status_msg[evm_status], + -EPERM, 0); } out: if (evm_status != INTEGRITY_PASS) diff --git a/kernel/security/integrity/ima/ima.h b/kernel/security/integrity/ima/ima.h index 8ee997dff..fc56d4dfa 100644 --- a/kernel/security/integrity/ima/ima.h +++ b/kernel/security/integrity/ima/ima.h @@ -106,7 +106,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, const char *op, const char *cause); int ima_init_crypto(void); void ima_putc(struct seq_file *m, void *data, int datalen); -void ima_print_digest(struct seq_file *m, u8 *digest, int size); +void ima_print_digest(struct seq_file *m, u8 *digest, u32 size); struct ima_template_desc *ima_template_desc_current(void); int ima_init_template(void); diff --git a/kernel/security/integrity/ima/ima_fs.c b/kernel/security/integrity/ima/ima_fs.c index 461215e5f..816d175da 100644 --- a/kernel/security/integrity/ima/ima_fs.c +++ b/kernel/security/integrity/ima/ima_fs.c @@ -190,9 +190,9 @@ static const struct file_operations ima_measurements_ops = { .release = seq_release, }; -void ima_print_digest(struct seq_file *m, u8 *digest, int size) +void ima_print_digest(struct seq_file *m, u8 *digest, u32 size) { - int i; + u32 i; for (i = 0; i < size; i++) seq_printf(m, "%02x", *(digest + i)); diff --git a/kernel/security/integrity/ima/ima_policy.c b/kernel/security/integrity/ima/ima_policy.c index d1eefb9d6..3997e206f 100644 --- a/kernel/security/integrity/ima/ima_policy.c +++ b/kernel/security/integrity/ima/ima_policy.c @@ -27,6 +27,8 @@ #define IMA_UID 0x0008 #define IMA_FOWNER 0x0010 #define IMA_FSUUID 0x0020 +#define IMA_INMASK 0x0040 +#define IMA_EUID 0x0080 #define UNKNOWN 0 #define MEASURE 0x0001 /* same as IMA_MEASURE */ @@ -42,6 +44,8 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE }; +enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; + struct ima_rule_entry { struct list_head list; int action; @@ -70,7 +74,7 @@ struct ima_rule_entry { * normal users can easily run the machine out of memory simply building * and running executables. */ -static struct ima_rule_entry default_rules[] = { +static struct ima_rule_entry dont_measure_rules[] = { {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, @@ -79,12 +83,31 @@ static struct ima_rule_entry default_rules[] = { {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC, + .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC} +}; + +static struct ima_rule_entry original_measurement_rules[] = { {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, - {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID, - .flags = IMA_FUNC | IMA_MASK | IMA_UID}, + {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, + .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, + {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, + {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, +}; + +static struct ima_rule_entry default_measurement_rules[] = { + {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, + .flags = IMA_FUNC | IMA_MASK}, + {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, + .flags = IMA_FUNC | IMA_MASK}, + {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, + .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, + {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, + .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, }; @@ -99,6 +122,7 @@ static struct ima_rule_entry default_appraise_rules[] = { {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, @@ -115,14 +139,29 @@ static struct list_head *ima_rules; static DEFINE_MUTEX(ima_rules_mutex); -static bool ima_use_tcb __initdata; +static int ima_policy __initdata; static int __init default_measure_policy_setup(char *str) { - ima_use_tcb = 1; + if (ima_policy) + return 1; + + ima_policy = ORIGINAL_TCB; return 1; } __setup("ima_tcb", default_measure_policy_setup); +static int __init policy_setup(char *str) +{ + if (ima_policy) + return 1; + + if (strcmp(str, "tcb") == 0) + ima_policy = DEFAULT_TCB; + + return 1; +} +__setup("ima_policy=", policy_setup); + static bool ima_use_appraise_tcb __initdata; static int __init default_appraise_policy_setup(char *str) { @@ -182,6 +221,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, if ((rule->flags & IMA_MASK) && (rule->mask != mask && func != POST_SETATTR)) return false; + if ((rule->flags & IMA_INMASK) && + (!(rule->mask & mask) && func != POST_SETATTR)) + return false; if ((rule->flags & IMA_FSMAGIC) && rule->fsmagic != inode->i_sb->s_magic) return false; @@ -190,6 +232,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule, return false; if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) return false; + if (rule->flags & IMA_EUID) { + if (has_capability_noaudit(current, CAP_SETUID)) { + if (!uid_eq(rule->uid, cred->euid) + && !uid_eq(rule->uid, cred->suid) + && !uid_eq(rule->uid, cred->uid)) + return false; + } else if (!uid_eq(rule->uid, cred->euid)) + return false; + } + if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid)) return false; for (i = 0; i < MAX_LSM_RULES; i++) { @@ -333,21 +385,31 @@ void __init ima_init_policy(void) { int i, measure_entries, appraise_entries; - /* if !ima_use_tcb set entries = 0 so we load NO default rules */ - measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0; + /* if !ima_policy set entries = 0 so we load NO default rules */ + measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0; appraise_entries = ima_use_appraise_tcb ? ARRAY_SIZE(default_appraise_rules) : 0; - for (i = 0; i < measure_entries + appraise_entries; i++) { - if (i < measure_entries) - list_add_tail(&default_rules[i].list, - &ima_default_rules); - else { - int j = i - measure_entries; + for (i = 0; i < measure_entries; i++) + list_add_tail(&dont_measure_rules[i].list, &ima_default_rules); - list_add_tail(&default_appraise_rules[j].list, + switch (ima_policy) { + case ORIGINAL_TCB: + for (i = 0; i < ARRAY_SIZE(original_measurement_rules); i++) + list_add_tail(&original_measurement_rules[i].list, &ima_default_rules); - } + break; + case DEFAULT_TCB: + for (i = 0; i < ARRAY_SIZE(default_measurement_rules); i++) + list_add_tail(&default_measurement_rules[i].list, + &ima_default_rules); + default: + break; + } + + for (i = 0; i < appraise_entries; i++) { + list_add_tail(&default_appraise_rules[i].list, + &ima_default_rules); } ima_rules = &ima_default_rules; @@ -373,7 +435,8 @@ enum { Opt_audit, Opt_obj_user, Opt_obj_role, Opt_obj_type, Opt_subj_user, Opt_subj_role, Opt_subj_type, - Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner, + Opt_func, Opt_mask, Opt_fsmagic, + Opt_uid, Opt_euid, Opt_fowner, Opt_appraise_type, Opt_fsuuid, Opt_permit_directio }; @@ -394,6 +457,7 @@ static match_table_t policy_tokens = { {Opt_fsmagic, "fsmagic=%s"}, {Opt_fsuuid, "fsuuid=%s"}, {Opt_uid, "uid=%s"}, + {Opt_euid, "euid=%s"}, {Opt_fowner, "fowner=%s"}, {Opt_appraise_type, "appraise_type=%s"}, {Opt_permit_directio, "permit_directio"}, @@ -435,6 +499,7 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value) static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) { struct audit_buffer *ab; + char *from; char *p; int result = 0; @@ -525,18 +590,23 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) if (entry->mask) result = -EINVAL; - if ((strcmp(args[0].from, "MAY_EXEC")) == 0) + from = args[0].from; + if (*from == '^') + from++; + + if ((strcmp(from, "MAY_EXEC")) == 0) entry->mask = MAY_EXEC; - else if (strcmp(args[0].from, "MAY_WRITE") == 0) + else if (strcmp(from, "MAY_WRITE") == 0) entry->mask = MAY_WRITE; - else if (strcmp(args[0].from, "MAY_READ") == 0) + else if (strcmp(from, "MAY_READ") == 0) entry->mask = MAY_READ; - else if (strcmp(args[0].from, "MAY_APPEND") == 0) + else if (strcmp(from, "MAY_APPEND") == 0) entry->mask = MAY_APPEND; else result = -EINVAL; if (!result) - entry->flags |= IMA_MASK; + entry->flags |= (*args[0].from == '^') + ? IMA_INMASK : IMA_MASK; break; case Opt_fsmagic: ima_log_string(ab, "fsmagic", args[0].from); @@ -566,6 +636,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; case Opt_uid: ima_log_string(ab, "uid", args[0].from); + case Opt_euid: + if (token == Opt_euid) + ima_log_string(ab, "euid", args[0].from); if (uid_valid(entry->uid)) { result = -EINVAL; @@ -574,11 +647,14 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) result = kstrtoul(args[0].from, 10, &lnum); if (!result) { - entry->uid = make_kuid(current_user_ns(), (uid_t)lnum); - if (!uid_valid(entry->uid) || (((uid_t)lnum) != lnum)) + entry->uid = make_kuid(current_user_ns(), + (uid_t) lnum); + if (!uid_valid(entry->uid) || + (uid_t)lnum != lnum) result = -EINVAL; else - entry->flags |= IMA_UID; + entry->flags |= (token == Opt_uid) + ? IMA_UID : IMA_EUID; } break; case Opt_fowner: diff --git a/kernel/security/integrity/ima/ima_template_lib.c b/kernel/security/integrity/ima/ima_template_lib.c index bcfc36cbd..61fbd0c0d 100644 --- a/kernel/security/integrity/ima/ima_template_lib.c +++ b/kernel/security/integrity/ima/ima_template_lib.c @@ -70,7 +70,8 @@ static void ima_show_template_data_ascii(struct seq_file *m, enum data_formats datafmt, struct ima_field_data *field_data) { - u8 *buf_ptr = field_data->data, buflen = field_data->len; + u8 *buf_ptr = field_data->data; + u32 buflen = field_data->len; switch (datafmt) { case DATA_FMT_DIGEST_WITH_ALGO: diff --git a/kernel/security/keys/keyring.c b/kernel/security/keys/keyring.c index e72548b58..d33437007 100644 --- a/kernel/security/keys/keyring.c +++ b/kernel/security/keys/keyring.c @@ -1181,9 +1181,11 @@ void __key_link_end(struct key *keyring, if (index_key->type == &key_type_keyring) up_write(&keyring_serialise_link_sem); - if (edit && !edit->dead_leaf) { - key_payload_reserve(keyring, - keyring->datalen - KEYQUOTA_LINK_BYTES); + if (edit) { + if (!edit->dead_leaf) { + key_payload_reserve(keyring, + keyring->datalen - KEYQUOTA_LINK_BYTES); + } assoc_array_cancel_edit(edit); } up_write(&keyring->sem); diff --git a/kernel/security/selinux/hooks.c b/kernel/security/selinux/hooks.c index 212070e1d..7f8d7f19e 100644 --- a/kernel/security/selinux/hooks.c +++ b/kernel/security/selinux/hooks.c @@ -3288,7 +3288,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared int rc = 0; if (default_noexec && - (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { + (prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) || + (!shared && (prot & PROT_WRITE)))) { /* * We are making executable an anonymous mapping or a * private file mapping that will also be writable. diff --git a/kernel/security/selinux/ss/ebitmap.c b/kernel/security/selinux/ss/ebitmap.c index afe6a269e..57644b1dc 100644 --- a/kernel/security/selinux/ss/ebitmap.c +++ b/kernel/security/selinux/ss/ebitmap.c @@ -153,6 +153,12 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, if (offset == (u32)-1) return 0; + /* don't waste ebitmap space if the netlabel bitmap is empty */ + if (bitmap == 0) { + offset += EBITMAP_UNIT_SIZE; + continue; + } + if (e_iter == NULL || offset >= e_iter->startbit + EBITMAP_SIZE) { e_prev = e_iter; |