ima: Move comprehensive rule validation checks out of the token parser
Use ima_validate_rule(), at the end of the token parsing stage, to verify combinations of actions, hooks, and flags. This is useful to increase readability by consolidating such checks into a single function and also because rule conditionals can be specified in arbitrary order making it difficult to do comprehensive rule validation until the entire rule has been parsed. This allows for the check that ties together the "keyrings" conditional with the KEY_CHECK function hook to be moved into the final rule validation. The modsig check no longer needs to compiled conditionally because the token parser will ensure that modsig support is enabled before accepting "imasig|modsig" appraise type values. The final rule validation will ensure that appraise_type and appraise_flag options are only present in appraise rules. Finally, this allows for the check that ties together the "pcr" conditional with the measure action to be moved into the final rule validation. Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
This commit is contained in:
parent
aa0c0227d3
commit
30031b0ec8
|
@ -372,7 +372,6 @@ static inline int ima_read_xattr(struct dentry *dentry,
|
||||||
#endif /* CONFIG_IMA_APPRAISE */
|
#endif /* CONFIG_IMA_APPRAISE */
|
||||||
|
|
||||||
#ifdef CONFIG_IMA_APPRAISE_MODSIG
|
#ifdef CONFIG_IMA_APPRAISE_MODSIG
|
||||||
bool ima_hook_supports_modsig(enum ima_hooks func);
|
|
||||||
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
||||||
struct modsig **modsig);
|
struct modsig **modsig);
|
||||||
void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size);
|
void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size);
|
||||||
|
@ -382,11 +381,6 @@ int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
|
||||||
u32 *data_len);
|
u32 *data_len);
|
||||||
void ima_free_modsig(struct modsig *modsig);
|
void ima_free_modsig(struct modsig *modsig);
|
||||||
#else
|
#else
|
||||||
static inline bool ima_hook_supports_modsig(enum ima_hooks func)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ima_read_modsig(enum ima_hooks func, const void *buf,
|
static inline int ima_read_modsig(enum ima_hooks func, const void *buf,
|
||||||
loff_t buf_len, struct modsig **modsig)
|
loff_t buf_len, struct modsig **modsig)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,26 +32,6 @@ struct modsig {
|
||||||
u8 raw_pkcs7[];
|
u8 raw_pkcs7[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* ima_hook_supports_modsig - can the policy allow modsig for this hook?
|
|
||||||
*
|
|
||||||
* modsig is only supported by hooks using ima_post_read_file(), because only
|
|
||||||
* they preload the contents of the file in a buffer. FILE_CHECK does that in
|
|
||||||
* some cases, but not when reached from vfs_open(). POLICY_CHECK can support
|
|
||||||
* it, but it's not useful in practice because it's a text file so deny.
|
|
||||||
*/
|
|
||||||
bool ima_hook_supports_modsig(enum ima_hooks func)
|
|
||||||
{
|
|
||||||
switch (func) {
|
|
||||||
case KEXEC_KERNEL_CHECK:
|
|
||||||
case KEXEC_INITRAMFS_CHECK:
|
|
||||||
case MODULE_CHECK:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ima_read_modsig - Read modsig from buf.
|
* ima_read_modsig - Read modsig from buf.
|
||||||
*
|
*
|
||||||
|
|
|
@ -984,10 +984,27 @@ static void check_template_modsig(const struct ima_template_desc *template)
|
||||||
|
|
||||||
static bool ima_validate_rule(struct ima_rule_entry *entry)
|
static bool ima_validate_rule(struct ima_rule_entry *entry)
|
||||||
{
|
{
|
||||||
/* Ensure that the action is set */
|
/* Ensure that the action is set and is compatible with the flags */
|
||||||
if (entry->action == UNKNOWN)
|
if (entry->action == UNKNOWN)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (entry->action != MEASURE && entry->flags & IMA_PCR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (entry->action != APPRAISE &&
|
||||||
|
entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The IMA_FUNC bit must be set if and only if there's a valid hook
|
||||||
|
* function specified, and vice versa. Enforcing this property allows
|
||||||
|
* for the NONE case below to validate a rule without an explicit hook
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
if (((entry->flags & IMA_FUNC) && entry->func == NONE) ||
|
||||||
|
(!(entry->flags & IMA_FUNC) && entry->func != NONE))
|
||||||
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that the hook function is compatible with the other
|
* Ensure that the hook function is compatible with the other
|
||||||
* components of the rule
|
* components of the rule
|
||||||
|
@ -999,12 +1016,27 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
|
||||||
case BPRM_CHECK:
|
case BPRM_CHECK:
|
||||||
case CREDS_CHECK:
|
case CREDS_CHECK:
|
||||||
case POST_SETATTR:
|
case POST_SETATTR:
|
||||||
case MODULE_CHECK:
|
|
||||||
case FIRMWARE_CHECK:
|
case FIRMWARE_CHECK:
|
||||||
|
case POLICY_CHECK:
|
||||||
|
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_PERMIT_DIRECTIO))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MODULE_CHECK:
|
||||||
case KEXEC_KERNEL_CHECK:
|
case KEXEC_KERNEL_CHECK:
|
||||||
case KEXEC_INITRAMFS_CHECK:
|
case KEXEC_INITRAMFS_CHECK:
|
||||||
case POLICY_CHECK:
|
if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC |
|
||||||
/* Validation of these hook functions is in ima_parse_rule() */
|
IMA_UID | IMA_FOWNER | IMA_FSUUID |
|
||||||
|
IMA_INMASK | IMA_EUID | IMA_PCR |
|
||||||
|
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
|
||||||
|
IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED |
|
||||||
|
IMA_CHECK_BLACKLIST))
|
||||||
|
return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case KEXEC_CMDLINE:
|
case KEXEC_CMDLINE:
|
||||||
if (entry->action & ~(MEASURE | DONT_MEASURE))
|
if (entry->action & ~(MEASURE | DONT_MEASURE))
|
||||||
|
@ -1218,7 +1250,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||||
keyrings_len = strlen(args[0].from) + 1;
|
keyrings_len = strlen(args[0].from) + 1;
|
||||||
|
|
||||||
if ((entry->keyrings) ||
|
if ((entry->keyrings) ||
|
||||||
(entry->func != KEY_CHECK) ||
|
|
||||||
(keyrings_len < 2)) {
|
(keyrings_len < 2)) {
|
||||||
result = -EINVAL;
|
result = -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
@ -1358,15 +1389,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||||
AUDIT_SUBJ_TYPE);
|
AUDIT_SUBJ_TYPE);
|
||||||
break;
|
break;
|
||||||
case Opt_appraise_type:
|
case Opt_appraise_type:
|
||||||
if (entry->action != APPRAISE) {
|
|
||||||
result = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ima_log_string(ab, "appraise_type", args[0].from);
|
ima_log_string(ab, "appraise_type", args[0].from);
|
||||||
if ((strcmp(args[0].from, "imasig")) == 0)
|
if ((strcmp(args[0].from, "imasig")) == 0)
|
||||||
entry->flags |= IMA_DIGSIG_REQUIRED;
|
entry->flags |= IMA_DIGSIG_REQUIRED;
|
||||||
else if (ima_hook_supports_modsig(entry->func) &&
|
else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) &&
|
||||||
strcmp(args[0].from, "imasig|modsig") == 0)
|
strcmp(args[0].from, "imasig|modsig") == 0)
|
||||||
entry->flags |= IMA_DIGSIG_REQUIRED |
|
entry->flags |= IMA_DIGSIG_REQUIRED |
|
||||||
IMA_MODSIG_ALLOWED;
|
IMA_MODSIG_ALLOWED;
|
||||||
|
@ -1374,11 +1400,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||||
result = -EINVAL;
|
result = -EINVAL;
|
||||||
break;
|
break;
|
||||||
case Opt_appraise_flag:
|
case Opt_appraise_flag:
|
||||||
if (entry->action != APPRAISE) {
|
|
||||||
result = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ima_log_string(ab, "appraise_flag", args[0].from);
|
ima_log_string(ab, "appraise_flag", args[0].from);
|
||||||
if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) &&
|
if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) &&
|
||||||
strstr(args[0].from, "blacklist"))
|
strstr(args[0].from, "blacklist"))
|
||||||
|
@ -1390,10 +1411,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||||
entry->flags |= IMA_PERMIT_DIRECTIO;
|
entry->flags |= IMA_PERMIT_DIRECTIO;
|
||||||
break;
|
break;
|
||||||
case Opt_pcr:
|
case Opt_pcr:
|
||||||
if (entry->action != MEASURE) {
|
|
||||||
result = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ima_log_string(ab, "pcr", args[0].from);
|
ima_log_string(ab, "pcr", args[0].from);
|
||||||
|
|
||||||
result = kstrtoint(args[0].from, 10, &entry->pcr);
|
result = kstrtoint(args[0].from, 10, &entry->pcr);
|
||||||
|
|
Loading…
Reference in New Issue