|
|
|
@ -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},
|
|
|
|
@ -81,13 +85,29 @@ static struct ima_rule_entry default_rules[] = {
|
|
|
|
|
{.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},
|
|
|
|
|
{.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},
|
|
|
|
|
};
|
|
|
|
@ -119,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)
|
|
|
|
|
{
|
|
|
|
@ -186,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;
|
|
|
|
@ -194,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++) {
|
|
|
|
@ -337,13 +385,27 @@ 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; i++)
|
|
|
|
|
list_add_tail(&default_rules[i].list, &ima_default_rules);
|
|
|
|
|
list_add_tail(&dont_measure_rules[i].list, &ima_default_rules);
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
@ -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:
|
|
|
|
|