* [PATCH v4 0/8] ima: support fs-verity digests and signatures
@ 2022-02-08 1:41 Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS Mimi Zohar
` (8 more replies)
0 siblings, 9 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
Support for including fs-verity file digests and signatures in the IMA
measurement list as well as verifying the fs-verity file digest based
signatures, both based on IMA policy rules, was discussed prior to
fs-verity being upstreamed[1,2].
Support for including fs-verity file digests in the 'd-ng' template field
is based on a new policy rule option named 'digest_type=verity'. A new
template field named 'd-type' as well as a new template named 'ima-ngv2'
are defined to differentiate between the regular IMA file hashes from the
fs-verity file digests (tree-hash based file hashes) stored in the 'd-ng'
template field.
Support for verifying fs-verity based file signatures stored in the
'security.ima' xattr is similarly based on the policy rule option
'digest_type=verity'.
To differentiate IMA from fs-verity file signatures a new xattr_type
named IMA_VERITY_DIGSIG is defined. Signature version 3, which is a hash
of the ima_file_id struct, disambiguates the signatures stored as
'security.ima' xattr. fs-verity only supports the new signature format
(version 3). To prevent abuse of the different signature formats, policy
rules must be limited to a specific signature version.
[1] https://events19.linuxfoundation.org/wp-content/uploads/2017/11/fs-verify_Mike-Halcrow_Eric-Biggers.pdf
[2] Documentation/filesystems/fsverity.rst
Changelog v4:
- Based on Eric Bigger's signature verification concerns of replacing the
contents of a file with the ima_file_id struct hash, require per policy
rule signature versions.
- Addressed Eric Bigger's other comments.
- Added new audit messages "causes".
- Updated patch descriptions.
Changelog v3:
- Addressed Eric Bigger's comments: included Ack, incremented the
signature format version, the crypto issues are generic and will be
addressed by him separately.
- Addressed Vitaly Chikunov's comments: hard coded maximum digest size
rather than using a flexible array, removed unnecessary assignment, and
fixed comment to match variable name.
- Defined new "ima_max_digest_size" struct to avoid wrapping the
"ima_digest_data" struct inside a function local structure or
having to dynamically allocate it with enough memory for the specific
hash algo size.
Changelog v2:
- Addressed Eric Bigger's comments: sign the hash of fsverity's digest
and the digest's metadata, use match_string, use preferred function
name fsverity_get_digest(), support including unsigned fs-verity's
digests in the IMA measurement list.
- Remove signatures requirement for including fs-verity's file digests in
the 'd-ng' field of the measurement list.
Changelog v1:
- Updated both fsverity and IMA documentation.
- Addressed both Eric Bigger's and Lakshmi's comments.
Mimi Zohar (8):
ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS
ima: define ima_max_digest_data struct without a flexible array
variable
fs-verity: define a function to return the integrity protected file
digest
ima: define a new template field 'd-type' and a new template
'ima-ngv2'
ima: permit fsverity's file digests in the IMA measurement list
ima: define signature version 3
ima: support fs-verity file digest based version 3 signatures
fsverity: update the documentation
Documentation/ABI/testing/ima_policy | 22 +++++
Documentation/filesystems/fsverity.rst | 22 +++--
Documentation/security/IMA-templates.rst | 11 ++-
fs/verity/Kconfig | 1 +
fs/verity/fsverity_private.h | 7 --
fs/verity/measure.c | 41 ++++++++
include/linux/fsverity.h | 18 ++++
security/integrity/digsig.c | 3 +-
security/integrity/ima/ima_api.c | 59 ++++++++---
security/integrity/ima/ima_appraise.c | 113 +++++++++++++++++++++-
security/integrity/ima/ima_init.c | 10 +-
security/integrity/ima/ima_main.c | 2 +-
security/integrity/ima/ima_policy.c | 45 ++++++++-
security/integrity/ima/ima_template.c | 3 +
security/integrity/ima/ima_template_lib.c | 23 ++++-
security/integrity/ima/ima_template_lib.h | 2 +
security/integrity/integrity.h | 53 +++++++++-
17 files changed, 385 insertions(+), 50 deletions(-)
--
2.27.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v4 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
@ 2022-02-08 1:41 ` Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 2/8] ima: define ima_max_digest_data struct without a flexible array variable Mimi Zohar
` (7 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
Simple policy rule options, such as fowner, uid, or euid, can be checked
immediately, while other policy rule options, such as requiring a file
signature, need to be deferred.
The 'flags' field in the integrity_iint_cache struct contains the policy
action', 'subaction', and non action/subaction.
action: measure/measured, appraise/appraised, (collect)/collected,
audit/audited
subaction: appraise status for each hook (e.g. file, mmap, bprm, read,
creds)
non action/subaction: deferred policy rule options and state
Rename the IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS.
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/ima/ima_main.c | 2 +-
security/integrity/ima/ima_policy.c | 2 +-
security/integrity/integrity.h | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 8ed6da428328..7c80dfe2c7a5 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -263,7 +263,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
/* reset appraisal flags if ima_inode_post_setattr was called */
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
- IMA_ACTION_FLAGS);
+ IMA_NONACTION_FLAGS);
/*
* Re-evaulate the file if either the xattr has changed or the
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 90f528558adc..a0f3775cbd82 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -712,7 +712,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
func, mask, func_data))
continue;
- action |= entry->flags & IMA_ACTION_FLAGS;
+ action |= entry->flags & IMA_NONACTION_FLAGS;
action |= entry->action & IMA_DO_MASK;
if (entry->action & IMA_APPRAISE) {
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 547425c20e11..d045dccd415a 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -30,8 +30,8 @@
#define IMA_HASH 0x00000100
#define IMA_HASHED 0x00000200
-/* iint cache flags */
-#define IMA_ACTION_FLAGS 0xff000000
+/* iint policy rule cache flags */
+#define IMA_NONACTION_FLAGS 0xff000000
#define IMA_DIGSIG_REQUIRED 0x01000000
#define IMA_PERMIT_DIRECTIO 0x02000000
#define IMA_NEW_FILE 0x04000000
--
2.27.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 2/8] ima: define ima_max_digest_data struct without a flexible array variable
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS Mimi Zohar
@ 2022-02-08 1:41 ` Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 3/8] fs-verity: define a function to return the integrity protected file digest Mimi Zohar
` (6 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
To support larger hash digests in the 'iint' cache, instead of defining
the 'digest' field as the maximum digest size, the 'digest' field was
defined as a flexible array variable and was dynamically allocated.
This resulted in wrapping the "ima_digest_data" struct inside a local
structure with the maximum digest size in a number of places.
The original reason for defining the 'digest' field as a flexible array
variable is still valid for the 'iint' cache use case. In addition,
define 'ima_max_digest_data' struct to be use instead of the (ugly)
local wrapping of the "ima_digest_data" struct.
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/ima/ima_api.c | 20 ++++++++++----------
security/integrity/ima/ima_init.c | 10 ++++------
security/integrity/integrity.h | 24 ++++++++++++++++++++++++
3 files changed, 38 insertions(+), 16 deletions(-)
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 5b220a2fe573..45294f18dabc 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -217,14 +217,11 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
const char *audit_cause = "failed";
struct inode *inode = file_inode(file);
const char *filename = file->f_path.dentry->d_name.name;
+ struct ima_max_digest_data hash;
int result = 0;
int length;
void *tmpbuf;
u64 i_version;
- struct {
- struct ima_digest_data hdr;
- char digest[IMA_MAX_DIGEST_SIZE];
- } hash;
/*
* Always collect the modsig, because IMA might have already collected
@@ -239,24 +236,27 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
/*
* Detecting file change is based on i_version. On filesystems
- * which do not support i_version, support is limited to an initial
- * measurement/appraisal/audit.
+ * which do not support i_version, support was originally limited
+ * to an initial measurement/appraisal/audit, but was modified to
+ * assume the file changed.
*/
i_version = inode_query_iversion(inode);
- hash.hdr.algo = algo;
+ hash.algo = algo;
/* Initialize hash digest to 0's in case of failure */
memset(&hash.digest, 0, sizeof(hash.digest));
if (buf)
- result = ima_calc_buffer_hash(buf, size, &hash.hdr);
+ result = ima_calc_buffer_hash(buf, size,
+ (struct ima_digest_data *)&hash);
else
- result = ima_calc_file_hash(file, &hash.hdr);
+ result = ima_calc_file_hash(file,
+ (struct ima_digest_data *)&hash);
if (result && result != -EBADF && result != -EINVAL)
goto out;
- length = sizeof(hash.hdr) + hash.hdr.length;
+ length = sizeof(struct ima_digest_data) + hash.length;
tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
if (!tmpbuf) {
result = -ENOMEM;
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index b26fa67476b4..890821af08dd 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -47,16 +47,13 @@ static int __init ima_add_boot_aggregate(void)
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
struct ima_event_data event_data = { .iint = iint,
.filename = boot_aggregate_name };
+ struct ima_max_digest_data hash;
int result = -ENOMEM;
int violation = 0;
- struct {
- struct ima_digest_data hdr;
- char digest[TPM_MAX_DIGEST_SIZE];
- } hash;
memset(iint, 0, sizeof(*iint));
memset(&hash, 0, sizeof(hash));
- iint->ima_hash = &hash.hdr;
+ iint->ima_hash = (struct ima_digest_data *)&hash;
iint->ima_hash->algo = ima_hash_algo;
iint->ima_hash->length = hash_digest_size[ima_hash_algo];
@@ -73,7 +70,8 @@ static int __init ima_add_boot_aggregate(void)
* is not found.
*/
if (ima_tpm_chip) {
- result = ima_calc_boot_aggregate(&hash.hdr);
+ result = ima_calc_boot_aggregate((struct ima_digest_data *)
+ &hash);
if (result < 0) {
audit_cause = "hashing_error";
goto err_out;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index d045dccd415a..ee2e6b7c7575 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/integrity.h>
#include <crypto/sha1.h>
+#include <crypto/hash.h>
#include <linux/key.h>
#include <linux/audit.h>
@@ -110,6 +111,29 @@ struct ima_digest_data {
u8 digest[];
} __packed;
+/*
+ * Instead of dynamically allocating memory for the ima_digest_data struct
+ * with space for the specific hash algo or wrapping the ima_digest_data
+ * struct inside another local structure, define ima_max_digest_data struct
+ * with the maximum digest size.
+ */
+struct ima_max_digest_data {
+ u8 algo;
+ u8 length;
+ union {
+ struct {
+ u8 unused;
+ u8 type;
+ } sha1;
+ struct {
+ u8 type;
+ u8 algo;
+ } ng;
+ u8 data[2];
+ } xattr;
+ u8 digest[HASH_MAX_DIGESTSIZE];
+} __packed;
+
/*
* signature format v2 - for using with asymmetric keys
*/
--
2.27.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 3/8] fs-verity: define a function to return the integrity protected file digest
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 2/8] ima: define ima_max_digest_data struct without a flexible array variable Mimi Zohar
@ 2022-02-08 1:41 ` Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 4/8] ima: define a new template field 'd-type' and a new template 'ima-ngv2' Mimi Zohar
` (5 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt,
linux-kernel, Eric Biggers
Define a function named fsverity_get_digest() to return the verity file
digest and the associated hash algorithm (enum hash_algo).
Acked-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
fs/verity/Kconfig | 1 +
fs/verity/fsverity_private.h | 7 ------
fs/verity/measure.c | 41 ++++++++++++++++++++++++++++++++++++
include/linux/fsverity.h | 18 ++++++++++++++++
4 files changed, 60 insertions(+), 7 deletions(-)
diff --git a/fs/verity/Kconfig b/fs/verity/Kconfig
index 24d1b54de807..54598cd80145 100644
--- a/fs/verity/Kconfig
+++ b/fs/verity/Kconfig
@@ -3,6 +3,7 @@
config FS_VERITY
bool "FS Verity (read-only file-based authenticity protection)"
select CRYPTO
+ select CRYPTO_HASH_INFO
# SHA-256 is implied as it's intended to be the default hash algorithm.
# To avoid bloat, other wanted algorithms must be selected explicitly.
# Note that CRYPTO_SHA256 denotes the generic C implementation, but
diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
index a7920434bae5..c6fb62e0ef1a 100644
--- a/fs/verity/fsverity_private.h
+++ b/fs/verity/fsverity_private.h
@@ -14,7 +14,6 @@
#define pr_fmt(fmt) "fs-verity: " fmt
-#include <crypto/sha2.h>
#include <linux/fsverity.h>
#include <linux/mempool.h>
@@ -26,12 +25,6 @@ struct ahash_request;
*/
#define FS_VERITY_MAX_LEVELS 8
-/*
- * Largest digest size among all hash algorithms supported by fs-verity.
- * Currently assumed to be <= size of fsverity_descriptor::root_hash.
- */
-#define FS_VERITY_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
-
/* A hash algorithm supported by fs-verity */
struct fsverity_hash_alg {
struct crypto_ahash *tfm; /* hash tfm, allocated on demand */
diff --git a/fs/verity/measure.c b/fs/verity/measure.c
index f0d7b30c62db..f832aaa41326 100644
--- a/fs/verity/measure.c
+++ b/fs/verity/measure.c
@@ -57,3 +57,44 @@ int fsverity_ioctl_measure(struct file *filp, void __user *_uarg)
return 0;
}
EXPORT_SYMBOL_GPL(fsverity_ioctl_measure);
+
+/**
+ * fsverity_get_digest() - get a verity file's digest
+ * @inode: inode to get digest of
+ * @digest: (out) pointer to the digest
+ * @alg: (out) pointer to the hash algorithm enumeration
+ *
+ * Return the file hash algorithm and digest of an fsverity protected file.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+int fsverity_get_digest(struct inode *inode,
+ u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
+ enum hash_algo *alg)
+{
+ const struct fsverity_info *vi;
+ const struct fsverity_hash_alg *hash_alg;
+ int i;
+
+ vi = fsverity_get_info(inode);
+ if (!vi)
+ return -ENODATA; /* not a verity file */
+
+ hash_alg = vi->tree_params.hash_alg;
+ memset(digest, 0, FS_VERITY_MAX_DIGEST_SIZE);
+
+ /* convert the verity hash algorithm name to a hash_algo_name enum */
+ i = match_string(hash_algo_name, HASH_ALGO__LAST, hash_alg->name);
+ if (i < 0)
+ return -EINVAL;
+ *alg = i;
+
+ if (WARN_ON_ONCE(hash_alg->digest_size != hash_digest_size[*alg]))
+ return -EINVAL;
+ memcpy(digest, vi->file_digest, hash_alg->digest_size);
+
+ pr_debug("file digest %s:%*phN\n", hash_algo_name[*alg],
+ hash_digest_size[*alg], digest);
+
+ return 0;
+}
diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h
index b568b3c7d095..9a1b70cc7318 100644
--- a/include/linux/fsverity.h
+++ b/include/linux/fsverity.h
@@ -12,8 +12,16 @@
#define _LINUX_FSVERITY_H
#include <linux/fs.h>
+#include <crypto/hash_info.h>
+#include <crypto/sha2.h>
#include <uapi/linux/fsverity.h>
+/*
+ * Largest digest size among all hash algorithms supported by fs-verity.
+ * Currently assumed to be <= size of fsverity_descriptor::root_hash.
+ */
+#define FS_VERITY_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
+
/* Verity operations for filesystems */
struct fsverity_operations {
@@ -131,6 +139,9 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *arg);
/* measure.c */
int fsverity_ioctl_measure(struct file *filp, void __user *arg);
+int fsverity_get_digest(struct inode *inode,
+ u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
+ enum hash_algo *alg);
/* open.c */
@@ -170,6 +181,13 @@ static inline int fsverity_ioctl_measure(struct file *filp, void __user *arg)
return -EOPNOTSUPP;
}
+static inline int fsverity_get_digest(struct inode *inode,
+ u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
+ enum hash_algo *alg)
+{
+ return -EOPNOTSUPP;
+}
+
/* open.c */
static inline int fsverity_file_open(struct inode *inode, struct file *filp)
--
2.27.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 4/8] ima: define a new template field 'd-type' and a new template 'ima-ngv2'
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
` (2 preceding siblings ...)
2022-02-08 1:41 ` [PATCH v4 3/8] fs-verity: define a function to return the integrity protected file digest Mimi Zohar
@ 2022-02-08 1:41 ` Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 5/8] ima: permit fsverity's file digests in the IMA measurement list Mimi Zohar
` (4 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
In preparation to differentiate between regular IMA file hashes and
fs-verity's file digests, define a new template field named 'd-type'.
Define a new template named 'ima-ngv2', which includes the new 'd-type'
field.
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/ima/ima_template.c | 3 +++
security/integrity/ima/ima_template_lib.c | 13 +++++++++++++
security/integrity/ima/ima_template_lib.h | 2 ++
3 files changed, 18 insertions(+)
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index db1ad6d7a57f..b321342e5bee 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -19,6 +19,7 @@ enum header_fields { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME,
static struct ima_template_desc builtin_templates[] = {
{.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
{.name = "ima-ng", .fmt = "d-ng|n-ng"},
+ {.name = "ima-ngv2", .fmt = "d-ng|n-ng|d-type"},
{.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
{.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
{.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
@@ -40,6 +41,8 @@ static const struct ima_template_field supported_fields[] = {
.field_show = ima_show_template_digest_ng},
{.field_id = "n-ng", .field_init = ima_eventname_ng_init,
.field_show = ima_show_template_string},
+ {.field_id = "d-type", .field_init = ima_eventdigest_type_init,
+ .field_show = ima_show_template_string},
{.field_id = "sig", .field_init = ima_eventsig_init,
.field_show = ima_show_template_sig},
{.field_id = "buf", .field_init = ima_eventbuf_init,
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 5a5d462ab36d..48c2fcbefacf 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -386,6 +386,19 @@ int ima_eventdigest_ng_init(struct ima_event_data *event_data,
hash_algo, field_data);
}
+/*
+ * This function writes the digest type of an event.
+ */
+int ima_eventdigest_type_init(struct ima_event_data *event_data,
+ struct ima_field_data *field_data)
+{
+ static const char * const digest_type[] = {"ima"};
+
+ return ima_write_template_field_data(digest_type[0],
+ strlen(digest_type[0]),
+ DATA_FMT_STRING, field_data);
+}
+
/*
* This function writes the digest of the file which is expected to match the
* digest contained in the file's appended signature.
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index c71f1de95753..539a5e354925 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -38,6 +38,8 @@ int ima_eventname_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventdigest_ng_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
+int ima_eventdigest_type_init(struct ima_event_data *event_data,
+ struct ima_field_data *field_data);
int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventname_ng_init(struct ima_event_data *event_data,
--
2.27.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 5/8] ima: permit fsverity's file digests in the IMA measurement list
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
` (3 preceding siblings ...)
2022-02-08 1:41 ` [PATCH v4 4/8] ima: define a new template field 'd-type' and a new template 'ima-ngv2' Mimi Zohar
@ 2022-02-08 1:41 ` Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 6/8] ima: define signature version 3 Mimi Zohar
` (3 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
Permit fsverity's file digest (a hash of struct fsverity_digest) to be
included in the 'd-ng' field of the IMA measurement list, based on the
new measurement policy rule 'digest_type=verity' option.
To differentiate between an unsigned regular IMA file hash and an
unsigned fsverity's file digest stored in the 'd-ng' field of the
measurement list, it is recommended to include the 'd-type' template
field.
The following policy rule requires fsverity file digests and specifies
the new 'ima-ngv2' template, which contains the new 'd-type' field. The
policy rule may be constrained, for example based on a fsuuid or LSM
label.
measure func=FILE_CHECK digest_type=verity template=ima-ngv2
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
Documentation/ABI/testing/ima_policy | 10 ++++++
Documentation/security/IMA-templates.rst | 7 ++++
security/integrity/ima/ima_api.c | 39 +++++++++++++++++++++--
security/integrity/ima/ima_policy.c | 38 +++++++++++++++++++++-
security/integrity/ima/ima_template_lib.c | 9 +++++-
security/integrity/integrity.h | 4 ++-
6 files changed, 102 insertions(+), 5 deletions(-)
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index 839fab811b18..ff3c906738cb 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -51,6 +51,9 @@ Description:
appraise_flag:= [check_blacklist]
Currently, blacklist check is only for files signed with appended
signature.
+ digest_type:= verity
+ Require fs-verity's file digest instead of the
+ regular IMA file hash.
keyrings:= list of keyrings
(eg, .builtin_trusted_keys|.ima). Only valid
when action is "measure" and func is KEY_CHECK.
@@ -149,3 +152,10 @@ Description:
security.ima xattr of a file:
appraise func=SETXATTR_CHECK appraise_algos=sha256,sha384,sha512
+
+ Example of 'measure' rule requiring fs-verity's digests on a
+ particular filesystem with indication of type of digest in
+ the measurement list.
+
+ measure func=FILE_CHECK digest_type=verity \
+ fsuuid=... template=ima-ngv2
diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
index 1a91d92950a7..1e3fe986764e 100644
--- a/Documentation/security/IMA-templates.rst
+++ b/Documentation/security/IMA-templates.rst
@@ -69,6 +69,8 @@ descriptors by adding their identifier to the format string
algorithm (field format: [<hash algo>:]digest, where the digest
prefix is shown only if the hash algorithm is not SHA1 or MD5);
- 'd-modsig': the digest of the event without the appended modsig;
+ - 'd-type': differentiate between fs-verity's Merkle tree based file hash
+ from a regular IMA file hash measurement.
- 'n-ng': the name of the event, without size limitations;
- 'sig': the file signature, or the EVM portable signature if the file
signature is not found;
@@ -106,3 +108,8 @@ currently the following methods are supported:
the ``ima_template=`` parameter;
- register a new template descriptor with custom format through the kernel
command line parameter ``ima_template_fmt=``.
+
+
+References
+==========
+[1] Documentation/filesystems/fsverity.rst
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 45294f18dabc..c359c4d50a1e 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -14,6 +14,7 @@
#include <linux/xattr.h>
#include <linux/evm.h>
#include <linux/iversion.h>
+#include <linux/fsverity.h>
#include "ima.h"
@@ -200,6 +201,23 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
allowed_algos);
}
+static int ima_get_verity_digest(struct integrity_iint_cache *iint,
+ struct ima_max_digest_data *hash)
+{
+ u8 verity_digest[FS_VERITY_MAX_DIGEST_SIZE];
+ enum hash_algo verity_alg;
+ int ret;
+
+ ret = fsverity_get_digest(iint->inode, verity_digest, &verity_alg);
+ if (ret)
+ return ret;
+ if (hash->algo != verity_alg)
+ return -EINVAL;
+ hash->length = hash_digest_size[verity_alg];
+ memcpy(hash->digest, verity_digest, hash->length);
+ return 0;
+}
+
/*
* ima_collect_measurement - collect file measurement
*
@@ -246,12 +264,29 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
/* Initialize hash digest to 0's in case of failure */
memset(&hash.digest, 0, sizeof(hash.digest));
- if (buf)
+ if (buf) {
result = ima_calc_buffer_hash(buf, size,
(struct ima_digest_data *)&hash);
- else
+ } else if (iint->flags & IMA_VERITY_REQUIRED) {
+ result = ima_get_verity_digest(iint, &hash);
+ switch (result) {
+ case 0:
+ iint->flags |= IMA_VERITY_DIGEST;
+ break;
+ case -ENODATA:
+ audit_cause = "no-verity-digest";
+ hash.length = hash_digest_size[algo];
+ result = -EINVAL;
+ break;
+ case -EINVAL:
+ default:
+ audit_cause = "invalid-verity-digest";
+ break;
+ }
+ } else {
result = ima_calc_file_hash(file,
(struct ima_digest_data *)&hash);
+ }
if (result && result != -EBADF && result != -EINVAL)
goto out;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index a0f3775cbd82..28aca1f9633b 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -1024,6 +1024,7 @@ enum policy_opt {
Opt_fowner_gt, Opt_fgroup_gt,
Opt_uid_lt, Opt_euid_lt, Opt_gid_lt, Opt_egid_lt,
Opt_fowner_lt, Opt_fgroup_lt,
+ 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
@@ -1066,6 +1067,7 @@ static const match_table_t policy_tokens = {
{Opt_egid_lt, "egid<%s"},
{Opt_fowner_lt, "fowner<%s"},
{Opt_fgroup_lt, "fgroup<%s"},
+ {Opt_digest_type, "digest_type=%s"},
{Opt_appraise_type, "appraise_type=%s"},
{Opt_appraise_flag, "appraise_flag=%s"},
{Opt_appraise_algos, "appraise_algos=%s"},
@@ -1173,6 +1175,21 @@ static void check_template_modsig(const struct ima_template_desc *template)
#undef MSG
}
+/*
+ * Make sure the policy rule and template format are in sync.
+ */
+static void check_template_field(const struct ima_template_desc *template,
+ const char *field, const char *msg)
+{
+ int i;
+
+ for (i = 0; i < template->num_fields; i++)
+ if (!strcmp(template->fields[i]->field_id, field))
+ return;
+
+ pr_notice_once("%s", msg);
+}
+
static bool ima_validate_rule(struct ima_rule_entry *entry)
{
/* Ensure that the action is set and is compatible with the flags */
@@ -1215,7 +1232,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
IMA_INMASK | IMA_EUID | IMA_PCR |
IMA_FSNAME | IMA_GID | IMA_EGID |
IMA_FGROUP | IMA_DIGSIG_REQUIRED |
- IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS))
+ IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS |
+ IMA_VERITY_REQUIRED))
return false;
break;
@@ -1708,6 +1726,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
LSM_SUBJ_TYPE,
AUDIT_SUBJ_TYPE);
break;
+ case Opt_digest_type:
+ ima_log_string(ab, "digest_type", args[0].from);
+ if ((strcmp(args[0].from, "verity")) == 0)
+ entry->flags |= IMA_VERITY_REQUIRED;
+ else
+ result = -EINVAL;
+ break;
case Opt_appraise_type:
ima_log_string(ab, "appraise_type", args[0].from);
if ((strcmp(args[0].from, "imasig")) == 0)
@@ -1798,6 +1823,15 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
check_template_modsig(template_desc);
}
+ /* d-type template field recommended for unsigned fs-verity digests */
+ if (!result && entry->action == MEASURE &&
+ entry->flags & IMA_VERITY_REQUIRED) {
+ template_desc = entry->template ? entry->template :
+ ima_template_desc_current();
+ check_template_field(template_desc, "d-type",
+ "verity rules should include d-type");
+ }
+
audit_log_format(ab, "res=%d", !result);
audit_log_end(ab);
return result;
@@ -2155,6 +2189,8 @@ int ima_policy_show(struct seq_file *m, void *v)
else
seq_puts(m, "appraise_type=imasig ");
}
+ if (entry->flags & IMA_VERITY_REQUIRED)
+ seq_puts(m, "digest_type=verity ");
if (entry->flags & IMA_CHECK_BLACKLIST)
seq_puts(m, "appraise_flag=check_blacklist ");
if (entry->flags & IMA_PERMIT_DIRECTIO)
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 48c2fcbefacf..31573b4c7763 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -392,7 +392,14 @@ int ima_eventdigest_ng_init(struct ima_event_data *event_data,
int ima_eventdigest_type_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
- static const char * const digest_type[] = {"ima"};
+ static const char * const digest_type[] = {"ima", "verity"};
+
+ if (event_data->iint->flags & IMA_VERITY_DIGEST) {
+ return ima_write_template_field_data(digest_type[1],
+ strlen(digest_type[1]),
+ DATA_FMT_STRING,
+ field_data);
+ }
return ima_write_template_field_data(digest_type[0],
strlen(digest_type[0]),
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index ee2e6b7c7575..cbc41d4288ed 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -32,7 +32,7 @@
#define IMA_HASHED 0x00000200
/* iint policy rule cache flags */
-#define IMA_NONACTION_FLAGS 0xff000000
+#define IMA_NONACTION_FLAGS 0xff800000
#define IMA_DIGSIG_REQUIRED 0x01000000
#define IMA_PERMIT_DIRECTIO 0x02000000
#define IMA_NEW_FILE 0x04000000
@@ -40,6 +40,8 @@
#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000
#define IMA_MODSIG_ALLOWED 0x20000000
#define IMA_CHECK_BLACKLIST 0x40000000
+#define IMA_VERITY_REQUIRED 0x80000000
+#define IMA_VERITY_DIGEST 0x00800000
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
IMA_HASH | IMA_APPRAISE_SUBMASK)
--
2.27.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 6/8] ima: define signature version 3
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
` (4 preceding siblings ...)
2022-02-08 1:41 ` [PATCH v4 5/8] ima: permit fsverity's file digests in the IMA measurement list Mimi Zohar
@ 2022-02-08 1:41 ` Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 7/8] ima: support fs-verity file digest based version 3 signatures Mimi Zohar
` (2 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
To disambiguate the signed data stored in the 'security.ima' xattr,
define signature version 3 as the hash of the ima_file_id structure.
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/digsig.c | 3 ++-
security/integrity/ima/ima_appraise.c | 36 +++++++++++++++++++++++++++
security/integrity/integrity.h | 20 +++++++++++++--
3 files changed, 56 insertions(+), 3 deletions(-)
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 3b06a01bd0fd..fd8f77d92a62 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -74,7 +74,8 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
/* v1 API expect signature without xattr type */
return digsig_verify(keyring, sig + 1, siglen - 1, digest,
digestlen);
- case 2:
+ case 2: /* regular file data hash based sginature */
+ case 3: /* struct ima_file_id data base signature */
return asymmetric_verify(keyring, sig, siglen, digest,
digestlen);
}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 17232bbfb9f9..7bc180bd808e 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -225,6 +225,34 @@ int ima_read_xattr(struct dentry *dentry,
return ret;
}
+/*
+ * calc_file_id_hash - calculate the hash of the ima_file_id struct data
+ * @type: xattr type [enum evm_ima_xattr_type]
+ * @algo: hash algorithm [enum hash_algo]
+ * @digest: pointer to the digest to be hashed
+ * @hash: (out) pointer to the hash
+ *
+ * IMA signature version 3 disambiguates the data that is signed by
+ * indirectly signing the hash of the ima_file_id structure data.
+ *
+ * Return 0 on success, error code otherwise.
+ */
+static int calc_file_id_hash(enum evm_ima_xattr_type type,
+ enum hash_algo algo, const u8 *digest,
+ struct ima_max_digest_data *hash)
+{
+ struct ima_file_id file_id = {.hash_algorithm = algo};
+ uint unused = HASH_MAX_DIGESTSIZE - hash_digest_size[algo];
+
+ memcpy(file_id.hash, digest, hash_digest_size[algo]);
+
+ hash->algo = algo;
+ hash->length = hash_digest_size[algo];
+
+ return ima_calc_buffer_hash(&file_id, sizeof(file_id) - unused,
+ (struct ima_digest_data *)hash);
+}
+
/*
* xattr_verify - verify xattr digest or signature
*
@@ -236,6 +264,7 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
struct evm_ima_xattr_data *xattr_value, int xattr_len,
enum integrity_status *status, const char **cause)
{
+ struct signature_v2_hdr *sig;
int rc = -EINVAL, hash_start = 0;
switch (xattr_value->type) {
@@ -274,6 +303,13 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
break;
case EVM_IMA_XATTR_DIGSIG:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
+
+ sig = (typeof(sig))xattr_value;
+ if (sig->version != 2) {
+ *cause = "invalid-signature-version";
+ *status = INTEGRITY_FAIL;
+ break;
+ }
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value,
xattr_len,
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index cbc41d4288ed..f59f83527c0c 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -94,7 +94,7 @@ struct evm_xattr {
u8 digest[SHA1_DIGEST_SIZE];
} __packed;
-#define IMA_MAX_DIGEST_SIZE 64
+#define IMA_MAX_DIGEST_SIZE HASH_MAX_DIGESTSIZE
struct ima_digest_data {
u8 algo;
@@ -137,7 +137,11 @@ struct ima_max_digest_data {
} __packed;
/*
- * signature format v2 - for using with asymmetric keys
+ * signature header format v2 - for using with asymmetric keys
+ *
+ * signature format:
+ * version 2: regular file data hash based signature
+ * version 3: struct ima_file_id data based signature
*/
struct signature_v2_hdr {
uint8_t type; /* xattr type */
@@ -148,6 +152,18 @@ struct signature_v2_hdr {
uint8_t sig[]; /* signature payload */
} __packed;
+/*
+ * IMA signature version 3 disambiguates the data that is signed, by
+ * indirectly signing the hash of the ima_file_id structure data.
+ *
+ * (The hash of the ima_file_id structure is only of the portion used.)
+ */
+struct ima_file_id {
+ __u8 hash_type; /* xattr type [enum evm_ima_xattr_type] */
+ __u8 hash_algorithm; /* Digest algorithm [enum hash_algo] */
+ __u8 hash[HASH_MAX_DIGESTSIZE];
+} __packed;
+
/* integrity data associated with an inode */
struct integrity_iint_cache {
struct rb_node rb_node; /* rooted in integrity_iint_tree */
--
2.27.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 7/8] ima: support fs-verity file digest based version 3 signatures
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
` (5 preceding siblings ...)
2022-02-08 1:41 ` [PATCH v4 6/8] ima: define signature version 3 Mimi Zohar
@ 2022-02-08 1:41 ` Mimi Zohar
2022-02-11 0:20 ` Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 8/8] fsverity: update the documentation Mimi Zohar
2022-02-08 5:50 ` [PATCH v4 0/8] ima: support fs-verity digests and signatures Eric Biggers
8 siblings, 1 reply; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
Instead of calculating a regular file hash and verifying the signature
stored in the 'security.ima' xattr against the calculated file hash, get
fs-verity's file digest and verify the signature (version 3) stored in
'security.ima' against the digest.
To differentiate between IMA's and fs-verity's signatures, define a
new signature type named 'IMA_VERITY_DIGSIG'.
Update the 'ima-sig' template field to also display the new fs-verity
signature type.
To prevent abuse of the different signature formats, policy rules must be
limited to a specific signature version. The following 'appraise' policy
rule requires fsverity file digests (signature v3). The policy rule may
be constrained, for example based on a fsuuid or LSM label.
Basic fs-verity policy rule example:
appraise func=BPRM_CHECK digest_type=verity
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
Documentation/ABI/testing/ima_policy | 12 ++++
Documentation/security/IMA-templates.rst | 4 +-
security/integrity/ima/ima_appraise.c | 79 +++++++++++++++++++++--
security/integrity/ima/ima_policy.c | 9 ++-
security/integrity/ima/ima_template_lib.c | 3 +-
security/integrity/integrity.h | 5 +-
6 files changed, 100 insertions(+), 12 deletions(-)
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index ff3c906738cb..aabbb206098d 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -159,3 +159,15 @@ Description:
measure func=FILE_CHECK digest_type=verity \
fsuuid=... template=ima-ngv2
+
+ Example of 'measure' and 'appraise' rules requiring fs-verity
+ signatures (version 3) stored in security.ima xattr. The
+ 'ima-sig' template option includes the signature in the
+ measurement list. The 'appraise' rule verifies the signature.
+ These policy rules are limited to a particular filesystem
+ based on its fsuuid.
+
+ measure func=BPRM_CHECK digest_type=verity \
+ fsuuid=... template=ima-sig
+ appraise func=BPRM_CHECK digest_type=verity \
+ fsuuid=...
diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
index 1e3fe986764e..fe9bc2595fa2 100644
--- a/Documentation/security/IMA-templates.rst
+++ b/Documentation/security/IMA-templates.rst
@@ -72,8 +72,8 @@ descriptors by adding their identifier to the format string
- 'd-type': differentiate between fs-verity's Merkle tree based file hash
from a regular IMA file hash measurement.
- 'n-ng': the name of the event, without size limitations;
- - 'sig': the file signature, or the EVM portable signature if the file
- signature is not found;
+ - 'sig': the file signature, based on either the file's/fsverity's digest[1],
+ or the EVM portable signature if the file signature is not found;
- 'modsig' the appended file signature;
- 'buf': the buffer data that was used to generate the hash without size limitations;
- 'evmsig': the EVM portable signature;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 7bc180bd808e..98f2ef99afc0 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -13,7 +13,9 @@
#include <linux/magic.h>
#include <linux/ima.h>
#include <linux/evm.h>
+#include <linux/fsverity.h>
#include <keys/system_keyring.h>
+#include <uapi/linux/fsverity.h>
#include "ima.h"
@@ -183,13 +185,18 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
return ima_hash_algo;
switch (xattr_value->type) {
+ case IMA_VERITY_DIGSIG:
+ sig = (typeof(sig))xattr_value;
+ if (sig->version != 3 || xattr_len <= sizeof(*sig) ||
+ sig->hash_algo >= HASH_ALGO__LAST)
+ return ima_hash_algo;
+ return sig->hash_algo;
case EVM_IMA_XATTR_DIGSIG:
sig = (typeof(sig))xattr_value;
if (sig->version != 2 || xattr_len <= sizeof(*sig)
|| sig->hash_algo >= HASH_ALGO__LAST)
return ima_hash_algo;
return sig->hash_algo;
- break;
case IMA_XATTR_DIGEST_NG:
/* first byte contains algorithm id */
ret = xattr_value->data[0];
@@ -235,15 +242,22 @@ int ima_read_xattr(struct dentry *dentry,
* IMA signature version 3 disambiguates the data that is signed by
* indirectly signing the hash of the ima_file_id structure data.
*
+ * Signing the ima_file_id struct is currently only supported for
+ * IMA_VERITY_DIGSIG type xattrs.
+ *
* Return 0 on success, error code otherwise.
*/
static int calc_file_id_hash(enum evm_ima_xattr_type type,
enum hash_algo algo, const u8 *digest,
struct ima_max_digest_data *hash)
{
- struct ima_file_id file_id = {.hash_algorithm = algo};
+ struct ima_file_id file_id = {
+ .hash_type = IMA_VERITY_DIGSIG, .hash_algorithm = algo};
uint unused = HASH_MAX_DIGESTSIZE - hash_digest_size[algo];
+ if (type != IMA_VERITY_DIGSIG)
+ return -EINVAL;
+
memcpy(file_id.hash, digest, hash_digest_size[algo]);
hash->algo = algo;
@@ -264,6 +278,7 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
struct evm_ima_xattr_data *xattr_value, int xattr_len,
enum integrity_status *status, const char **cause)
{
+ struct ima_max_digest_data hash;
struct signature_v2_hdr *sig;
int rc = -EINVAL, hash_start = 0;
@@ -275,7 +290,10 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
case IMA_XATTR_DIGEST:
if (*status != INTEGRITY_PASS_IMMUTABLE) {
if (iint->flags & IMA_DIGSIG_REQUIRED) {
- *cause = "IMA-signature-required";
+ if (iint->flags & IMA_VERITY_REQUIRED)
+ *cause = "verity-signature-required";
+ else
+ *cause = "IMA-signature-required";
*status = INTEGRITY_FAIL;
break;
}
@@ -304,6 +322,12 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
case EVM_IMA_XATTR_DIGSIG:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
+ if (iint->flags & (IMA_DIGSIG_REQUIRED | IMA_VERITY_REQUIRED)) {
+ *cause = "verity-signature-required";
+ *status = INTEGRITY_FAIL;
+ break;
+ }
+
sig = (typeof(sig))xattr_value;
if (sig->version != 2) {
*cause = "invalid-signature-version";
@@ -332,6 +356,44 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
} else {
*status = INTEGRITY_PASS;
}
+ break;
+ case IMA_VERITY_DIGSIG:
+ set_bit(IMA_DIGSIG, &iint->atomic_flags);
+
+ if (iint->flags & IMA_DIGSIG_REQUIRED) {
+ if (!(iint->flags & IMA_VERITY_REQUIRED)) {
+ *cause = "IMA-signature-required";
+ *status = INTEGRITY_FAIL;
+ break;
+ }
+ }
+
+ sig = (typeof(sig))xattr_value;
+ if (sig->version != 3) {
+ *cause = "invalid-signature-version";
+ *status = INTEGRITY_FAIL;
+ break;
+ }
+
+ rc = calc_file_id_hash(IMA_VERITY_DIGSIG, iint->ima_hash->algo,
+ iint->ima_hash->digest, &hash);
+ if (rc) {
+ *cause = "sigv3-hashing-error";
+ *status = INTEGRITY_FAIL;
+ break;
+ }
+
+ rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
+ (const char *)xattr_value,
+ xattr_len, hash.digest,
+ hash.length);
+ if (rc) {
+ *cause = "invalid-verity-signature";
+ *status = INTEGRITY_FAIL;
+ } else {
+ *status = INTEGRITY_PASS;
+ }
+
break;
default:
*status = INTEGRITY_UNKNOWN;
@@ -432,8 +494,15 @@ int ima_appraise_measurement(enum ima_hooks func,
if (rc && rc != -ENODATA)
goto out;
- cause = iint->flags & IMA_DIGSIG_REQUIRED ?
- "IMA-signature-required" : "missing-hash";
+ if (iint->flags & IMA_DIGSIG_REQUIRED) {
+ if (iint->flags & IMA_VERITY_REQUIRED)
+ cause = "verity-signature-required";
+ else
+ cause = "IMA-signature-required";
+ } else {
+ cause = "missing-hash";
+ }
+
status = INTEGRITY_NOLABEL;
if (file->f_mode & FMODE_CREATED)
iint->flags |= IMA_NEW_FILE;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 28aca1f9633b..576cbe790e27 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -1728,10 +1728,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
break;
case Opt_digest_type:
ima_log_string(ab, "digest_type", args[0].from);
- if ((strcmp(args[0].from, "verity")) == 0)
+ if ((strcmp(args[0].from, "verity")) == 0) {
entry->flags |= IMA_VERITY_REQUIRED;
- else
+ if (entry->action == APPRAISE)
+ entry->flags |= IMA_DIGSIG_REQUIRED;
+ } else {
result = -EINVAL;
+ }
break;
case Opt_appraise_type:
ima_log_string(ab, "appraise_type", args[0].from);
@@ -2186,7 +2189,7 @@ int ima_policy_show(struct seq_file *m, void *v)
if (entry->flags & IMA_DIGSIG_REQUIRED) {
if (entry->flags & IMA_MODSIG_ALLOWED)
seq_puts(m, "appraise_type=imasig|modsig ");
- else
+ else if (!(entry->flags & IMA_VERITY_REQUIRED))
seq_puts(m, "appraise_type=imasig ");
}
if (entry->flags & IMA_VERITY_REQUIRED)
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 31573b4c7763..8f789ee4383e 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -498,7 +498,8 @@ int ima_eventsig_init(struct ima_event_data *event_data,
{
struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
- if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
+ if (!xattr_value ||
+ !(xattr_value->type & (EVM_IMA_XATTR_DIGSIG | IMA_VERITY_DIGSIG)))
return ima_eventevmsig_init(event_data, field_data);
return ima_write_template_field_data(xattr_value, event_data->xattr_len,
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index f59f83527c0c..df68f291fbf0 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -80,6 +80,7 @@ enum evm_ima_xattr_type {
EVM_IMA_XATTR_DIGSIG,
IMA_XATTR_DIGEST_NG,
EVM_XATTR_PORTABLE_DIGSIG,
+ IMA_VERITY_DIGSIG,
IMA_XATTR_LAST
};
@@ -154,7 +155,9 @@ struct signature_v2_hdr {
/*
* IMA signature version 3 disambiguates the data that is signed, by
- * indirectly signing the hash of the ima_file_id structure data.
+ * indirectly signing the hash of the ima_file_id structure data,
+ * containing either the fsverity_descriptor struct digest or, in the
+ * future, the regular IMA file hash.
*
* (The hash of the ima_file_id structure is only of the portion used.)
*/
--
2.27.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 8/8] fsverity: update the documentation
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
` (6 preceding siblings ...)
2022-02-08 1:41 ` [PATCH v4 7/8] ima: support fs-verity file digest based version 3 signatures Mimi Zohar
@ 2022-02-08 1:41 ` Mimi Zohar
2022-02-08 5:50 ` [PATCH v4 0/8] ima: support fs-verity digests and signatures Eric Biggers
8 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 1:41 UTC (permalink / raw)
To: linux-integrity
Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
Update the fsverity documentation related to IMA signature support.
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
Documentation/filesystems/fsverity.rst | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst
index 1d831e3cbcb3..28a47488848e 100644
--- a/Documentation/filesystems/fsverity.rst
+++ b/Documentation/filesystems/fsverity.rst
@@ -74,8 +74,12 @@ authenticating the files is up to userspace. However, to meet some
users' needs, fs-verity optionally supports a simple signature
verification mechanism where users can configure the kernel to require
that all fs-verity files be signed by a key loaded into a keyring; see
-`Built-in signature verification`_. Support for fs-verity file hashes
-in IMA (Integrity Measurement Architecture) policies is also planned.
+`Built-in signature verification`_.
+
+IMA supports including fs-verity file digests and signatures in the
+IMA (Integrity Measurement Architecture) measurement list and
+verifying fs-verity based file signatures stored as security.ima
+xattrs, based on policy.
User API
========
@@ -653,13 +657,13 @@ weren't already directly answered in other parts of this document.
hashed and what to do with those hashes, such as log them,
authenticate them, or add them to a measurement list.
- IMA is planned to support the fs-verity hashing mechanism as an
- alternative to doing full file hashes, for people who want the
- performance and security benefits of the Merkle tree based hash.
- But it doesn't make sense to force all uses of fs-verity to be
- through IMA. As a standalone filesystem feature, fs-verity
- already meets many users' needs, and it's testable like other
- filesystem features e.g. with xfstests.
+ IMA supports the fs-verity hashing mechanism as an alternative
+ to doing full file hashes, for people who want the performance
+ and security benefits of the Merkle tree based hash. But it
+ doesn't make sense to force all uses of fs-verity to be through
+ IMA. As a standalone filesystem feature, fs-verity already meets
+ many users' needs, and it's testable like other filesystem
+ features e.g. with xfstests.
:Q: Isn't fs-verity useless because the attacker can just modify the
hashes in the Merkle tree, which is stored on-disk?
--
2.27.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/8] ima: support fs-verity digests and signatures
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
` (7 preceding siblings ...)
2022-02-08 1:41 ` [PATCH v4 8/8] fsverity: update the documentation Mimi Zohar
@ 2022-02-08 5:50 ` Eric Biggers
2022-02-08 14:57 ` Mimi Zohar
8 siblings, 1 reply; 12+ messages in thread
From: Eric Biggers @ 2022-02-08 5:50 UTC (permalink / raw)
To: Mimi Zohar; +Cc: linux-integrity, Stefan Berger, linux-fscrypt, linux-kernel
On Mon, Feb 07, 2022 at 08:41:32PM -0500, Mimi Zohar wrote:
> Support for including fs-verity file digests and signatures in the IMA
> measurement list as well as verifying the fs-verity file digest based
> signatures, both based on IMA policy rules, was discussed prior to
> fs-verity being upstreamed[1,2].
>
> Support for including fs-verity file digests in the 'd-ng' template field
> is based on a new policy rule option named 'digest_type=verity'. A new
> template field named 'd-type' as well as a new template named 'ima-ngv2'
> are defined to differentiate between the regular IMA file hashes from the
> fs-verity file digests (tree-hash based file hashes) stored in the 'd-ng'
> template field.
>
> Support for verifying fs-verity based file signatures stored in the
> 'security.ima' xattr is similarly based on the policy rule option
> 'digest_type=verity'.
>
> To differentiate IMA from fs-verity file signatures a new xattr_type
> named IMA_VERITY_DIGSIG is defined. Signature version 3, which is a hash
> of the ima_file_id struct, disambiguates the signatures stored as
> 'security.ima' xattr. fs-verity only supports the new signature format
> (version 3). To prevent abuse of the different signature formats, policy
> rules must be limited to a specific signature version.
>
> [1] https://events19.linuxfoundation.org/wp-content/uploads/2017/11/fs-verify_Mike-Halcrow_Eric-Biggers.pdf
> [2] Documentation/filesystems/fsverity.rst
What does this patchset apply to? I'm no longer able to apply it. I tried
both v5.17-rc3, and the next-integrity branch of
https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git.
- Eric
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/8] ima: support fs-verity digests and signatures
2022-02-08 5:50 ` [PATCH v4 0/8] ima: support fs-verity digests and signatures Eric Biggers
@ 2022-02-08 14:57 ` Mimi Zohar
0 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-08 14:57 UTC (permalink / raw)
To: Eric Biggers; +Cc: linux-integrity, Stefan Berger, linux-fscrypt, linux-kernel
On Mon, 2022-02-07 at 21:50 -0800, Eric Biggers wrote:
> On Mon, Feb 07, 2022 at 08:41:32PM -0500, Mimi Zohar wrote:
> > Support for including fs-verity file digests and signatures in the IMA
> > measurement list as well as verifying the fs-verity file digest based
> > signatures, both based on IMA policy rules, was discussed prior to
> > fs-verity being upstreamed[1,2].
> >
> > Support for including fs-verity file digests in the 'd-ng' template field
> > is based on a new policy rule option named 'digest_type=verity'. A new
> > template field named 'd-type' as well as a new template named 'ima-ngv2'
> > are defined to differentiate between the regular IMA file hashes from the
> > fs-verity file digests (tree-hash based file hashes) stored in the 'd-ng'
> > template field.
> >
> > Support for verifying fs-verity based file signatures stored in the
> > 'security.ima' xattr is similarly based on the policy rule option
> > 'digest_type=verity'.
> >
> > To differentiate IMA from fs-verity file signatures a new xattr_type
> > named IMA_VERITY_DIGSIG is defined. Signature version 3, which is a hash
> > of the ima_file_id struct, disambiguates the signatures stored as
> > 'security.ima' xattr. fs-verity only supports the new signature format
> > (version 3). To prevent abuse of the different signature formats, policy
> > rules must be limited to a specific signature version.
> >
> > [1] https://events19.linuxfoundation.org/wp-content/uploads/2017/11/fs-verify_Mike-Halcrow_Eric-Biggers.pdf
> > [2] Documentation/filesystems/fsverity.rst
>
> What does this patchset apply to? I'm no longer able to apply it. I tried
> both v5.17-rc3, and the next-integrity branch of
> https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git.
Just refreshed 'next-integrity' now.
--
thanks,
Mimi
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 7/8] ima: support fs-verity file digest based version 3 signatures
2022-02-08 1:41 ` [PATCH v4 7/8] ima: support fs-verity file digest based version 3 signatures Mimi Zohar
@ 2022-02-11 0:20 ` Mimi Zohar
0 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2022-02-11 0:20 UTC (permalink / raw)
To: linux-integrity; +Cc: Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel
On Mon, 2022-02-07 at 20:41 -0500, Mimi Zohar wrote:
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index 28aca1f9633b..576cbe790e27 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -1728,10 +1728,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
> break;
> case Opt_digest_type:
> ima_log_string(ab, "digest_type", args[0].from);
> - if ((strcmp(args[0].from, "verity")) == 0)
> + if ((strcmp(args[0].from, "verity")) == 0) {
> entry->flags |= IMA_VERITY_REQUIRED;
> - else
> + if (entry->action == APPRAISE)
> + entry->flags |= IMA_DIGSIG_REQUIRED;
Instead of overloading the "digest_type=verity" to require a signature,
extend the existing "appraise_type" to support signature v3 (e.g.
appraise_type=sigv3). This will simplify IMA signature v3 support in
the future.
> + } else {
> result = -EINVAL;
> + }
> break;
> case Opt_appraise_type:
> ima_log_string(ab, "appraise_type", args[0].from);
>
--
thanks,
Mimi
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2022-02-11 0:20 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-08 1:41 [PATCH v4 0/8] ima: support fs-verity digests and signatures Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 2/8] ima: define ima_max_digest_data struct without a flexible array variable Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 3/8] fs-verity: define a function to return the integrity protected file digest Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 4/8] ima: define a new template field 'd-type' and a new template 'ima-ngv2' Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 5/8] ima: permit fsverity's file digests in the IMA measurement list Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 6/8] ima: define signature version 3 Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 7/8] ima: support fs-verity file digest based version 3 signatures Mimi Zohar
2022-02-11 0:20 ` Mimi Zohar
2022-02-08 1:41 ` [PATCH v4 8/8] fsverity: update the documentation Mimi Zohar
2022-02-08 5:50 ` [PATCH v4 0/8] ima: support fs-verity digests and signatures Eric Biggers
2022-02-08 14:57 ` Mimi Zohar
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).