|
|
|
@@ -36,6 +36,9 @@
|
|
|
|
|
#define IMA_KEYRINGS 0x0400
|
|
|
|
|
#define IMA_LABEL 0x0800
|
|
|
|
|
#define IMA_VALIDATE_ALGOS 0x1000
|
|
|
|
|
#define IMA_GID 0x2000
|
|
|
|
|
#define IMA_EGID 0x4000
|
|
|
|
|
#define IMA_FGROUP 0x8000
|
|
|
|
|
|
|
|
|
|
#define UNKNOWN 0
|
|
|
|
|
#define MEASURE 0x0001 /* same as IMA_MEASURE */
|
|
|
|
@@ -78,9 +81,13 @@ struct ima_rule_entry {
|
|
|
|
|
unsigned long fsmagic;
|
|
|
|
|
uuid_t fsuuid;
|
|
|
|
|
kuid_t uid;
|
|
|
|
|
kgid_t gid;
|
|
|
|
|
kuid_t fowner;
|
|
|
|
|
bool (*uid_op)(kuid_t, kuid_t); /* Handlers for operators */
|
|
|
|
|
bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */
|
|
|
|
|
kgid_t fgroup;
|
|
|
|
|
bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */
|
|
|
|
|
bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid);
|
|
|
|
|
bool (*fowner_op)(kuid_t cred_uid, kuid_t rule_uid); /* uid_eq(), uid_gt(), uid_lt() */
|
|
|
|
|
bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */
|
|
|
|
|
int pcr;
|
|
|
|
|
unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
|
|
|
|
|
struct {
|
|
|
|
@@ -104,7 +111,8 @@ static_assert(
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Without LSM specific knowledge, the default policy can only be
|
|
|
|
|
* written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
|
|
|
|
|
* written in terms of .action, .func, .mask, .fsmagic, .uid, .gid,
|
|
|
|
|
* .fowner, and .fgroup
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -228,7 +236,7 @@ static struct ima_rule_entry *arch_policy_entry __ro_after_init;
|
|
|
|
|
static LIST_HEAD(ima_default_rules);
|
|
|
|
|
static LIST_HEAD(ima_policy_rules);
|
|
|
|
|
static LIST_HEAD(ima_temp_rules);
|
|
|
|
|
static struct list_head *ima_rules = &ima_default_rules;
|
|
|
|
|
static struct list_head __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules);
|
|
|
|
|
|
|
|
|
|
static int ima_policy __initdata;
|
|
|
|
|
|
|
|
|
@@ -582,10 +590,23 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
|
|
|
|
|
} else if (!rule->uid_op(cred->euid, rule->uid))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((rule->flags & IMA_GID) && !rule->gid_op(cred->gid, rule->gid))
|
|
|
|
|
return false;
|
|
|
|
|
if (rule->flags & IMA_EGID) {
|
|
|
|
|
if (has_capability_noaudit(current, CAP_SETGID)) {
|
|
|
|
|
if (!rule->gid_op(cred->egid, rule->gid)
|
|
|
|
|
&& !rule->gid_op(cred->sgid, rule->gid)
|
|
|
|
|
&& !rule->gid_op(cred->gid, rule->gid))
|
|
|
|
|
return false;
|
|
|
|
|
} else if (!rule->gid_op(cred->egid, rule->gid))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ((rule->flags & IMA_FOWNER) &&
|
|
|
|
|
!rule->fowner_op(i_uid_into_mnt(mnt_userns, inode), rule->fowner))
|
|
|
|
|
return false;
|
|
|
|
|
if ((rule->flags & IMA_FGROUP) &&
|
|
|
|
|
!rule->fgroup_op(i_gid_into_mnt(mnt_userns, inode), rule->fgroup))
|
|
|
|
|
return false;
|
|
|
|
|
for (i = 0; i < MAX_LSM_RULES; i++) {
|
|
|
|
|
int rc = 0;
|
|
|
|
|
u32 osid;
|
|
|
|
@@ -675,12 +696,14 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
|
|
|
|
|
{
|
|
|
|
|
struct ima_rule_entry *entry;
|
|
|
|
|
int action = 0, actmask = flags | (flags << 1);
|
|
|
|
|
struct list_head *ima_rules_tmp;
|
|
|
|
|
|
|
|
|
|
if (template_desc && !*template_desc)
|
|
|
|
|
*template_desc = ima_template_desc_current();
|
|
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
list_for_each_entry_rcu(entry, ima_rules, list) {
|
|
|
|
|
ima_rules_tmp = rcu_dereference(ima_rules);
|
|
|
|
|
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
|
|
|
|
|
|
|
|
|
|
if (!(entry->action & actmask))
|
|
|
|
|
continue;
|
|
|
|
@@ -741,9 +764,11 @@ void ima_update_policy_flags(void)
|
|
|
|
|
{
|
|
|
|
|
struct ima_rule_entry *entry;
|
|
|
|
|
int new_policy_flag = 0;
|
|
|
|
|
struct list_head *ima_rules_tmp;
|
|
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
list_for_each_entry(entry, ima_rules, list) {
|
|
|
|
|
ima_rules_tmp = rcu_dereference(ima_rules);
|
|
|
|
|
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
|
|
|
|
|
/*
|
|
|
|
|
* SETXATTR_CHECK rules do not implement a full policy check
|
|
|
|
|
* because rule checking would probably have an important
|
|
|
|
@@ -845,7 +870,7 @@ static int __init ima_init_arch_policy(void)
|
|
|
|
|
char rule[255];
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
result = strlcpy(rule, *rules, sizeof(rule));
|
|
|
|
|
result = strscpy(rule, *rules, sizeof(rule));
|
|
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&arch_policy_entry[i].list);
|
|
|
|
|
result = ima_parse_rule(rule, &arch_policy_entry[i]);
|
|
|
|
@@ -864,8 +889,7 @@ static int __init ima_init_arch_policy(void)
|
|
|
|
|
/**
|
|
|
|
|
* ima_init_policy - initialize the default measure rules.
|
|
|
|
|
*
|
|
|
|
|
* ima_rules points to either the ima_default_rules or the
|
|
|
|
|
* the new ima_policy_rules.
|
|
|
|
|
* ima_rules points to either the ima_default_rules or the new ima_policy_rules.
|
|
|
|
|
*/
|
|
|
|
|
void __init ima_init_policy(void)
|
|
|
|
|
{
|
|
|
|
@@ -968,10 +992,10 @@ void ima_update_policy(void)
|
|
|
|
|
|
|
|
|
|
list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu);
|
|
|
|
|
|
|
|
|
|
if (ima_rules != policy) {
|
|
|
|
|
if (ima_rules != (struct list_head __rcu *)policy) {
|
|
|
|
|
ima_policy_flag = 0;
|
|
|
|
|
ima_rules = policy;
|
|
|
|
|
|
|
|
|
|
rcu_assign_pointer(ima_rules, policy);
|
|
|
|
|
/*
|
|
|
|
|
* IMA architecture specific policy rules are specified
|
|
|
|
|
* as strings and converted to an array of ima_entry_rules
|
|
|
|
@@ -987,16 +1011,19 @@ void ima_update_policy(void)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Keep the enumeration in sync with the policy_tokens! */
|
|
|
|
|
enum {
|
|
|
|
|
enum policy_opt {
|
|
|
|
|
Opt_measure, Opt_dont_measure,
|
|
|
|
|
Opt_appraise, Opt_dont_appraise,
|
|
|
|
|
Opt_audit, Opt_hash, Opt_dont_hash,
|
|
|
|
|
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_fsname,
|
|
|
|
|
Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
|
|
|
|
|
Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
|
|
|
|
|
Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
|
|
|
|
|
Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname, Opt_fsuuid,
|
|
|
|
|
Opt_uid_eq, Opt_euid_eq, Opt_gid_eq, Opt_egid_eq,
|
|
|
|
|
Opt_fowner_eq, Opt_fgroup_eq,
|
|
|
|
|
Opt_uid_gt, Opt_euid_gt, Opt_gid_gt, Opt_egid_gt,
|
|
|
|
|
Opt_fowner_gt, Opt_fgroup_gt,
|
|
|
|
|
Opt_uid_lt, Opt_euid_lt, Opt_gid_lt, Opt_egid_lt,
|
|
|
|
|
Opt_fowner_lt, Opt_fgroup_lt,
|
|
|
|
|
Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
|
|
|
|
|
Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
|
|
|
|
|
Opt_label, Opt_err
|
|
|
|
@@ -1023,13 +1050,22 @@ static const match_table_t policy_tokens = {
|
|
|
|
|
{Opt_fsuuid, "fsuuid=%s"},
|
|
|
|
|
{Opt_uid_eq, "uid=%s"},
|
|
|
|
|
{Opt_euid_eq, "euid=%s"},
|
|
|
|
|
{Opt_gid_eq, "gid=%s"},
|
|
|
|
|
{Opt_egid_eq, "egid=%s"},
|
|
|
|
|
{Opt_fowner_eq, "fowner=%s"},
|
|
|
|
|
{Opt_fgroup_eq, "fgroup=%s"},
|
|
|
|
|
{Opt_uid_gt, "uid>%s"},
|
|
|
|
|
{Opt_euid_gt, "euid>%s"},
|
|
|
|
|
{Opt_gid_gt, "gid>%s"},
|
|
|
|
|
{Opt_egid_gt, "egid>%s"},
|
|
|
|
|
{Opt_fowner_gt, "fowner>%s"},
|
|
|
|
|
{Opt_fgroup_gt, "fgroup>%s"},
|
|
|
|
|
{Opt_uid_lt, "uid<%s"},
|
|
|
|
|
{Opt_euid_lt, "euid<%s"},
|
|
|
|
|
{Opt_gid_lt, "gid<%s"},
|
|
|
|
|
{Opt_egid_lt, "egid<%s"},
|
|
|
|
|
{Opt_fowner_lt, "fowner<%s"},
|
|
|
|
|
{Opt_fgroup_lt, "fgroup<%s"},
|
|
|
|
|
{Opt_appraise_type, "appraise_type=%s"},
|
|
|
|
|
{Opt_appraise_flag, "appraise_flag=%s"},
|
|
|
|
|
{Opt_appraise_algos, "appraise_algos=%s"},
|
|
|
|
@@ -1061,7 +1097,7 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
|
|
|
|
|
pr_warn("rule for LSM \'%s\' is undefined\n",
|
|
|
|
|
entry->lsm[lsm_rule].args_p);
|
|
|
|
|
|
|
|
|
|
if (ima_rules == &ima_default_rules) {
|
|
|
|
|
if (ima_rules == (struct list_head __rcu *)(&ima_default_rules)) {
|
|
|
|
|
kfree(entry->lsm[lsm_rule].args_p);
|
|
|
|
|
entry->lsm[lsm_rule].args_p = NULL;
|
|
|
|
|
result = -EINVAL;
|
|
|
|
@@ -1073,22 +1109,36 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value,
|
|
|
|
|
bool (*rule_operator)(kuid_t, kuid_t))
|
|
|
|
|
enum policy_opt rule_operator)
|
|
|
|
|
{
|
|
|
|
|
if (!ab)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (rule_operator == &uid_gt)
|
|
|
|
|
switch (rule_operator) {
|
|
|
|
|
case Opt_uid_gt:
|
|
|
|
|
case Opt_euid_gt:
|
|
|
|
|
case Opt_gid_gt:
|
|
|
|
|
case Opt_egid_gt:
|
|
|
|
|
case Opt_fowner_gt:
|
|
|
|
|
case Opt_fgroup_gt:
|
|
|
|
|
audit_log_format(ab, "%s>", key);
|
|
|
|
|
else if (rule_operator == &uid_lt)
|
|
|
|
|
break;
|
|
|
|
|
case Opt_uid_lt:
|
|
|
|
|
case Opt_euid_lt:
|
|
|
|
|
case Opt_gid_lt:
|
|
|
|
|
case Opt_egid_lt:
|
|
|
|
|
case Opt_fowner_lt:
|
|
|
|
|
case Opt_fgroup_lt:
|
|
|
|
|
audit_log_format(ab, "%s<", key);
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
audit_log_format(ab, "%s=", key);
|
|
|
|
|
}
|
|
|
|
|
audit_log_format(ab, "%s ", value);
|
|
|
|
|
}
|
|
|
|
|
static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
|
|
|
|
|
{
|
|
|
|
|
ima_log_string_op(ab, key, value, NULL);
|
|
|
|
|
ima_log_string_op(ab, key, value, Opt_err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -1163,7 +1213,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
|
|
|
|
|
if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC |
|
|
|
|
|
IMA_UID | IMA_FOWNER | IMA_FSUUID |
|
|
|
|
|
IMA_INMASK | IMA_EUID | IMA_PCR |
|
|
|
|
|
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
|
|
|
|
|
IMA_FSNAME | IMA_GID | IMA_EGID |
|
|
|
|
|
IMA_FGROUP | IMA_DIGSIG_REQUIRED |
|
|
|
|
|
IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
@@ -1174,7 +1225,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
|
|
|
|
|
if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC |
|
|
|
|
|
IMA_UID | IMA_FOWNER | IMA_FSUUID |
|
|
|
|
|
IMA_INMASK | IMA_EUID | IMA_PCR |
|
|
|
|
|
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
|
|
|
|
|
IMA_FSNAME | IMA_GID | IMA_EGID |
|
|
|
|
|
IMA_FGROUP | IMA_DIGSIG_REQUIRED |
|
|
|
|
|
IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED |
|
|
|
|
|
IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
|
|
|
|
|
return false;
|
|
|
|
@@ -1186,7 +1238,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
|
|
|
|
|
|
|
|
|
|
if (entry->flags & ~(IMA_FUNC | IMA_FSMAGIC | IMA_UID |
|
|
|
|
|
IMA_FOWNER | IMA_FSUUID | IMA_EUID |
|
|
|
|
|
IMA_PCR | IMA_FSNAME))
|
|
|
|
|
IMA_PCR | IMA_FSNAME | IMA_GID | IMA_EGID |
|
|
|
|
|
IMA_FGROUP))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
@@ -1194,7 +1247,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
|
|
|
|
|
if (entry->action & ~(MEASURE | DONT_MEASURE))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_PCR |
|
|
|
|
|
if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR |
|
|
|
|
|
IMA_KEYRINGS))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
@@ -1206,7 +1259,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
|
|
|
|
|
if (entry->action & ~(MEASURE | DONT_MEASURE))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_PCR |
|
|
|
|
|
if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR |
|
|
|
|
|
IMA_LABEL))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
@@ -1276,7 +1329,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|
|
|
|
struct audit_buffer *ab;
|
|
|
|
|
char *from;
|
|
|
|
|
char *p;
|
|
|
|
|
bool uid_token;
|
|
|
|
|
bool eid_token; /* either euid or egid */
|
|
|
|
|
struct ima_template_desc *template_desc;
|
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
|
@@ -1284,9 +1337,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|
|
|
|
AUDIT_INTEGRITY_POLICY_RULE);
|
|
|
|
|
|
|
|
|
|
entry->uid = INVALID_UID;
|
|
|
|
|
entry->gid = INVALID_GID;
|
|
|
|
|
entry->fowner = INVALID_UID;
|
|
|
|
|
entry->fgroup = INVALID_GID;
|
|
|
|
|
entry->uid_op = &uid_eq;
|
|
|
|
|
entry->gid_op = &gid_eq;
|
|
|
|
|
entry->fowner_op = &uid_eq;
|
|
|
|
|
entry->fgroup_op = &gid_eq;
|
|
|
|
|
entry->action = UNKNOWN;
|
|
|
|
|
while ((p = strsep(&rule, " \t")) != NULL) {
|
|
|
|
|
substring_t args[MAX_OPT_ARGS];
|
|
|
|
@@ -1504,12 +1561,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|
|
|
|
fallthrough;
|
|
|
|
|
case Opt_uid_eq:
|
|
|
|
|
case Opt_euid_eq:
|
|
|
|
|
uid_token = (token == Opt_uid_eq) ||
|
|
|
|
|
(token == Opt_uid_gt) ||
|
|
|
|
|
(token == Opt_uid_lt);
|
|
|
|
|
eid_token = (token == Opt_euid_eq) ||
|
|
|
|
|
(token == Opt_euid_gt) ||
|
|
|
|
|
(token == Opt_euid_lt);
|
|
|
|
|
|
|
|
|
|
ima_log_string_op(ab, uid_token ? "uid" : "euid",
|
|
|
|
|
args[0].from, entry->uid_op);
|
|
|
|
|
ima_log_string_op(ab, eid_token ? "euid" : "uid",
|
|
|
|
|
args[0].from, token);
|
|
|
|
|
|
|
|
|
|
if (uid_valid(entry->uid)) {
|
|
|
|
|
result = -EINVAL;
|
|
|
|
@@ -1524,8 +1581,43 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|
|
|
|
(uid_t)lnum != lnum)
|
|
|
|
|
result = -EINVAL;
|
|
|
|
|
else
|
|
|
|
|
entry->flags |= uid_token
|
|
|
|
|
? IMA_UID : IMA_EUID;
|
|
|
|
|
entry->flags |= eid_token
|
|
|
|
|
? IMA_EUID : IMA_UID;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Opt_gid_gt:
|
|
|
|
|
case Opt_egid_gt:
|
|
|
|
|
entry->gid_op = &gid_gt;
|
|
|
|
|
fallthrough;
|
|
|
|
|
case Opt_gid_lt:
|
|
|
|
|
case Opt_egid_lt:
|
|
|
|
|
if ((token == Opt_gid_lt) || (token == Opt_egid_lt))
|
|
|
|
|
entry->gid_op = &gid_lt;
|
|
|
|
|
fallthrough;
|
|
|
|
|
case Opt_gid_eq:
|
|
|
|
|
case Opt_egid_eq:
|
|
|
|
|
eid_token = (token == Opt_egid_eq) ||
|
|
|
|
|
(token == Opt_egid_gt) ||
|
|
|
|
|
(token == Opt_egid_lt);
|
|
|
|
|
|
|
|
|
|
ima_log_string_op(ab, eid_token ? "egid" : "gid",
|
|
|
|
|
args[0].from, token);
|
|
|
|
|
|
|
|
|
|
if (gid_valid(entry->gid)) {
|
|
|
|
|
result = -EINVAL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = kstrtoul(args[0].from, 10, &lnum);
|
|
|
|
|
if (!result) {
|
|
|
|
|
entry->gid = make_kgid(current_user_ns(),
|
|
|
|
|
(gid_t)lnum);
|
|
|
|
|
if (!gid_valid(entry->gid) ||
|
|
|
|
|
(((gid_t)lnum) != lnum))
|
|
|
|
|
result = -EINVAL;
|
|
|
|
|
else
|
|
|
|
|
entry->flags |= eid_token
|
|
|
|
|
? IMA_EGID : IMA_GID;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Opt_fowner_gt:
|
|
|
|
@@ -1536,8 +1628,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|
|
|
|
entry->fowner_op = &uid_lt;
|
|
|
|
|
fallthrough;
|
|
|
|
|
case Opt_fowner_eq:
|
|
|
|
|
ima_log_string_op(ab, "fowner", args[0].from,
|
|
|
|
|
entry->fowner_op);
|
|
|
|
|
ima_log_string_op(ab, "fowner", args[0].from, token);
|
|
|
|
|
|
|
|
|
|
if (uid_valid(entry->fowner)) {
|
|
|
|
|
result = -EINVAL;
|
|
|
|
@@ -1546,13 +1637,41 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|
|
|
|
|
|
|
|
|
result = kstrtoul(args[0].from, 10, &lnum);
|
|
|
|
|
if (!result) {
|
|
|
|
|
entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum);
|
|
|
|
|
if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum))
|
|
|
|
|
entry->fowner = make_kuid(current_user_ns(),
|
|
|
|
|
(uid_t)lnum);
|
|
|
|
|
if (!uid_valid(entry->fowner) ||
|
|
|
|
|
(((uid_t)lnum) != lnum))
|
|
|
|
|
result = -EINVAL;
|
|
|
|
|
else
|
|
|
|
|
entry->flags |= IMA_FOWNER;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Opt_fgroup_gt:
|
|
|
|
|
entry->fgroup_op = &gid_gt;
|
|
|
|
|
fallthrough;
|
|
|
|
|
case Opt_fgroup_lt:
|
|
|
|
|
if (token == Opt_fgroup_lt)
|
|
|
|
|
entry->fgroup_op = &gid_lt;
|
|
|
|
|
fallthrough;
|
|
|
|
|
case Opt_fgroup_eq:
|
|
|
|
|
ima_log_string_op(ab, "fgroup", args[0].from, token);
|
|
|
|
|
|
|
|
|
|
if (gid_valid(entry->fgroup)) {
|
|
|
|
|
result = -EINVAL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = kstrtoul(args[0].from, 10, &lnum);
|
|
|
|
|
if (!result) {
|
|
|
|
|
entry->fgroup = make_kgid(current_user_ns(),
|
|
|
|
|
(gid_t)lnum);
|
|
|
|
|
if (!gid_valid(entry->fgroup) ||
|
|
|
|
|
(((gid_t)lnum) != lnum))
|
|
|
|
|
result = -EINVAL;
|
|
|
|
|
else
|
|
|
|
|
entry->flags |= IMA_FGROUP;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Opt_obj_user:
|
|
|
|
|
ima_log_string(ab, "obj_user", args[0].from);
|
|
|
|
|
result = ima_lsm_rule_init(entry, args,
|
|
|
|
@@ -1768,9 +1887,11 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos)
|
|
|
|
|
{
|
|
|
|
|
loff_t l = *pos;
|
|
|
|
|
struct ima_rule_entry *entry;
|
|
|
|
|
struct list_head *ima_rules_tmp;
|
|
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
list_for_each_entry_rcu(entry, ima_rules, list) {
|
|
|
|
|
ima_rules_tmp = rcu_dereference(ima_rules);
|
|
|
|
|
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
|
|
|
|
|
if (!l--) {
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
return entry;
|
|
|
|
@@ -1789,7 +1910,8 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
(*pos)++;
|
|
|
|
|
|
|
|
|
|
return (&entry->list == ima_rules) ? NULL : entry;
|
|
|
|
|
return (&entry->list == &ima_default_rules ||
|
|
|
|
|
&entry->list == &ima_policy_rules) ? NULL : entry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ima_policy_stop(struct seq_file *m, void *v)
|
|
|
|
@@ -1936,6 +2058,28 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|
|
|
|
seq_puts(m, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry->flags & IMA_GID) {
|
|
|
|
|
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid));
|
|
|
|
|
if (entry->gid_op == &gid_gt)
|
|
|
|
|
seq_printf(m, pt(Opt_gid_gt), tbuf);
|
|
|
|
|
else if (entry->gid_op == &gid_lt)
|
|
|
|
|
seq_printf(m, pt(Opt_gid_lt), tbuf);
|
|
|
|
|
else
|
|
|
|
|
seq_printf(m, pt(Opt_gid_eq), tbuf);
|
|
|
|
|
seq_puts(m, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry->flags & IMA_EGID) {
|
|
|
|
|
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid));
|
|
|
|
|
if (entry->gid_op == &gid_gt)
|
|
|
|
|
seq_printf(m, pt(Opt_egid_gt), tbuf);
|
|
|
|
|
else if (entry->gid_op == &gid_lt)
|
|
|
|
|
seq_printf(m, pt(Opt_egid_lt), tbuf);
|
|
|
|
|
else
|
|
|
|
|
seq_printf(m, pt(Opt_egid_eq), tbuf);
|
|
|
|
|
seq_puts(m, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry->flags & IMA_FOWNER) {
|
|
|
|
|
snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
|
|
|
|
|
if (entry->fowner_op == &uid_gt)
|
|
|
|
@@ -1947,6 +2091,17 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|
|
|
|
seq_puts(m, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry->flags & IMA_FGROUP) {
|
|
|
|
|
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup));
|
|
|
|
|
if (entry->fgroup_op == &gid_gt)
|
|
|
|
|
seq_printf(m, pt(Opt_fgroup_gt), tbuf);
|
|
|
|
|
else if (entry->fgroup_op == &gid_lt)
|
|
|
|
|
seq_printf(m, pt(Opt_fgroup_lt), tbuf);
|
|
|
|
|
else
|
|
|
|
|
seq_printf(m, pt(Opt_fgroup_eq), tbuf);
|
|
|
|
|
seq_puts(m, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry->flags & IMA_VALIDATE_ALGOS) {
|
|
|
|
|
seq_puts(m, "appraise_algos=");
|
|
|
|
|
ima_policy_show_appraise_algos(m, entry->allowed_algos);
|
|
|
|
@@ -2014,6 +2169,7 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
|
|
|
|
|
struct ima_rule_entry *entry;
|
|
|
|
|
bool found = false;
|
|
|
|
|
enum ima_hooks func;
|
|
|
|
|
struct list_head *ima_rules_tmp;
|
|
|
|
|
|
|
|
|
|
if (id >= READING_MAX_ID)
|
|
|
|
|
return false;
|
|
|
|
@@ -2021,7 +2177,8 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
|
|
|
|
|
func = read_idmap[id] ?: FILE_CHECK;
|
|
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
list_for_each_entry_rcu(entry, ima_rules, list) {
|
|
|
|
|
ima_rules_tmp = rcu_dereference(ima_rules);
|
|
|
|
|
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
|
|
|
|
|
if (entry->action != APPRAISE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|