diff mbox series

[RFC,2/5] fsverity: Revalidate built-in signatures at file open

Message ID 20211112124411.1948809-3-roberto.sassu@huawei.com (mailing list archive)
State New
Headers show
Series shmem/fsverity: Prepare for mandatory integrity enforcement | expand

Commit Message

Roberto Sassu Nov. 12, 2021, 12:44 p.m. UTC
Fsverity signatures are validated only upon request by the user by setting
the requirement through procfs or sysctl.

However, signatures are validated only when the fsverity-related
initialization is performed on the file. If the initialization happened
while the signature requirement was disabled, the signature is not
validated again.

Keep track in the fsverity_info structure if the signature was validated
and, based on that and on the signature requirement, perform signature
validation at every call of fsverity_file_open() (the behavior remains the
same if the requirement is not set).

Finally, expose the information of whether the signature was validated
through the new function fsverity_sig_validated(). It could be used for
example by IPE to enforce the signature requirement in a mandatory way (the
procfs/sysctl methods are discretionary).

NOTE: revalidation is not performed if the keys in the fs-verity keyring
changed; this would probably require a more sophisticated mechanism such as
one based on sequence numbers.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 fs/verity/fsverity_private.h |  7 +++++--
 fs/verity/open.c             | 19 ++++++++++++++++++-
 fs/verity/signature.c        |  6 ++++--
 include/linux/fsverity.h     |  6 ++++++
 4 files changed, 33 insertions(+), 5 deletions(-)

Comments

Eric Biggers Nov. 12, 2021, 7:15 p.m. UTC | #1
On Fri, Nov 12, 2021 at 01:44:08PM +0100, Roberto Sassu wrote:
> Fsverity signatures are validated only upon request by the user by setting
> the requirement through procfs or sysctl.
> 
> However, signatures are validated only when the fsverity-related
> initialization is performed on the file. If the initialization happened
> while the signature requirement was disabled, the signature is not
> validated again.

I'm not sure this really matters.  If someone has started using a verity file
before the require_signatures sysctl was set, then there is already a race
condition; this patch doesn't fix that.  Don't you need to set the
require_signatures sysctl early enough anyway?

- Eric
Roberto Sassu Nov. 15, 2021, 9:42 a.m. UTC | #2
> From: Eric Biggers [mailto:ebiggers@kernel.org]
> Sent: Friday, November 12, 2021 8:15 PM
> On Fri, Nov 12, 2021 at 01:44:08PM +0100, Roberto Sassu wrote:
> > Fsverity signatures are validated only upon request by the user by setting
> > the requirement through procfs or sysctl.
> >
> > However, signatures are validated only when the fsverity-related
> > initialization is performed on the file. If the initialization happened
> > while the signature requirement was disabled, the signature is not
> > validated again.
> 
> I'm not sure this really matters.  If someone has started using a verity file
> before the require_signatures sysctl was set, then there is already a race
> condition; this patch doesn't fix that.  Don't you need to set the
> require_signatures sysctl early enough anyway?

Yes, access to already opened files is not revoked. It will work
for a new open. Actually, the main reason for this patch was that
one of the tests in xfstests-dev fails (generic/577).

While persistent filesystems are unmounted and mounted before
the test, which causes the fsverity_info structure to be removed
from the inode, requiring a new verification, tmpfs is just remounted.
During remount, the fsverity_info structure of already instantiated
inodes is kept.

Since fsverity_verify_signature() is called only when the
fsverity_info structure is created, all files with that structure are
considered valid, even if signature verification was temporarily
disabled at the time the structure was created.

Requiring signature verification early could be a solution, but
it is still at discretion of root. Maybe it would be a good idea to
disable the interface with a kernel option, so that signatures
can be enforced in a mandatory way.

This patch probably helps more LSMs, by exposing the information
of whether the signature was validated, to make their decision
depending on their policy.

Thanks

Roberto

HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Li Peng, Zhong Ronghua
diff mbox series

Patch

diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
index a7920434bae5..bcd5c0587e42 100644
--- a/fs/verity/fsverity_private.h
+++ b/fs/verity/fsverity_private.h
@@ -75,6 +75,7 @@  struct fsverity_info {
 	u8 root_hash[FS_VERITY_MAX_DIGEST_SIZE];
 	u8 file_digest[FS_VERITY_MAX_DIGEST_SIZE];
 	const struct inode *inode;
+	bool sig_validated;
 };
 
 /* Arbitrary limit to bound the kmalloc() size.  Can be changed. */
