linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM
@ 2021-09-30 11:55 Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 1/7] integrity: Change type of IMA rule-related flags to u64 Roberto Sassu
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Roberto Sassu @ 2021-09-30 11:55 UTC (permalink / raw)
  To: zohar, gregkh, mchehab+huawei
  Cc: linux-integrity, linux-security-module, linux-kernel, Roberto Sassu

I'm posting this patch set, although the dependencies are not yet accepted,
to provide a more complete picture about DIGLIM and how it can be
concretely used.

This patch set depends on:
- new execution policies in IMA
  (https://lore.kernel.org/linux-integrity/20210409114313.4073-1-roberto.sassu@huawei.com/)
- support for the euid policy keyword for critical data
  (https://lore.kernel.org/linux-integrity/20210705115650.3373599-1-roberto.sassu@huawei.com/)
- DIGLIM basic features
  (https://lore.kernel.org/linux-integrity/20210914163401.864635-1-roberto.sassu@huawei.com/)
- DIGLIM advanced features
  (https://lore.kernel.org/linux-integrity/20210915163145.1046505-1-roberto.sassu@huawei.com/)

The patch sets 'integrity: Introduce DIGLIM' and 'integrity: Introduce
DIGLIM advanced features' introduced the possibility to build a repository
of reference values for files shipped with Linux distributions.

Currently those reference values can be loaded from a file in the compact
format, supported by the kernel, or from RPM headers. With future patch
sets, which will add support for PGP appended signatures, it will also be
possible to appraise untouched RPM headers with IMA.

The objective of this patch set is to introduce an alternative method for
performing measurements and appraisal with IMA, that overcome some
important limitations of the currently supported methods. For example,
for measurement, it is very hard to obtain a stable PCR that can be use
for sealing of TPM keys or data. For appraisal, Linux distributions vendors
have to change their building systems to include file signatures in the
packages.

The alternative method introduced with this patch set consists in skipping
the measurement and/or in granting access, when appraisal is in enforcing
mode, if the file or metadata digest has been found in the DIGLIM hash
table. A discussion about this approach can be found in the Benefits
section at:

https://lore.kernel.org/linux-integrity/20210914163401.864635-1-roberto.sassu@huawei.com/

The structure of this patch set is as follows.

Patches 1-3 introduce the 'use_diglim' keyword to select the alternative
method for measurement and appraisal and two new hardcoded policies to
measure and appraise DIGLIM-related files, and to enable usage of DIGLIM
for the other selected policy rules.

Patches 4-5 query respectively the file and metadata digest in DIGLIM.
DIGLIM returns whether the digest lists containing the passed digest have
been measured and appraised (requirement to select the alternative method),
and whether the file or metadata are immutable. In a future extension, a
new modifier will be introduced to tell IMA that the digest belongs to a
deny list instead of an allow list, so that IMA can act accordingly.

Patches 5-6 introduce the alternative method for measurement and appraisal.
If at least one digest list containing the calculated file or metadata
digest have been measured, IMA behaves as it performed a measurement. If at
least one digest list containing the calculated metadata digest has been
appraised, metadata verification is successful (required only when EVM is
enabled). If the same condition is verified for the calculated file or
metadata digest, file content verification is successful and the file is
marked as immutable if the digest lists have the corresponding modifier set
in the header.

It is important to remark that unless 'use_diglim' is set in the IMA
policy, DIGLIM is completely ignored and IMA behaves as before. In
addition, even if DIGLIM usage is enabled, other appraisal verification
methods with the xattr or the appended signature take precedence.

Roberto Sassu (7):
  integrity: Change type of IMA rule-related flags to u64
  ima: Introduce new policy keyword use_diglim
  ima: Introduce diglim and appraise_diglim policies
  ima: Query file digest and retrieve info from its digest lists
  ima: Query metadata digest and retrieve info from its digest lists
  ima: Skip measurement of files found in DIGLIM hash table
  ima: Add support for appraisal with digest lists

 Documentation/ABI/testing/ima_policy          |   4 +-
 .../admin-guide/kernel-parameters.txt         |  19 ++-
 include/linux/evm.h                           |  14 ++
 security/integrity/evm/evm_main.c             |  40 +++++
 security/integrity/ima/ima.h                  |   9 +-
 security/integrity/ima/ima_api.c              |   2 +-
 security/integrity/ima/ima_appraise.c         |  37 ++++-
 security/integrity/ima/ima_main.c             |  84 +++++++++-
 security/integrity/ima/ima_policy.c           | 144 +++++++++++++++++-
 security/integrity/integrity.h                |  62 ++++----
 10 files changed, 365 insertions(+), 50 deletions(-)

-- 
2.32.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [RFC][PATCH 1/7] integrity: Change type of IMA rule-related flags to u64
  2021-09-30 11:55 [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM Roberto Sassu
@ 2021-09-30 11:55 ` Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 2/7] ima: Introduce new policy keyword use_diglim Roberto Sassu
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Roberto Sassu @ 2021-09-30 11:55 UTC (permalink / raw)
  To: zohar, gregkh, mchehab+huawei
  Cc: linux-integrity, linux-security-module, linux-kernel, Roberto Sassu

Change the type of the flags member of integrity_iint_cache and
ima_rule_entry, and the type of return value of ima_match_policy() and
ima_get_action() to u64 to make room for more flags.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 security/integrity/ima/ima.h        |  4 +-
 security/integrity/ima/ima_api.c    |  2 +-
 security/integrity/ima/ima_main.c   |  3 +-
 security/integrity/ima/ima_policy.c |  6 +--
 security/integrity/integrity.h      | 60 ++++++++++++++---------------
 5 files changed, 38 insertions(+), 37 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d01ca3566aec..cde2e1c2a6be 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -255,7 +255,7 @@ static inline void ima_process_queued_keys(void) {}
 #endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS */
 
 /* LIM API function definitions */
-int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
+u64 ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
 		   const struct cred *cred, u32 secid, int mask,
 		   enum ima_hooks func, int *pcr,
 		   struct ima_template_desc **template_desc,
@@ -286,7 +286,7 @@ void ima_free_template_entry(struct ima_template_entry *entry);
 const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
 
 /* IMA policy related functions */
-int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
+u64 ima_match_policy(struct user_namespace *mnt_userns, 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,
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 2c6c3a5228b5..bd9316d89243 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -185,7 +185,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
  * Returns IMA_MEASURE, IMA_APPRAISE mask.
  *
  */
-int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
+u64 ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
 		   const struct cred *cred, u32 secid, int mask,
 		   enum ima_hooks func, int *pcr,
 		   struct ima_template_desc **template_desc,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index d33765c7aaa7..fe1f4ef1bb9d 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -208,7 +208,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
 	char *pathbuf = NULL;
 	char filename[NAME_MAX];
 	const char *pathname = NULL;
-	int rc = 0, action, must_appraise = 0;
+	u64 action;
+	int rc = 0, must_appraise = 0;
 	int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
 	struct evm_ima_xattr_data *xattr_value = NULL;
 	struct modsig *modsig = NULL;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 8d6f5d85dfa4..084b5d9257da 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -74,7 +74,7 @@ struct ima_rule_opt_list {
 struct ima_rule_entry {
 	struct list_head list;
 	int action;
-	unsigned int flags;
+	u64 flags;
 	enum ima_hooks func;
 	int mask;
 	unsigned long fsmagic;
@@ -702,14 +702,14 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
  * list when walking it.  Reads are many orders of magnitude more numerous
  * than writes so ima_match_policy() is classical RCU candidate.
  */
-int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
+u64 ima_match_policy(struct user_namespace *mnt_userns, 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)
 {
 	struct ima_rule_entry *entry;
-	int action = 0, actmask = flags | (flags << 1);
+	u64 action = 0, actmask = flags | (flags << 1);
 	struct list_head *ima_rules_tmp;
 
 	if (template_desc && !*template_desc)
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 2ab85f286d17..cb4a8cd2a213 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -23,27 +23,27 @@
 #include <crypto/hash_info.h>
 
 /* iint action cache flags */
-#define IMA_MEASURE		0x00000001
-#define IMA_MEASURED		0x00000002
-#define IMA_APPRAISE		0x00000004
-#define IMA_APPRAISED		0x00000008
-/*#define IMA_COLLECT		0x00000010  do not use this flag */
-#define IMA_COLLECTED		0x00000020
-#define IMA_AUDIT		0x00000040
-#define IMA_AUDITED		0x00000080
-#define IMA_HASH		0x00000100
-#define IMA_HASHED		0x00000200
+#define IMA_MEASURE		0x0000000000000001
+#define IMA_MEASURED		0x0000000000000002
+#define IMA_APPRAISE		0x0000000000000004
+#define IMA_APPRAISED		0x0000000000000008
+/*#define IMA_COLLECT		0x0000000000000010  do not use this flag */
+#define IMA_COLLECTED		0x0000000000000020
+#define IMA_AUDIT		0x0000000000000040
+#define IMA_AUDITED		0x0000000000000080
+#define IMA_HASH		0x0000000000000100
+#define IMA_HASHED		0x0000000000000200
 
 /* iint cache flags */
-#define IMA_ACTION_FLAGS	0xff000000
-#define IMA_DIGSIG_REQUIRED	0x01000000
-#define IMA_PERMIT_DIRECTIO	0x02000000
-#define IMA_NEW_FILE		0x04000000
-#define EVM_IMMUTABLE_DIGSIG	0x08000000
-#define IMA_FAIL_UNVERIFIABLE_SIGS	0x10000000
-#define IMA_MODSIG_ALLOWED	0x20000000
-#define IMA_CHECK_BLACKLIST	0x40000000
-#define IMA_META_IMMUTABLE_REQUIRED	0x80000000
+#define IMA_ACTION_FLAGS	0xffffffffff000000
+#define IMA_DIGSIG_REQUIRED	0x0000000001000000
+#define IMA_PERMIT_DIRECTIO	0x0000000002000000
+#define IMA_NEW_FILE		0x0000000004000000
+#define EVM_IMMUTABLE_DIGSIG	0x0000000008000000
+#define IMA_FAIL_UNVERIFIABLE_SIGS	0x0000000010000000
+#define IMA_MODSIG_ALLOWED	0x0000000020000000
+#define IMA_CHECK_BLACKLIST	0x0000000040000000
+#define IMA_META_IMMUTABLE_REQUIRED	0x0000000080000000
 
 #define IMA_DO_MASK		(IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
 				 IMA_HASH | IMA_APPRAISE_SUBMASK)
@@ -52,16 +52,16 @@
 				 IMA_APPRAISED_SUBMASK)
 
 /* iint subaction appraise cache flags */
-#define IMA_FILE_APPRAISE	0x00001000
-#define IMA_FILE_APPRAISED	0x00002000
-#define IMA_MMAP_APPRAISE	0x00004000
-#define IMA_MMAP_APPRAISED	0x00008000
-#define IMA_BPRM_APPRAISE	0x00010000
-#define IMA_BPRM_APPRAISED	0x00020000
-#define IMA_READ_APPRAISE	0x00040000
-#define IMA_READ_APPRAISED	0x00080000
-#define IMA_CREDS_APPRAISE	0x00100000
-#define IMA_CREDS_APPRAISED	0x00200000
+#define IMA_FILE_APPRAISE	0x0000000000001000
+#define IMA_FILE_APPRAISED	0x0000000000002000
+#define IMA_MMAP_APPRAISE	0x0000000000004000
+#define IMA_MMAP_APPRAISED	0x0000000000008000
+#define IMA_BPRM_APPRAISE	0x0000000000010000
+#define IMA_BPRM_APPRAISED	0x0000000000020000
+#define IMA_READ_APPRAISE	0x0000000000040000
+#define IMA_READ_APPRAISED	0x0000000000080000
+#define IMA_CREDS_APPRAISE	0x0000000000100000
+#define IMA_CREDS_APPRAISED	0x0000000000200000
 #define IMA_APPRAISE_SUBMASK	(IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
 				 IMA_BPRM_APPRAISE | IMA_READ_APPRAISE | \
 				 IMA_CREDS_APPRAISE)
@@ -133,7 +133,7 @@ struct integrity_iint_cache {
 	struct mutex mutex;	/* protects: version, flags, digest */
 	struct inode *inode;	/* back pointer to inode in question */
 	u64 version;		/* track inode changes */
-	unsigned long flags;
+	u64 flags;
 	unsigned long measured_pcrs;
 	unsigned long atomic_flags;
 	enum integrity_status ima_file_status:4;
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC][PATCH 2/7] ima: Introduce new policy keyword use_diglim
  2021-09-30 11:55 [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 1/7] integrity: Change type of IMA rule-related flags to u64 Roberto Sassu
@ 2021-09-30 11:55 ` Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 3/7] ima: Introduce diglim and appraise_diglim policies Roberto Sassu
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Roberto Sassu @ 2021-09-30 11:55 UTC (permalink / raw)
  To: zohar, gregkh, mchehab+huawei
  Cc: linux-integrity, linux-security-module, linux-kernel, Roberto Sassu

Introduce the 'use_diglim' policy keyword to enable the usage of
DIGLIM if the file matches the other criteria of the rule.

If the file or metadata digest is found in the DIGLIM hash table,
'use_diglim':
- skips the creation of a new measurement entry (action=measure)
- allows access to the file (action=appraise)

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 Documentation/ABI/testing/ima_policy |  4 +++-
 security/integrity/ima/ima_policy.c  | 36 +++++++++++++++++++++++++---
 security/integrity/integrity.h       |  2 ++
 3 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index a8a5791db14c..4979fc068b0e 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -27,7 +27,7 @@ Description:
 			lsm:	[[subj_user=] [subj_role=] [subj_type=]
 				 [obj_user=] [obj_role=] [obj_type=]]
 			option:	[[appraise_type=]] [template=] [permit_directio]
-				[appraise_flag=] [appraise_algos=] [keyrings=]
+				[appraise_flag=] [appraise_algos=] [keyrings=] [use_diglim]
 		  base:
 			func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
 				[FIRMWARE_CHECK]
@@ -60,6 +60,8 @@ Description:
 			For example, "sha256,sha512" to only accept to appraise
 			files where the security.ima xattr was hashed with one
 			of these two algorithms.
+			use_diglim: enables usage of DIGLIM for measurement and
+			appraisal
 
 		  default policy:
 			# PROC_SUPER_MAGIC
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 084b5d9257da..dfab21aeb7e1 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -1048,7 +1048,7 @@ enum {
 	Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
 	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_use_diglim, Opt_err
 };
 
 static const match_table_t policy_tokens = {
@@ -1087,6 +1087,7 @@ static const match_table_t policy_tokens = {
 	{Opt_template, "template=%s"},
 	{Opt_keyrings, "keyrings=%s"},
 	{Opt_label, "label=%s"},
+	{Opt_use_diglim, "use_diglim"},
 	{Opt_err, NULL}
 };
 
@@ -1181,6 +1182,15 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
 	if (entry->action != MEASURE && entry->flags & IMA_PCR)
 		return false;
 
+	/*
+	 * Ensure that measurements made with DIGLIM don't have the standard
+	 * IMA PCR.
+	 */
+	if ((entry->flags & IMA_USE_DIGLIM_MEASURE) &&
+	    (!(entry->flags & IMA_PCR) ||
+	     entry->pcr == CONFIG_IMA_MEASURE_PCR_IDX))
+		return false;
+
 	if (entry->action != APPRAISE &&
 	    entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
 			    IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS |
@@ -1215,7 +1225,9 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
 				     IMA_INMASK | IMA_EUID | IMA_PCR |
 				     IMA_FSNAME | IMA_DIGSIG_REQUIRED |
 				     IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS |
-				     IMA_META_IMMUTABLE_REQUIRED))
+				     IMA_META_IMMUTABLE_REQUIRED |
+				     IMA_USE_DIGLIM_MEASURE |
+				     IMA_USE_DIGLIM_APPRAISE))
 			return false;
 
 		break;
@@ -1229,7 +1241,9 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
 				     IMA_FSNAME | IMA_DIGSIG_REQUIRED |
 				     IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED |
 				     IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS |
-				     IMA_META_IMMUTABLE_REQUIRED))
+				     IMA_META_IMMUTABLE_REQUIRED |
+				     IMA_USE_DIGLIM_MEASURE |
+				     IMA_USE_DIGLIM_APPRAISE))
 			return false;
 
 		break;
