@@ -53,6 +53,8 @@ extern int ima_hash_algo;
extern int ima_appraise;
extern struct tpm_chip *ima_tpm_chip;
+extern int ima_digest_list_actions;
+
/* IMA event related data */
struct ima_event_data {
struct integrity_iint_cache *iint;
@@ -163,6 +163,9 @@ bool ima_check_current_is_parser(void)
struct file *parser_file;
struct mm_struct *mm;
+ if (!(ima_digest_list_actions & ima_policy_flag))
+ return false;
+
mm = get_task_mm(current);
if (!mm)
return false;
@@ -204,3 +207,36 @@ struct task_struct *ima_get_parser(void)
{
return current_parser;
}
+
+/**********************
+ * Digest usage check *
+ **********************/
+void ima_check_parser_action(struct inode *inode, enum ima_hooks hook,
+ int mask, int action, bool check_digest,
+ struct ima_digest *digest)
+{
+ int action_mask = (IMA_DO_MASK & ~IMA_APPRAISE_SUBMASK);
+
+ if (current != current_parser)
+ return;
+
+ if (!(mask & (MAY_READ | MAY_EXEC)))
+ return;
+
+ if (hook == MMAP_CHECK && mask == MAY_EXEC && check_digest &&
+ (!digest || digest->type != COMPACT_PARSER))
+ action_mask = 0;
+
+ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+ action_mask = 0;
+
+ ima_digest_list_actions &= (action & action_mask);
+}
+
+struct ima_digest *ima_digest_allow(struct ima_digest *digest, int action)
+{
+ if (!(ima_digest_list_actions & action))
+ return NULL;
+
+ return digest;
+}
@@ -29,6 +29,10 @@ int ima_parse_compact_list(loff_t size, void *buf);
bool ima_check_current_is_parser(void);
void ima_set_parser(struct task_struct *parser);
struct task_struct *ima_get_parser(void);
+void ima_check_parser_action(struct inode *inode, enum ima_hooks hook,
+ int mask, int action, bool check_digest,
+ struct ima_digest *digest);
+struct ima_digest *ima_digest_allow(struct ima_digest *digest, int action);
#else
static inline struct ima_digest *ima_lookup_digest(u8 *digest,
enum hash_algo algo)
@@ -50,5 +54,16 @@ static inline struct task_struct *ima_get_parser(void)
{
return NULL;
}
+static inline void ima_check_parser_action(struct inode *inode,
+ enum ima_hooks hook, int mask,
+ int action, bool check_digest,
+ struct ima_digest *digest)
+{
+}
+static inline struct ima_digest *ima_digest_allow(struct ima_digest *digest,
+ int action)
+{
+ return NULL;
+}
#endif /*CONFIG_IMA_DIGEST_LIST*/
#endif /*LINUX_IMA_DIGEST_LIST_H*/
@@ -29,6 +29,7 @@
#include <linux/fs.h>
#include "ima.h"
+#include "ima_digest_list.h"
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise = IMA_APPRAISE_ENFORCE;
@@ -36,6 +37,9 @@ int ima_appraise = IMA_APPRAISE_ENFORCE;
int ima_appraise;
#endif
+/* Actions (measure/appraisal) for which digest lists can be used */
+int ima_digest_list_actions;
+
int ima_hash_algo = HASH_ALGO_SHA1;
static int hash_setup_done;
@@ -252,11 +256,15 @@ static int process_measurement(struct file *file, const struct cred *cred,
const char *pathname = NULL;
int rc = 0, action, must_appraise = 0;
int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+ struct ima_digest *found_digest = NULL;
struct evm_ima_xattr_data *xattr_value = NULL;
int xattr_len = 0;
bool violation_check;
enum hash_algo hash_algo;
+ ima_check_parser_action(inode, func, mask, ima_policy_flag, false,
+ NULL);
+
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return 0;
@@ -268,6 +276,9 @@ static int process_measurement(struct file *file, const struct cred *cred,
&template_desc);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
+
+ ima_check_parser_action(inode, func, mask, action, false, NULL);
+
if (!action && !violation_check)
return 0;
@@ -312,7 +323,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags) ||
((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
!(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) &&
- !(action & IMA_FAIL_UNVERIFIABLE_SIGS))) {
+ !(action & IMA_FAIL_UNVERIFIABLE_SIGS)) ||
+ ima_get_parser() == current) {
iint->flags &= ~IMA_DONE_MASK;
iint->measured_pcrs = 0;
}
@@ -366,6 +378,9 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
pathname = ima_d_path(&file->f_path, &pathbuf, filename);
+ found_digest = ima_lookup_digest(iint->ima_hash->digest, hash_algo);
+ ima_check_parser_action(inode, func, mask, action, true, found_digest);
+
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, pcr,
The Digest Lists extension creates a new measurement only when a file is unknown (i.e. its digest is not found in the uploaded digest lists). However, if digest lists are not measured, a remote verifier cannot determine which files could have possibly been accessed. If they are not appraised, a user would be able to access files that are not signed or protected with a HMAC. This patch prevents this issue by monitoring the process that opened digest_list_data and that can upload digests. If the process opens a file that is not measured, digest list queries by IMA-Measure will be always negative (ima_digest_allow() will always return a NULL pointer). The same happens for IMA-Appraise. This patch also ensures that the parser can only execute shared libraries with type COMPACT_PARSER (i.e. libraries adding support for custom digest list formats). Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> --- security/integrity/ima/ima.h | 2 ++ security/integrity/ima/ima_digest_list.c | 36 ++++++++++++++++++++++++ security/integrity/ima/ima_digest_list.h | 15 ++++++++++ security/integrity/ima/ima_main.c | 17 ++++++++++- 4 files changed, 69 insertions(+), 1 deletion(-)