Commit 30425756 authored by Roberto Sassu's avatar Roberto Sassu Committed by zgzxx
Browse files

ima: Allow direct upload of digest lists to securityfs

euleros inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I91FSN


CVE: NA

-------------------------------------------------

This patch allows direct upload of digest lists by user space parsers.
This operation is possible if the digest of the process's executable is
found in the digest lists and its type is COMPACT_PARSER.

ima_check_measured_appraised() is called at the end of ima_file_check() to
verify that everything accessed by the user space parsers (except for
directories and securityfs) has been processed by IMA. If a digest list
was not processed by an IMA submodule, digest list lookup is disabled for
that submodule.

v4:
 - fix checkpatch warning LONG_LINE and SUSPECT_CODE_INDENT in ima_main.c
   (zhangguangzhi)

Signed-off-by: default avatarRoberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: default avatarTianxing Zhang <zhangtianxing3@huawei.com>
Reviewed-by: default avatarJason Yan <yanaijie@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
Signed-off-by: default avatarzhoushuiqing <zhoushuiqing2@huawei.com>
Signed-off-by: default avatarzhangguangzhi <zhangguangzhi3@huawei.com>
parent 7634d983
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -647,7 +647,7 @@ int ima_appraise_measurement(enum ima_hooks func,
		/* Allow access to digest lists without metadata, only if they
		 * are signed or found in a digest list (immutable)
		 */
		if (func == DIGEST_LIST_CHECK) {
		if (func == DIGEST_LIST_CHECK || ima_current_is_parser()) {
			if (xattr_value->type == EVM_IMA_XATTR_DIGSIG)
				break;
			if (found_digest &&
+56 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <linux/file.h>
#include <linux/namei.h>
#include <linux/xattr.h>
#include <linux/sched/mm.h>
#include <linux/magic.h>

#include "ima.h"
#include "ima_digest_list.h"
@@ -217,6 +219,10 @@ void ima_check_measured_appraised(struct file *file)
	if (!ima_digest_list_actions)
		return;

	if (file_inode(file)->i_sb->s_magic == SECURITYFS_MAGIC ||
	    S_ISDIR(file_inode(file)->i_mode))
		return;

	iint = integrity_iint_find(file_inode(file));
	if (!iint) {
		pr_err("%s not processed, disabling digest lists lookup\n",
@@ -343,3 +349,53 @@ void __init ima_load_digest_lists(void)
out:
	path_put(&path);
}

/****************
 * Parser check *
 ****************/
bool ima_check_current_is_parser(void)
{
	struct integrity_iint_cache *parser_iint;
	struct file *parser_file;
	struct mm_struct *mm;

	mm = get_task_mm(current);
	if (!mm)
		return false;

	parser_file = get_mm_exe_file(mm);
	mmput(mm);

	if (!parser_file)
		return false;

	parser_iint = integrity_iint_find(file_inode(parser_file));
	fput(parser_file);

	if (!parser_iint)
		return false;

	/* flag cannot be cleared due to write protection of executables */
	if (!(parser_iint->flags & IMA_COLLECTED))
		return false;

	return ima_lookup_digest(parser_iint->ima_hash->digest,
				 parser_iint->ima_hash->algo, COMPACT_PARSER);
}

struct task_struct *parser_task;

void ima_set_parser(void)
{
	parser_task = current;
}

void ima_unset_parser(void)
{
	parser_task = NULL;
}

bool ima_current_is_parser(void)
{
	return (current == parser_task);
}
+18 −0
Original line number Diff line number Diff line
@@ -24,6 +24,10 @@ extern struct ima_h_table ima_digests_htable;

int ima_parse_compact_list(loff_t size, void *buf, int op);
void ima_check_measured_appraised(struct file *file);
bool ima_check_current_is_parser(void);
void ima_set_parser(void);
void ima_unset_parser(void);
bool ima_current_is_parser(void);
#else
static inline int ima_parse_compact_list(loff_t size, void *buf, int op)
{
@@ -32,5 +36,19 @@ static inline int ima_parse_compact_list(loff_t size, void *buf, int op)
static inline void ima_check_measured_appraised(struct file *file)
{
}
static inline bool ima_check_current_is_parser(void)
{
	return false;
}
static inline void ima_set_parser(void)
{
}
static inline void ima_unset_parser(void)
{
}
static inline bool ima_current_is_parser(void)
{
	return false;
}
#endif /*CONFIG_IMA_DIGEST_LIST*/
#endif /*LINUX_IMA_DIGEST_LIST_H*/
+24 −1
Original line number Diff line number Diff line
@@ -466,6 +466,20 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
		} else {
			result = ima_parse_add_rule(data);
		}
	} else if (dentry == digest_list_data) {
		if (!ima_current_is_parser()) {
			result = -EACCES;
		} else {
			result = ima_parse_compact_list(datalen, data,
							DIGEST_LIST_OP_ADD);
		}
	} else if (dentry == digest_list_data_del) {
		if (!ima_current_is_parser()) {
			result = -EACCES;
		} else {
			result = ima_parse_compact_list(datalen, data,
							DIGEST_LIST_OP_DEL);
		}
#else
		result = ima_read_policy(data);
	} else if (ima_appraise & IMA_APPRAISE_POLICY) {
@@ -474,7 +488,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
				    "policy_update", "signed policy required",
				    1, 0);
		result = -EACCES;
#endif
#endif /* CONFIG_IMA_DIGEST_LIST */
	} else {
#ifdef CONFIG_IMA_DIGEST_LIST
		pr_err("Unknown data type\n");
@@ -593,6 +607,12 @@ static int ima_open_policy(struct inode *inode, struct file *filp)
	if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
#endif
		return -EBUSY;

#ifdef CONFIG_IMA_DIGEST_LIST
	if (dentry == digest_list_data || dentry == digest_list_data_del)
		if (ima_check_current_is_parser())
			ima_set_parser();
#endif
	return 0;
}

@@ -625,6 +645,9 @@ static int ima_release_policy(struct inode *inode, struct file *file)
	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
		return seq_release(inode, file);
#ifdef CONFIG_IMA_DIGEST_LIST
	if (dentry == digest_list_data || dentry == digest_list_data_del)
		ima_unset_parser();

	if (dentry != ima_policy) {
		clear_bit(flag, &ima_fs_flags);
		return 0;
+12 −0
Original line number Diff line number Diff line
@@ -645,11 +645,23 @@ int ima_bprm_check(struct linux_binprm *bprm)
int ima_file_check(struct file *file, int mask)
{
	u32 secid;
#ifdef CONFIG_IMA_DIGEST_LIST
	int rc;
#endif

	security_current_getsecid_subj(&secid);
#ifdef CONFIG_IMA_DIGEST_LIST
	rc = process_measurement(file, current_cred(), secid, NULL, 0,
				 mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
					 MAY_APPEND), FILE_CHECK);
	if (ima_current_is_parser() && !rc)
		ima_check_measured_appraised(file);
	return rc;
#else
	return process_measurement(file, current_cred(), secid, NULL, 0,
				   mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
					   MAY_APPEND), FILE_CHECK);
#endif
}
EXPORT_SYMBOL_GPL(ima_file_check);