@@ -1719,6 +1733,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 						 &(template_desc->num_fields));
 			entry->template = template_desc;
 			break;
+		case Opt_use_diglim:
+			ima_log_string(ab, "use_diglim", args[0].from);
+			if (entry->action != IMA_MEASURE &&
+			    entry->action != IMA_APPRAISE) {
+				result = -EINVAL;
+				break;
+			}
+
+			if (entry->action == IMA_MEASURE)
+				entry->flags |= IMA_USE_DIGLIM_MEASURE;
+			else
+				entry->flags |= IMA_USE_DIGLIM_APPRAISE;
+			break;
 		case Opt_err:
 			ima_log_string(ab, "UNKNOWN", p);
 			result = -EINVAL;
@@ -2058,6 +2085,9 @@ int ima_policy_show(struct seq_file *m, void *v)
 		seq_puts(m, "appraise_type=meta_immutable ");
 	if (entry->flags & IMA_PERMIT_DIRECTIO)
 		seq_puts(m, "permit_directio ");
+	if ((entry->flags & IMA_USE_DIGLIM_MEASURE) ||
+	    (entry->flags & IMA_USE_DIGLIM_APPRAISE))
+		seq_puts(m, "use_diglim ");
 	rcu_read_unlock();
 	seq_puts(m, "\n");
 	return 0;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index cb4a8cd2a213..89ed87a957bc 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -44,6 +44,8 @@
 #define IMA_MODSIG_ALLOWED	0x0000000020000000
 #define IMA_CHECK_BLACKLIST	0x0000000040000000
 #define IMA_META_IMMUTABLE_REQUIRED	0x0000000080000000