@@ -138,14 +139,16 @@  void __init fsverity_exit_info_cache(void);
 
 /* signature.c */
 
+extern int fsverity_require_signatures;
+
 #ifdef CONFIG_FS_VERITY_BUILTIN_SIGNATURES
-int fsverity_verify_signature(const struct fsverity_info *vi,
+int fsverity_verify_signature(struct fsverity_info *vi,
 			      const u8 *signature, size_t sig_size);
 
 int __init fsverity_init_signature(void);
 #else /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
 static inline int
-fsverity_verify_signature(const struct fsverity_info *vi,
+fsverity_verify_signature(struct fsverity_info *vi,
 			  const u8 *signature, size_t sig_size)
 {
 	return 0;
diff --git a/fs/verity/open.c b/fs/verity/open.c
index 9127c77c6539..22c6644b0282 100644
--- a/fs/verity/open.c
+++ b/fs/verity/open.c
@@ -242,6 +242,17 @@  ssize_t fsverity_get_file_digest(struct fsverity_info *info, u8 *buf,
 	return hash_digest_size[*algo];
 }
 
+/*
+ * Provide the information of whether the fsverity built-in signature was
+ * validated.
+ *
+ * Return: true if the signature was validated, false if not
+ */
+bool fsverity_sig_validated(struct fsverity_info *info)
+{
+	return info->sig_validated;
+}
+
 static bool validate_fsverity_descriptor(struct inode *inode,
 					 const struct fsverity_descriptor *desc,
 					 size_t desc_size)
@@ -333,13 +344,19 @@  static int ensure_verity_info(struct inode *inode)
 	size_t desc_size;
 	int err;
 
-	if (vi)
+	if (vi && (!fsverity_require_signatures || vi->sig_validated))
 		return 0;
 
 	err = fsverity_get_descriptor(inode, &desc, &desc_size);
 	if (err)
 		return err;
 
+	if (vi) {
+		err = fsverity_verify_signature(vi, desc->signature,
+						le32_to_cpu(desc->sig_size));
+		goto out_free_desc;
+	}
+
 	vi = fsverity_create_info(inode, desc, desc_size);
 	if (IS_ERR(vi)) {
 		err = PTR_ERR(vi);
diff --git a/fs/verity/signature.c b/fs/verity/signature.c
index 143a530a8008..dbe6b3b0431c 100644
--- a/fs/verity/signature.c
+++ b/fs/verity/signature.c
@@ -16,7 +16,7 @@ 
  * /proc/sys/fs/verity/require_signatures
  * If 1, all verity files must have a valid builtin signature.
  */
-static int fsverity_require_signatures;
+int fsverity_require_signatures;
 
 /*
  * Keyring that contains the trusted X.509 certificates.
@@ -37,7 +37,7 @@  static struct key *fsverity_keyring;
  *
  * Return: 0 on success (signature valid or not required); -errno on failure
  */
-int fsverity_verify_signature(const struct fsverity_info *vi,
+int fsverity_verify_signature(struct fsverity_info *vi,
 			      const u8 *signature, size_t sig_size)
 {
 	const struct inode *inode = vi->inode;
@@ -82,6 +82,8 @@  int fsverity_verify_signature(const struct fsverity_info *vi,
 		return err;
 	}
 
+	vi->sig_validated = true;
+
 	pr_debug("Valid signature for file digest %s:%*phN\n",
 		 hash_alg->name, hash_alg->digest_size, vi->file_digest);
 	return 0;
diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h
index 877a7f609dd9..85e52333d1b8 100644
--- a/include/linux/fsverity.h
+++ b/include/linux/fsverity.h
@@ -140,6 +140,7 @@  int fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr);
 void fsverity_cleanup_inode(struct inode *inode);
 ssize_t fsverity_get_file_digest(struct fsverity_info *info, u8 *buf,
 				 size_t bufsize, enum hash_algo *algo);
+bool fsverity_sig_validated(struct fsverity_info *info);
 
 /* read_metadata.c */
 
@@ -197,6 +198,11 @@  static inline ssize_t fsverity_get_file_digest(struct fsverity_info *info,
 	return -EOPNOTSUPP;
 }
 
+static inline bool fsverity_sig_validated(struct fsverity_info *info)
+{
+	return false;
+}
+
 /* read_metadata.c */
 
 static inline int fsverity_ioctl_read_metadata(struct file *filp,