@@ -29,7 +29,7 @@ Description:
[obj_user=] [obj_role=] [obj_type=]]
option: [digest_type=] [template=] [permit_directio]
[appraise_type=] [appraise_flag=]
- [appraise_algos=] [keyrings=]
+ [appraise_algos=] [keyrings=] [digest_cache=]
base:
func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
[FIRMWARE_CHECK]
@@ -77,6 +77,9 @@ Description:
For example, "sha256,sha512" to only accept to appraise
files where the security.ima xattr was hashed with one
of these two algorithms.
+ digest_cache:= [data]
+ "data" means that the digest cache is used only
+ for file data measurement and/or appraisal.
default policy:
# PROC_SUPER_MAGIC
@@ -43,6 +43,10 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
#define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0)
+/* Digest cache usage flags. */
+#define IMA_DIGEST_CACHE_MEASURE_DATA 0x0000000000000001
+#define IMA_DIGEST_CACHE_APPRAISE_DATA 0x0000000000000002
+
/* current content of the policy */
extern int ima_policy_flag;
@@ -367,7 +371,8 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
- const char *func_data, unsigned int *allowed_algos);
+ const char *func_data, unsigned int *allowed_algos,
+ u64 *digest_cache_usage);
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
void *buf, loff_t size, enum hash_algo algo,
@@ -398,7 +403,8 @@ int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode,
const struct cred *cred, u32 secid, enum ima_hooks func,
int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
- const char *func_data, unsigned int *allowed_algos);
+ const char *func_data, unsigned int *allowed_algos,
+ u64 *digest_cache_usage);
void ima_init_policy(void);
void ima_update_policy(void);
void ima_update_policy_flags(void);
@@ -173,6 +173,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* @template_desc: pointer filled in if matched measure policy sets template=
* @func_data: func specific data, may be NULL
* @allowed_algos: allowlist of hash algorithms for the IMA xattr
+ * @digest_cache_usage: Actions and purpose for which digest cache is allowed
*
* The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic=
@@ -190,7 +191,8 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
- const char *func_data, unsigned int *allowed_algos)
+ const char *func_data, unsigned int *allowed_algos,
+ u64 *digest_cache_usage)
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
@@ -198,7 +200,7 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
return ima_match_policy(idmap, inode, cred, secid, func, mask,
flags, pcr, template_desc, func_data,
- allowed_algos);
+ allowed_algos, digest_cache_usage);
}
static bool ima_get_verity_digest(struct ima_iint_cache *iint,
@@ -81,7 +81,7 @@ int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
security_current_getsecid_subj(&secid);
return ima_match_policy(idmap, inode, current_cred(), secid,
func, mask, IMA_APPRAISE | IMA_HASH, NULL,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
}
static int ima_fix_xattr(struct dentry *dentry, struct ima_iint_cache *iint)
@@ -232,7 +232,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
*/
action = ima_get_action(file_mnt_idmap(file), inode, cred, secid,
mask, func, &pcr, &template_desc, NULL,
- &allowed_algos);
+ &allowed_algos, NULL);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK ||
func == MMAP_CHECK_REQPROT) &&
(ima_policy_flag & IMA_MEASURE));
@@ -489,11 +489,11 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
inode = file_inode(vma->vm_file);
action = ima_get_action(file_mnt_idmap(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
- &pcr, &template, NULL, NULL);
+ &pcr, &template, NULL, NULL, NULL);
action |= ima_get_action(file_mnt_idmap(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC,
MMAP_CHECK_REQPROT, &pcr, &template, NULL,
- NULL);
+ NULL, NULL);
/* Is the mmap'ed file in policy? */
if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
@@ -972,7 +972,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
security_current_getsecid_subj(&secid);
action = ima_get_action(idmap, inode, current_cred(),
secid, 0, func, &pcr, &template,
- func_data, NULL);
+ func_data, NULL, NULL);
if (!(action & IMA_MEASURE) && !digest)
return -ENOENT;
}
@@ -122,6 +122,7 @@ struct ima_rule_entry {
struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */
struct ima_rule_opt_list *label; /* Measure data grouped under this label */
struct ima_template_desc *template;
+ u64 digest_cache_usage; /* Actions and purpose for which digest cache is allowed */
};
/*
@@ -726,6 +727,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @template_desc: the template that should be used for this rule
* @func_data: func specific data, may be NULL
* @allowed_algos: allowlist of hash algorithms for the IMA xattr
+ * @digest_cache_usage: Actions and purpose for which digest cache is allowed
*
* Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
* conditions.
@@ -738,7 +740,8 @@ int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode,
const struct cred *cred, u32 secid, enum ima_hooks func,
int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
- const char *func_data, unsigned int *allowed_algos)
+ const char *func_data, unsigned int *allowed_algos,
+ u64 *digest_cache_usage)
{
struct ima_rule_entry *entry;
int action = 0, actmask = flags | (flags << 1);
@@ -783,6 +786,9 @@ int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode,
if (template_desc && entry->template)
*template_desc = entry->template;
+ if (digest_cache_usage)
+ *digest_cache_usage |= entry->digest_cache_usage;
+
if (!actmask)
break;
}
@@ -859,6 +865,30 @@ static int ima_appraise_flag(enum ima_hooks func)
return 0;
}
+static bool ima_digest_cache_func_allowed(struct ima_rule_entry *entry)
+{
+ switch (entry->func) {
+ case NONE:
+ case FILE_CHECK:
+ case MMAP_CHECK:
+ case MMAP_CHECK_REQPROT:
+ case BPRM_CHECK:
+ case CREDS_CHECK:
+ case FIRMWARE_CHECK:
+ case POLICY_CHECK:
+ case MODULE_CHECK:
+ case KEXEC_KERNEL_CHECK:
+ case KEXEC_INITRAMFS_CHECK:
+ /* Exception: always add policy updates to measurement list! */
+ if (entry->action == MEASURE && entry->func == POLICY_CHECK)
+ return false;
+
+ return true;
+ default:
+ return false;
+ }
+}
+
static void add_rules(struct ima_rule_entry *entries, int count,
enum policy_rule_list policy_rule)
{
@@ -1073,7 +1103,7 @@ enum policy_opt {
Opt_digest_type,
Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
- Opt_label, Opt_err
+ Opt_label, Opt_digest_cache, Opt_err
};
static const match_table_t policy_tokens = {
@@ -1122,6 +1152,7 @@ static const match_table_t policy_tokens = {
{Opt_template, "template=%s"},
{Opt_keyrings, "keyrings=%s"},
{Opt_label, "label=%s"},
+ {Opt_digest_cache, "digest_cache=%s"},
{Opt_err, NULL}
};
@@ -1245,6 +1276,18 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
if (entry->action != MEASURE && entry->flags & IMA_PCR)
return false;
+ /* New-style measurements with digest cache cannot be on default PCR. */
+ if (entry->action == MEASURE &&
+ (entry->digest_cache_usage & IMA_DIGEST_CACHE_MEASURE_DATA)) {
+ if (!(entry->flags & IMA_PCR) ||
+ entry->pcr == CONFIG_IMA_MEASURE_PCR_IDX)
+ return false;
+ }
+
+ /* Digest caches can be used only for a subset of the IMA hooks. */
+ if (entry->digest_cache_usage && !ima_digest_cache_func_allowed(entry))
+ return false;
+
if (entry->action != APPRAISE &&
entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
@@ -1881,6 +1924,26 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
&(template_desc->num_fields));
entry->template = template_desc;
break;
+ case Opt_digest_cache:
+ ima_log_string(ab, "digest_cache", args[0].from);
+
+ result = -EINVAL;
+
+ if (!strcmp(args[0].from, "data")) {
+ switch (entry->action) {
+ case MEASURE:
+ entry->digest_cache_usage |= IMA_DIGEST_CACHE_MEASURE_DATA;
+ result = 0;
+ break;
+ case APPRAISE:
+ entry->digest_cache_usage |= IMA_DIGEST_CACHE_APPRAISE_DATA;
+ result = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
case Opt_err:
ima_log_string(ab, "UNKNOWN", p);
result = -EINVAL;
@@ -2271,6 +2334,9 @@ int ima_policy_show(struct seq_file *m, void *v)
seq_puts(m, "digest_type=verity ");
if (entry->flags & IMA_PERMIT_DIRECTIO)
seq_puts(m, "permit_directio ");
+ if ((entry->digest_cache_usage & IMA_DIGEST_CACHE_MEASURE_DATA) ||
+ (entry->digest_cache_usage & IMA_DIGEST_CACHE_APPRAISE_DATA))
+ seq_puts(m, "digest_cache=data ");
rcu_read_unlock();
seq_puts(m, "\n");
return 0;