+#define IMA_USE_DIGLIM_MEASURE	0x0000000100000000
+#define IMA_USE_DIGLIM_APPRAISE	0x0000000200000000
 
 #define IMA_DO_MASK		(IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
 				 IMA_HASH | IMA_APPRAISE_SUBMASK)
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC][PATCH 3/7] ima: Introduce diglim and appraise_diglim policies
  2021-09-30 11:55 [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 1/7] integrity: Change type of IMA rule-related flags to u64 Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 2/7] ima: Introduce new policy keyword use_diglim Roberto Sassu
@ 2021-09-30 11:55 ` Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 4/7] ima: Query file digest and retrieve info from its digest lists Roberto Sassu
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Roberto Sassu @ 2021-09-30 11:55 UTC (permalink / raw)
  To: zohar, gregkh, mchehab+huawei
  Cc: linux-integrity, linux-security-module, linux-kernel, Roberto Sassu

Introduce two new hardcoded policies, 'diglim' and 'appraise_diglim' to
measure and appraise digest lists and related files.

In particular, the 'diglim' policy adds the new rule:

measure func=DIGEST_LIST_CHECK pcr=<PCR value> use_diglim

where PCR value is 11 or the one chosen with the ima_diglim_pcr= kernel
option. It also adds the use_diglim directive to existing selected rules
with hooks BPRM_CHECK, CREDS_CHECK, MMAP_CHECK, FILE_CHECK, MODULE_CHECK,
FIRMWARE_CHECK and DIGEST_LIST_CHECK.

A rule with the DIGEST_LIST_CHECK hook is sufficient to cover all aspects
of the digest list loading process. For direct upload, the kernel reads the
file with type READING_DIGEST_LIST, which is mapped to that hook. For
upload by a user space parser, DIGLIM LSM performs a second read for every
file opened by the parser (including the executable), also with type
READING_DIGEST_LIST.

The 'appraise_diglim' policy adds the new rule:

appraise func=DIGEST_LIST_CHECK appraise_type=imasig|modsig use_diglim

and, like for the 'diglim' policy, adds the use_diglim directive for the
selected IMA rules with action appraise.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 .../admin-guide/kernel-parameters.txt         |  19 +++-
 security/integrity/ima/ima_policy.c           | 102 +++++++++++++++++-
 2 files changed, 119 insertions(+), 2 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index e0db162ba202..fa4959a321d8 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1835,6 +1835,13 @@
 			Use the canonical format for the binary runtime
 			measurements, instead of host native format.
 
+	ima_diglim_pcr=
+			[IMA]
+			Format: 0 - 23
+			default: 11
+			Define the PCR to be used for measurement entries
+			created with the diglim IMA policy.
+
 	ima_hash=	[IMA]
 			Format: { md5 | sha1 | rmd160 | sha256 | sha384
 				   | sha512 | ... }
@@ -1846,7 +1853,8 @@
 	ima_policy=	[IMA]
 			The builtin policies to load during IMA setup.
 			Format: "tcb | appraise_tcb | secure_boot |
-				 fail_securely | critical_data"
+				 fail_securely | critical_data | diglim |
+				 appraise_diglim"
 
 			The "tcb" policy measures all programs exec'd, files
 			mmap'd for exec, and all files opened with the read
@@ -1860,6 +1868,11 @@
 			the tmpfs filesystem, for the "ima_tcb", "tcb" and
 			"exec_tcb" policies.
 
+			The "diglim" policy enables measurement of
+			DIGLIM-related files (e.g. digest lists, parsers) and
+			usage of DIGLIM for measurement (exec, mmap, open,
+			firmware and module loading).
+
 			The "appraise_tcb" policy appraises the integrity of
 			all files owned by root.
 
@@ -1876,6 +1889,10 @@
 			rule for the tmpfs and ramfs filesystems for the
 			"appraise_tcb" and "appraise_exec_tcb" policies.
 
+			The "appraise_diglim" policy enables appraisal of
+			DIGLIM-related files and usage of DIGLIM for appraisal
+			(exec, mmap, open, firmware and module loading).
+
 			The "secure_boot" policy appraises the integrity
 			of files (eg. kexec kernel image, kernel modules,
 			firmware, policy, etc) based on file signatures.
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index dfab21aeb7e1..5e1532abca5d 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -162,6 +162,10 @@ static struct ima_rule_entry default_measurement_rules[] __ro_after_init = {
 	{.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC},
 };
 
+static struct ima_rule_entry diglim_measure_rule __ro_after_init = {
+	.action = MEASURE, .func = DIGEST_LIST_CHECK, .flags = IMA_FUNC
+};
+
 static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
 	{.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC},
 	{.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC},
@@ -228,6 +232,11 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
 	 .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
 };
 
+static struct ima_rule_entry diglim_appraise_rule __ro_after_init = {
+	.action = APPRAISE, .func = DIGEST_LIST_CHECK,
+	.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED
+};
+
 static struct ima_rule_entry critical_data_rules[] __ro_after_init = {
 	{.action = MEASURE, .func = CRITICAL_DATA, .flags = IMA_FUNC},
 };
@@ -253,9 +262,12 @@ static int __init default_measure_policy_setup(char *str)
 __setup("ima_tcb", default_measure_policy_setup);
 
 static unsigned int ima_measure_skip_flags __initdata;
+static unsigned int ima_measure_diglim __initdata;
 static unsigned int ima_appraise_skip_flags __initdata;
+static unsigned int ima_diglim_pcr __initdata = 11;
 static bool ima_use_appraise_tcb __initdata;
 static bool ima_use_appraise_exec_immutable __initdata;
+static bool ima_use_appraise_diglim __initdata;
 static bool ima_use_secure_boot __initdata;
 static bool ima_use_critical_data __initdata;
 static bool ima_fail_unverifiable_sigs __ro_after_init;
@@ -273,7 +285,9 @@ static int __init policy_setup(char *str)
 		else if ((strcmp(p, "exec_tcb") == 0) && !ima_policy) {
 			ima_policy = DEFAULT_TCB;
 			ima_measure_skip_flags |= IMA_SKIP_OPEN;
-		} else if (strcmp(p, "appraise_tcb") == 0)
+		} else if (strcmp(p, "diglim") == 0)
+			ima_measure_diglim = true;
+		else if (strcmp(p, "appraise_tcb") == 0)
 			ima_use_appraise_tcb = true;
 		else if ((strcmp(p, "appraise_tmpfs") == 0))
 			ima_appraise_skip_flags |= IMA_SKIP_TMPFS;
@@ -282,6 +296,8 @@ static int __init policy_setup(char *str)
 			ima_appraise_skip_flags |= IMA_SKIP_OPEN;
 		} else if (strcmp(p, "appraise_exec_immutable") == 0)
 			ima_use_appraise_exec_immutable = true;
+		else if (strcmp(p, "appraise_diglim") == 0)
+			ima_use_appraise_diglim = true;
 		else if (strcmp(p, "secure_boot") == 0)
 			ima_use_secure_boot = true;
 		else if (strcmp(p, "critical_data") == 0)
@@ -303,6 +319,28 @@ static int __init default_appraise_policy_setup(char *str)
 }
 __setup("ima_appraise_tcb", default_appraise_policy_setup);
 
+static int __init default_diglim_pcr_setup(char *str)
+{
+	unsigned int pcr;
+	int ret;
+
+	ret = kstrtouint(str, 10, &pcr);
+	if (ret < 0 || pcr > 23) {
+		pr_err("Invalid value for ima_diglim_pcr=\n");
+		return 1;
+	}
+
+	/* Using the default IMA PCR is forbidden. */
+	if (ret == CONFIG_IMA_MEASURE_PCR_IDX) {
+		pr_err("Default IMA PCR cannot be used for ima_diglim_pcr=\n");
+		return 1;
+	}
+
+	ima_diglim_pcr = pcr;
+	return 1;
+}
+__setup("ima_diglim_pcr=", default_diglim_pcr_setup);
+
 static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
 {
 	struct ima_rule_opt_list *opt_list;
@@ -812,6 +850,61 @@ void ima_update_policy_flags(void)
 	ima_policy_flag = new_policy_flag;
 }
 
+/*
+ * Add the IMA_USE_DIGLIM_MEASURE and IMA_USE_DIGLIM_APPRAISE flags to the
+ * initial policy depending on the options in the kernel command line, and set
+ * the correct PCR for the measure rules.
+ */
+static void __init ima_add_diglim_flag(void)
+{
+	struct ima_rule_entry *entry;
+
+	if (!IS_ENABLED(CONFIG_DIGLIM))
+		return;
+
+	if (!ima_measure_diglim && !ima_use_appraise_diglim)
+		return;
+
+	list_for_each_entry(entry, ima_rules, list) {
+		if (entry->action != IMA_MEASURE &&
+		    entry->action != IMA_APPRAISE)
+			continue;
+
+		if (entry->action == IMA_MEASURE && !ima_measure_diglim)
+			continue;
+
+		if (entry->action == IMA_APPRAISE &&
+		    !ima_use_appraise_diglim)
+			continue;
+
+		switch (entry->func) {
+		case BPRM_CHECK:
+			fallthrough;
+		case CREDS_CHECK:
+			fallthrough;
+		case MMAP_CHECK:
+			fallthrough;
+		case FILE_CHECK:
+			fallthrough;
+		case MODULE_CHECK:
+			fallthrough;
+		case FIRMWARE_CHECK:
+			fallthrough;
+		case DIGEST_LIST_CHECK:
+			if (entry->action == IMA_MEASURE) {
+				entry->flags |= IMA_USE_DIGLIM_MEASURE;
+				entry->flags |= IMA_PCR;
+				entry->pcr = ima_diglim_pcr;
+			} else {
+				entry->flags |= IMA_USE_DIGLIM_APPRAISE;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+}
+
 static int ima_appraise_flag(enum ima_hooks func)
 {
 	if (func == MODULE_CHECK)
@@ -989,7 +1082,14 @@ void __init ima_init_policy(void)
 
 	atomic_set(&ima_setxattr_allowed_hash_algorithms, 0);
 
+	if (ima_measure_diglim)
+		add_rules(&diglim_measure_rule, 1, IMA_DEFAULT_POLICY, 0);
+
+	if (ima_use_appraise_diglim)
+		add_rules(&diglim_appraise_rule, 1, IMA_DEFAULT_POLICY, 0);
+
 	ima_update_policy_flags();
+	ima_add_diglim_flag();
 }
 
 /* Make sure we have a valid policy, at least containing some rules. */
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC][PATCH 4/7] ima: Query file digest and retrieve info from its digest lists
  2021-09-30 11:55 [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM Roberto Sassu
                   ` (2 preceding siblings ...)
  2021-09-30 11:55 ` [RFC][PATCH 3/7] ima: Introduce diglim and appraise_diglim policies Roberto Sassu
@ 2021-09-30 11:55 ` Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 5/7] ima: Query metadata " Roberto Sassu
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Roberto Sassu @ 2021-09-30 11:55 UTC (permalink / raw)
  To: zohar, gregkh, mchehab+huawei
  Cc: linux-integrity, linux-security-module, linux-kernel, Roberto Sassu

If a file is going to be measured or appraised, and the use_diglim keyword
has been added to the matching rule, query the calculated file digest with
DIGLIM and retrieve some information: the actions (logical OR) done on the
digest lists containing that digest; modifiers (logical OR) associated to
the type.

Retrieved actions and modifiers will be then processed by the corresponding
IMA submodules.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 security/integrity/ima/ima.h      |  1 +
 security/integrity/ima/ima_main.c | 21 +++++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index cde2e1c2a6be..550805b79984 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -21,6 +21,7 @@
 #include <linux/tpm.h>
 #include <linux/audit.h>
 #include <crypto/hash_info.h>
+#include <linux/diglim.h>
 
 #include "../integrity.h"
 
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index fe1f4ef1bb9d..b32c4f8d19ea 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -198,6 +198,20 @@ void ima_file_free(struct file *file)
 	ima_check_last_writer(iint, inode, file);
 }
 
+static void diglim_file_digest_lookup(struct file *file,
+				      struct integrity_iint_cache *iint,
+				      int action, u16 *modifiers, u8 *actions)
+{
+	if ((file->f_mode & FMODE_CREATED) && !i_size_read(file_inode(file)))
+		return;
+
+	if (!(iint->flags & IMA_COLLECTED))
+		return;
+
+	diglim_digest_get_info(iint->ima_hash->digest, iint->ima_hash->algo,
+			       COMPACT_FILE, modifiers, actions);
+}
+
 static int process_measurement(struct file *file, const struct cred *cred,
 			       u32 secid, char *buf, loff_t size, int mask,
 			       enum ima_hooks func)
@@ -209,6 +223,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
 	char filename[NAME_MAX];
 	const char *pathname = NULL;
 	u64 action;
+	u16 file_modifiers = 0;
+	u8 file_actions = 0;
 	int rc = 0, must_appraise = 0;
 	int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
 	struct evm_ima_xattr_data *xattr_value = NULL;
@@ -344,6 +360,11 @@ 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);
 
+	if (iint->flags & IMA_USE_DIGLIM_MEASURE ||
+	    iint->flags & IMA_USE_DIGLIM_APPRAISE)
+		diglim_file_digest_lookup(file, iint, action, &file_modifiers,
+					  &file_actions);
+
 	if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
 		rc = ima_check_blacklist(iint, modsig, pcr);
 		if (rc != -EPERM) {
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC][PATCH 5/7] ima: Query metadata digest and retrieve info from its digest lists
  2021-09-30 11:55 [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM Roberto Sassu
                   ` (3 preceding siblings ...)
  2021-09-30 11:55 ` [RFC][PATCH 4/7] ima: Query file digest and retrieve info from its digest lists Roberto Sassu
@ 2021-09-30 11:55 ` Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 6/7] ima: Skip measurement of files found in DIGLIM hash table Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 7/7] ima: Add support for appraisal with digest lists Roberto Sassu
  6 siblings, 0 replies; 8+ messages in thread
From: Roberto Sassu @ 2021-09-30 11:55 UTC (permalink / raw)
  To: zohar, gregkh, mchehab+huawei
  Cc: linux-integrity, linux-security-module, linux-kernel, Roberto Sassu

First, introduce the new function evm_get_hash() to obtain the EVM digest
of file metadata. The EVM digest is calculated depending on the passed
security.evm type.

Then, introduce the new function diglim_metadata_digest_lookup(), to search
the metadata digest obtained from evm_get_hash() with type
EVM_XATTR_PORTABLE_DIGSIG in the DIGLIM hash table and to obtain the
actions and modifiers (logical OR) associated to the EVM digest, taken from
the digest lists that contain that digest.

Retrieved actions and modifiers will be then processed by the corresponding
IMA submodules.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 include/linux/evm.h               | 14 +++++++++
 security/integrity/evm/evm_main.c | 40 ++++++++++++++++++++++++
 security/integrity/ima/ima_main.c | 51 +++++++++++++++++++++++++++++--
 3 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/include/linux/evm.h b/include/linux/evm.h
index 4c374be70247..92856a7dbcab 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -11,6 +11,7 @@
 
 #include <linux/integrity.h>
 #include <linux/xattr.h>
+#include <crypto/hash_info.h>
 
 struct integrity_iint_cache;
 
@@ -42,6 +43,10 @@ extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
 extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
 				     int buffer_size, char type,
 				     bool canonical_fmt);
+extern int evm_get_hash(struct dentry *dentry, const char *req_xattr_name,
+			const char *req_xattr_value, size_t req_xattr_value_len,
+			char type, enum hash_algo algo, u8 *digest,
+			size_t digest_len);
 #ifdef CONFIG_FS_POSIX_ACL
 extern int posix_xattr_acl(const char *xattrname);
 #else
@@ -129,6 +134,15 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
 {
 	return -EOPNOTSUPP;
 }
+static inline int evm_get_hash(struct dentry *dentry,
+			       const char *req_xattr_name,
+			       const char *req_xattr_value,
+			       size_t req_xattr_value_len, char type,
+			       enum hash_algo algo, u8 *digest,
+			       size_t digest_len)
+{
+	return -EOPNOTSUPP;
+}
 
 #endif /* CONFIG_EVM */
 #endif /* LINUX_EVM_H */
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index a8d7c761853e..3d45873f9266 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -429,6 +429,46 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
 }
 EXPORT_SYMBOL_GPL(evm_verifyxattr);
 
+/**
+ * evm_get_hash - obtain the EVM digest calculated according to the passed type
+ * @dentry: object the EVM digest is calculated from
+ * @req_xattr_name: requested xattr
+ * @req_xattr_value: requested xattr value
+ * @req_xattr_value_len: requested xattr value length
+ * @type: requested security.evm type
+ * @algo: requested EVM digest algorithm
+ * @digest: the buffer the EVM digest is written to
+ * @digest_len: size of the buffer
+ *
+ * Calculate the EVM digest from metadata according to the passed security.evm
+ * type.
+ *
+ * Returns 0 if the digest has been calculated successfully, a negative value
+ * otherwise.
+ *
+ * This function requires the caller to lock the inode's i_mutex before it
+ * is executed.
+ */
+int evm_get_hash(struct dentry *dentry, const char *req_xattr_name,
+		 const char *req_xattr_value, size_t req_xattr_value_len,
+		 char type, enum hash_algo algo, u8 *digest, size_t digest_len)
+{
+	struct evm_digest evm_digest;
+	int rc;
+
+	if (digest_len < hash_digest_size[algo])
+		return -EINVAL;
+
+	evm_digest.hdr.algo = algo;
+	rc = evm_calc_hash(dentry, req_xattr_name, req_xattr_value,
+			   req_xattr_value_len, type, &evm_digest);
+	if (rc < 0)
+		return rc;
+
+	memcpy(digest, evm_digest.digest, hash_digest_size[algo]);
+	return 0;
+}
+
 /*
  * evm_verify_current_integrity - verify the dentry's metadata integrity
  * @dentry: pointer to the affected dentry
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index b32c4f8d19ea..84ccb76f6c3c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/xattr.h>
 #include <linux/ima.h>
+#include <linux/evm.h>
 #include <linux/iversion.h>
 #include <linux/fs.h>
 
@@ -212,6 +213,44 @@ static void diglim_file_digest_lookup(struct file *file,
 			       COMPACT_FILE, modifiers, actions);
 }
 
+static void diglim_metadata_digest_lookup(struct file *file,
+					struct integrity_iint_cache *iint,
+					int action,
+					struct evm_ima_xattr_data *xattr_value,
+					int xattr_len, u16 *modifiers,
+					u8 *actions)
+{
+	u8 digest[IMA_MAX_DIGEST_SIZE];
+	struct evm_xattr fake_ima_xattr;
+	struct evm_ima_xattr_data *ima_xattr = xattr_value;
+	int rc;
+
+	if ((file->f_mode & FMODE_CREATED) && !i_size_read(file_inode(file)))
+		return;
+
+	if (!(iint->flags & IMA_COLLECTED))
+		return;
+
+	if (!xattr_value) {
+		fake_ima_xattr.data.type = IMA_XATTR_DIGEST_NG;
+		fake_ima_xattr.data.data[0] = iint->ima_hash->algo;
+		memcpy(&fake_ima_xattr.data.data[1], iint->ima_hash->digest,
+		       hash_digest_size[iint->ima_hash->algo]);
+		ima_xattr = &fake_ima_xattr.data;
+		xattr_len = 2 + hash_digest_size[iint->ima_hash->algo];
+	}
+
+	rc = evm_get_hash(file_dentry(file), XATTR_NAME_IMA,
+			  (const char *)ima_xattr, xattr_len,
+			  EVM_XATTR_PORTABLE_DIGSIG, iint->ima_hash->algo,
+			  digest, sizeof(digest));
+	if (rc < 0)
+		return;
+
+	diglim_digest_get_info(digest, iint->ima_hash->algo, COMPACT_METADATA,
+			       modifiers, actions);
+}
+
 static int process_measurement(struct file *file, const struct cred *cred,
 			       u32 secid, char *buf, loff_t size, int mask,
 			       enum ima_hooks func)
@@ -223,8 +262,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
 	char filename[NAME_MAX];
 	const char *pathname = NULL;
 	u64 action;
-	u16 file_modifiers = 0;
-	u8 file_actions = 0;
+	u16 file_modifiers = 0, metadata_modifiers = 0;
+	u8 file_actions = 0, metadata_actions = 0;
 	int rc = 0, must_appraise = 0;
 	int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
 	struct evm_ima_xattr_data *xattr_value = NULL;
@@ -361,9 +400,15 @@ static int process_measurement(struct file *file, const struct cred *cred,
 		pathname = ima_d_path(&file->f_path, &pathbuf, filename);
 
 	if (iint->flags & IMA_USE_DIGLIM_MEASURE ||
-	    iint->flags & IMA_USE_DIGLIM_APPRAISE)
+	    iint->flags & IMA_USE_DIGLIM_APPRAISE) {
 		diglim_file_digest_lookup(file, iint, action, &file_modifiers,
 					  &file_actions);
+		inode_lock(inode);
+		diglim_metadata_digest_lookup(file, iint, action, xattr_value,
+					      xattr_len, &metadata_modifiers,
+					      &metadata_actions);
+		inode_unlock(inode);
+	}
 
 	if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
 		rc = ima_check_blacklist(iint, modsig, pcr);
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC][PATCH 6/7] ima: Skip measurement of files found in DIGLIM hash table
  2021-09-30 11:55 [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM Roberto Sassu
                   ` (4 preceding siblings ...)
  2021-09-30 11:55 ` [RFC][PATCH 5/7] ima: Query metadata " Roberto Sassu
@ 2021-09-30 11:55 ` Roberto Sassu
  2021-09-30 11:55 ` [RFC][PATCH 7/7] ima: Add support for appraisal with digest lists Roberto Sassu
  6 siblings, 0 replies; 8+ messages in thread
From: Roberto Sassu @ 2021-09-30 11:55 UTC (permalink / raw)
  To: zohar, gregkh, mchehab+huawei
  Cc: linux-integrity, linux-security-module, linux-kernel, Roberto Sassu

Skip a file measurement if the IMA policy allows the usage of DIGLIM with
the use_diglim directive, if the content or metadata digests were found in
the DIGLIM hash table and if at least one of the digest lists containing
the found digest has the action COMPACT_ACTION_IMA_MEASURED set.

Since the usage of the use_diglim directive requires to specify a different
PCR than the default one, this avoids confusion with the standard IMA
measurement list where if a file is missing it means that it was not
accessed.

The new meaning of measurements done with the use_diglim directive is that
if a file is missing, it was not accessed or it was accessed, was found in
the DIGLIM hash table, and the measurement of at least one digest list
containing its content or metadata digest is in the measurement list.

Files not found in the DIGLIM hash table or files whose content or metadata
digest was not measured will still appear in the measurement list.

Given that with the new behavior it cannot be determined whether a file was
accessed or not, remote verifiers must assume the worst case where every
file, whose content or metadata digest is in a measured digest list, was
accessed. With this assumption, it is safe to assume the measurement list
generated with the new behavior as complete.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 security/integrity/ima/ima_main.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 84ccb76f6c3c..7add0e70f67a 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -442,6 +442,15 @@ static int process_measurement(struct file *file, const struct cred *cred,
 	if (must_appraise)
 		if (rc && (ima_appraise & IMA_APPRAISE_ENFORCE))
 			action &= ~(IMA_MEASURE | IMA_AUDIT);
+	/* Use DIGLIM method for measurement if enabled in the policy. */
+	if (action & IMA_MEASURE && (iint->flags & IMA_USE_DIGLIM_MEASURE)) {
+		if (file_actions & (1 << COMPACT_ACTION_IMA_MEASURED) ||
+		    metadata_actions & (1 << COMPACT_ACTION_IMA_MEASURED)) {
+			iint->flags |= IMA_MEASURED;
+			iint->measured_pcrs |= (0x1 << pcr);
+			action &= ~IMA_MEASURE;
+		}
+	}
 	if (action & IMA_MEASURE)
 		ima_store_measurement(iint, file, pathname,
 				      xattr_value, xattr_len, modsig, pcr,
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC][PATCH 7/7] ima: Add support for appraisal with digest lists
  2021-09-30 11:55 [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM Roberto Sassu
                   ` (5 preceding siblings ...)
  2021-09-30 11:55 ` [RFC][PATCH 6/7] ima: Skip measurement of files found in DIGLIM hash table Roberto Sassu
@ 2021-09-30 11:55 ` Roberto Sassu
  6 siblings, 0 replies; 8+ messages in thread
From: Roberto Sassu @ 2021-09-30 11:55 UTC (permalink / raw)
  To: zohar, gregkh, mchehab+huawei
  Cc: linux-integrity, linux-security-module, linux-kernel, Roberto Sassu

Introduce a new appraisal method based on the lookup of the file and
metadata digest in the DIGLIM hash table, enabled with the use_diglim
directive.

First pass to ima_appraise_measurement() the actions performed on the
digest lists containing the found digests.

Then, consider the metadata verification as successful if EVM returned the
status INTEGRITY_NOLABEL (no security.evm), if the metadata digest was
found in the DIGLIM hash table and at least one digest list containing it
was succefully appraised with a signature.

Finally, consider the file content verification as successful if there is
no security.ima or appended signature, if the file or metadata digest
(calculated with the actual file digest) were found in the DIGLIM hash
table and at least one digest list containing it has a valid signature.

Furthermore, mark the file as immutable if the COMPACT_MOD_IMMUTABLE
modifier was set in the header of the digest lists containing the found
digests.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 security/integrity/ima/ima.h          |  4 ++-
 security/integrity/ima/ima_appraise.c | 37 +++++++++++++++++++++++----
 security/integrity/ima/ima_main.c     |  6 ++++-
 3 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 550805b79984..631e9e4c343b 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -319,7 +319,9 @@ int ima_appraise_measurement(enum ima_hooks func,
 			     struct integrity_iint_cache *iint,
 			     struct file *file, const unsigned char *filename,
 			     struct evm_ima_xattr_data *xattr_value,
-			     int xattr_len, const struct modsig *modsig);
+			     int xattr_len, const struct modsig *modsig,
+			     u16 file_modifiers, u8 file_actions,
+			     u16 metadata_modifiers, u8 metadata_actions);
 int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
 		      int mask, enum ima_hooks func);
 void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index e1b9a5bc4252..a0885272411e 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -377,7 +377,9 @@ int ima_appraise_measurement(enum ima_hooks func,
 			     struct integrity_iint_cache *iint,
 			     struct file *file, const unsigned char *filename,
 			     struct evm_ima_xattr_data *xattr_value,
-			     int xattr_len, const struct modsig *modsig)
+			     int xattr_len, const struct modsig *modsig,
+			     u16 file_modifiers, u8 file_actions,
+			     u16 metadata_modifiers, u8 metadata_actions)
 {
 	static const char op[] = "appraise_data";
 	const char *cause = "unknown";
@@ -387,12 +389,26 @@ int ima_appraise_measurement(enum ima_hooks func,
 	int rc = xattr_len;
 	bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;
 
-	/* If not appraising a modsig, we need an xattr. */
-	if (!(inode->i_opflags & IOP_XATTR) && !try_modsig)
+	/* We are interested only in appraisal-related flags. */
+	file_actions &= COMPACT_ACTION_IMA_APPRAISED_DIGSIG;
+	metadata_actions &= COMPACT_ACTION_IMA_APPRAISED_DIGSIG;
+
+	/* Disable DIGLIM method for appraisal if not enabled in the policy. */
+	if (!(iint->flags & IMA_USE_DIGLIM_APPRAISE)) {
+		file_actions = 0;
+		metadata_actions = 0;
+	}
+
+	/* If not appraising a modsig or using DIGLIM, we need an xattr. */
+	if (!(inode->i_opflags & IOP_XATTR) && !try_modsig &&
+	    !file_actions && !metadata_actions)
 		return INTEGRITY_UNKNOWN;
 
-	/* If reading the xattr failed and there's no modsig, error out. */
-	if (rc <= 0 && !try_modsig) {
+	/*
+	 * If reading the xattr failed, there's no modsig and the DIGLIM
+	 * appraisal method is not available, error out.
+	 */
+	if (rc <= 0 && !try_modsig && !file_actions && !metadata_actions) {
 		if (rc && rc != -ENODATA)
 			goto out;
 
@@ -420,6 +436,10 @@ int ima_appraise_measurement(enum ima_hooks func,
 			break;
 		fallthrough;
 	case INTEGRITY_NOLABEL:		/* No security.evm xattr. */
+		if (metadata_actions) {
+			status = INTEGRITY_PASS_IMMUTABLE;
+			break;
+		}
 		cause = "missing-HMAC";
 		goto out;
 	case INTEGRITY_FAIL_IMMUTABLE:
@@ -455,6 +475,13 @@ int ima_appraise_measurement(enum ima_hooks func,
 	     rc == -ENOKEY))
 		rc = modsig_verify(func, modsig, &status, &cause);
 
+	if (!xattr_value && !try_modsig && (file_actions || metadata_actions)) {
+		status = INTEGRITY_PASS;
+
+		if ((file_modifiers & (1 << COMPACT_MOD_IMMUTABLE)) ||
+		    (metadata_modifiers & (1 << COMPACT_MOD_IMMUTABLE)))
+			set_bit(IMA_DIGSIG, &iint->atomic_flags);
+	}
 out:
 	/*
 	 * File signatures on some filesystems can not be properly verified.
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 7add0e70f67a..7a9a2392d49c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -416,7 +416,11 @@ static int process_measurement(struct file *file, const struct cred *cred,
 			inode_lock(inode);
 			rc = ima_appraise_measurement(func, iint, file,
 						      pathname, xattr_value,
-						      xattr_len, modsig);
+						      xattr_len, modsig,
+						      file_modifiers,
+						      file_actions,
+						      metadata_modifiers,
+						      metadata_actions);
 			inode_unlock(inode);
 		}
 		if (!rc)
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-09-30 11:57 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-30 11:55 [RFC][PATCH 0/7] ima: Measure and appraise files with DIGLIM Roberto Sassu
2021-09-30 11:55 ` [RFC][PATCH 1/7] integrity: Change type of IMA rule-related flags to u64 Roberto Sassu
2021-09-30 11:55 ` [RFC][PATCH 2/7] ima: Introduce new policy keyword use_diglim Roberto Sassu
2021-09-30 11:55 ` [RFC][PATCH 3/7] ima: Introduce diglim and appraise_diglim policies Roberto Sassu
2021-09-30 11:55 ` [RFC][PATCH 4/7] ima: Query file digest and retrieve info from its digest lists Roberto Sassu
2021-09-30 11:55 ` [RFC][PATCH 5/7] ima: Query metadata " Roberto Sassu
2021-09-30 11:55 ` [RFC][PATCH 6/7] ima: Skip measurement of files found in DIGLIM hash table Roberto Sassu
2021-09-30 11:55 ` [RFC][PATCH 7/7] ima: Add support for appraisal with digest lists Roberto Sassu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).