mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	fs-verity: support builtin file signatures
To meet some users' needs, add optional support for having fs-verity handle a portion of the authentication policy in the kernel. An ".fs-verity" keyring is created to which X.509 certificates can be added; then a sysctl 'fs.verity.require_signatures' can be set to cause the kernel to enforce that all fs-verity files contain a signature of their file measurement by a key in this keyring. See the "Built-in signature verification" section of Documentation/filesystems/fsverity.rst for the full documentation. Reviewed-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
		
							parent
							
								
									add890c9f9
								
							
						
					
					
						commit
						432434c9f8
					
				
					 8 changed files with 269 additions and 14 deletions
				
			
		| 
						 | 
					@ -36,3 +36,20 @@ config FS_VERITY_DEBUG
 | 
				
			||||||
	  Enable debugging messages related to fs-verity by default.
 | 
						  Enable debugging messages related to fs-verity by default.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  Say N unless you are an fs-verity developer.
 | 
						  Say N unless you are an fs-verity developer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config FS_VERITY_BUILTIN_SIGNATURES
 | 
				
			||||||
 | 
						bool "FS Verity builtin signature support"
 | 
				
			||||||
 | 
						depends on FS_VERITY
 | 
				
			||||||
 | 
						select SYSTEM_DATA_VERIFICATION
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Support verifying signatures of verity files against the X.509
 | 
				
			||||||
 | 
						  certificates that have been loaded into the ".fs-verity"
 | 
				
			||||||
 | 
						  kernel keyring.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  This is meant as a relatively simple mechanism that can be
 | 
				
			||||||
 | 
						  used to provide an authenticity guarantee for verity files, as
 | 
				
			||||||
 | 
						  an alternative to IMA appraisal.  Userspace programs still
 | 
				
			||||||
 | 
						  need to check that the verity bit is set in order to get an
 | 
				
			||||||
 | 
						  authenticity guarantee.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  If unsure, say N.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,3 +6,5 @@ obj-$(CONFIG_FS_VERITY) += enable.o \
 | 
				
			||||||
			   measure.o \
 | 
								   measure.o \
 | 
				
			||||||
			   open.o \
 | 
								   open.o \
 | 
				
			||||||
			   verify.o
 | 
								   verify.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_FS_VERITY_BUILTIN_SIGNATURES) += signature.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,7 +161,7 @@ static int enable_verity(struct file *filp,
 | 
				
			||||||
	const struct fsverity_operations *vops = inode->i_sb->s_vop;
 | 
						const struct fsverity_operations *vops = inode->i_sb->s_vop;
 | 
				
			||||||
	struct merkle_tree_params params = { };
 | 
						struct merkle_tree_params params = { };
 | 
				
			||||||
	struct fsverity_descriptor *desc;
 | 
						struct fsverity_descriptor *desc;
 | 
				
			||||||
	size_t desc_size = sizeof(*desc);
 | 
						size_t desc_size = sizeof(*desc) + arg->sig_size;
 | 
				
			||||||
	struct fsverity_info *vi;
 | 
						struct fsverity_info *vi;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,6 +183,16 @@ static int enable_verity(struct file *filp,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	desc->salt_size = arg->salt_size;
 | 
						desc->salt_size = arg->salt_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get the signature if the user provided one */
 | 
				
			||||||
 | 
						if (arg->sig_size &&
 | 
				
			||||||
 | 
						    copy_from_user(desc->signature,
 | 
				
			||||||
 | 
								   (const u8 __user *)(uintptr_t)arg->sig_ptr,
 | 
				
			||||||
 | 
								   arg->sig_size)) {
 | 
				
			||||||
 | 
							err = -EFAULT;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						desc->sig_size = cpu_to_le32(arg->sig_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	desc->data_size = cpu_to_le64(inode->i_size);
 | 
						desc->data_size = cpu_to_le64(inode->i_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Prepare the Merkle tree parameters */
 | 
						/* Prepare the Merkle tree parameters */
 | 
				
			||||||
| 
						 | 
					@ -238,6 +248,10 @@ static int enable_verity(struct file *filp,
 | 
				
			||||||
		goto rollback;
 | 
							goto rollback;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (arg->sig_size)
 | 
				
			||||||
 | 
							pr_debug("Storing a %u-byte PKCS#7 signature alongside the file\n",
 | 
				
			||||||
 | 
								 arg->sig_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Tell the filesystem to finish enabling verity on the file.
 | 
						 * Tell the filesystem to finish enabling verity on the file.
 | 
				
			||||||
	 * Serialized with ->begin_enable_verity() by the inode lock.
 | 
						 * Serialized with ->begin_enable_verity() by the inode lock.
 | 
				
			||||||
| 
						 | 
					@ -304,8 +318,8 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg)
 | 
				
			||||||
	if (arg.salt_size > FIELD_SIZEOF(struct fsverity_descriptor, salt))
 | 
						if (arg.salt_size > FIELD_SIZEOF(struct fsverity_descriptor, salt))
 | 
				
			||||||
		return -EMSGSIZE;
 | 
							return -EMSGSIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (arg.sig_size)
 | 
						if (arg.sig_size > FS_VERITY_MAX_SIGNATURE_SIZE)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EMSGSIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Require a regular file with write access.  But the actual fd must
 | 
						 * Require a regular file with write access.  But the actual fd must
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,23 +75,41 @@ struct fsverity_info {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Merkle tree properties.  The file measurement is the hash of this structure.
 | 
					 * Merkle tree properties.  The file measurement is the hash of this structure
 | 
				
			||||||
 | 
					 * excluding the signature and with the sig_size field set to 0.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct fsverity_descriptor {
 | 
					struct fsverity_descriptor {
 | 
				
			||||||
	__u8 version;		/* must be 1 */
 | 
						__u8 version;		/* must be 1 */
 | 
				
			||||||
	__u8 hash_algorithm;	/* Merkle tree hash algorithm */
 | 
						__u8 hash_algorithm;	/* Merkle tree hash algorithm */
 | 
				
			||||||
	__u8 log_blocksize;	/* log2 of size of data and tree blocks */
 | 
						__u8 log_blocksize;	/* log2 of size of data and tree blocks */
 | 
				
			||||||
	__u8 salt_size;		/* size of salt in bytes; 0 if none */
 | 
						__u8 salt_size;		/* size of salt in bytes; 0 if none */
 | 
				
			||||||
	__le32 sig_size;	/* reserved, must be 0 */
 | 
						__le32 sig_size;	/* size of signature in bytes; 0 if none */
 | 
				
			||||||
	__le64 data_size;	/* size of file the Merkle tree is built over */
 | 
						__le64 data_size;	/* size of file the Merkle tree is built over */
 | 
				
			||||||
	__u8 root_hash[64];	/* Merkle tree root hash */
 | 
						__u8 root_hash[64];	/* Merkle tree root hash */
 | 
				
			||||||
	__u8 salt[32];		/* salt prepended to each hashed block */
 | 
						__u8 salt[32];		/* salt prepended to each hashed block */
 | 
				
			||||||
	__u8 __reserved[144];	/* must be 0's */
 | 
						__u8 __reserved[144];	/* must be 0's */
 | 
				
			||||||
 | 
						__u8 signature[];	/* optional PKCS#7 signature */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Arbitrary limit to bound the kmalloc() size.  Can be changed. */
 | 
					/* Arbitrary limit to bound the kmalloc() size.  Can be changed. */
 | 
				
			||||||
#define FS_VERITY_MAX_DESCRIPTOR_SIZE	16384
 | 
					#define FS_VERITY_MAX_DESCRIPTOR_SIZE	16384
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FS_VERITY_MAX_SIGNATURE_SIZE	(FS_VERITY_MAX_DESCRIPTOR_SIZE - \
 | 
				
			||||||
 | 
										 sizeof(struct fsverity_descriptor))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Format in which verity file measurements are signed.  This is the same as
 | 
				
			||||||
 | 
					 * 'struct fsverity_digest', except here some magic bytes are prepended to
 | 
				
			||||||
 | 
					 * provide some context about what is being signed in case the same key is used
 | 
				
			||||||
 | 
					 * for non-fsverity purposes, and here the fields have fixed endianness.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct fsverity_signed_digest {
 | 
				
			||||||
 | 
						char magic[8];			/* must be "FSVerity" */
 | 
				
			||||||
 | 
						__le16 digest_algorithm;
 | 
				
			||||||
 | 
						__le16 digest_size;
 | 
				
			||||||
 | 
						__u8 digest[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* hash_algs.c */
 | 
					/* hash_algs.c */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct fsverity_hash_alg fsverity_hash_algs[];
 | 
					extern struct fsverity_hash_alg fsverity_hash_algs[];
 | 
				
			||||||
| 
						 | 
					@ -127,7 +145,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
 | 
				
			||||||
				     const u8 *salt, size_t salt_size);
 | 
									     const u8 *salt, size_t salt_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct fsverity_info *fsverity_create_info(const struct inode *inode,
 | 
					struct fsverity_info *fsverity_create_info(const struct inode *inode,
 | 
				
			||||||
					   const void *desc, size_t desc_size);
 | 
										   void *desc, size_t desc_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void fsverity_set_info(struct inode *inode, struct fsverity_info *vi);
 | 
					void fsverity_set_info(struct inode *inode, struct fsverity_info *vi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,8 +154,32 @@ void fsverity_free_info(struct fsverity_info *vi);
 | 
				
			||||||
int __init fsverity_init_info_cache(void);
 | 
					int __init fsverity_init_info_cache(void);
 | 
				
			||||||
void __init fsverity_exit_info_cache(void);
 | 
					void __init fsverity_exit_info_cache(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* signature.c */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_FS_VERITY_BUILTIN_SIGNATURES
 | 
				
			||||||
 | 
					int fsverity_verify_signature(const struct fsverity_info *vi,
 | 
				
			||||||
 | 
								      const struct fsverity_descriptor *desc,
 | 
				
			||||||
 | 
								      size_t desc_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __init fsverity_init_signature(void);
 | 
				
			||||||
 | 
					#else /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					fsverity_verify_signature(const struct fsverity_info *vi,
 | 
				
			||||||
 | 
								  const struct fsverity_descriptor *desc,
 | 
				
			||||||
 | 
								  size_t desc_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int fsverity_init_signature(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* verify.c */
 | 
					/* verify.c */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int __init fsverity_init_workqueue(void);
 | 
					int __init fsverity_init_workqueue(void);
 | 
				
			||||||
 | 
					void __init fsverity_exit_workqueue(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _FSVERITY_PRIVATE_H */
 | 
					#endif /* _FSVERITY_PRIVATE_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,9 +45,15 @@ static int __init fsverity_init(void)
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto err_exit_info_cache;
 | 
							goto err_exit_info_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = fsverity_init_signature();
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto err_exit_workqueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_debug("Initialized fs-verity\n");
 | 
						pr_debug("Initialized fs-verity\n");
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_exit_workqueue:
 | 
				
			||||||
 | 
						fsverity_exit_workqueue();
 | 
				
			||||||
err_exit_info_cache:
 | 
					err_exit_info_cache:
 | 
				
			||||||
	fsverity_exit_info_cache();
 | 
						fsverity_exit_info_cache();
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -122,22 +122,32 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Compute the file measurement by hashing the fsverity_descriptor. */
 | 
					/*
 | 
				
			||||||
 | 
					 * Compute the file measurement by hashing the fsverity_descriptor excluding the
 | 
				
			||||||
 | 
					 * signature and with the sig_size field set to 0.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
static int compute_file_measurement(const struct fsverity_hash_alg *hash_alg,
 | 
					static int compute_file_measurement(const struct fsverity_hash_alg *hash_alg,
 | 
				
			||||||
				    const struct fsverity_descriptor *desc,
 | 
									    struct fsverity_descriptor *desc,
 | 
				
			||||||
				    u8 *measurement)
 | 
									    u8 *measurement)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), measurement);
 | 
						__le32 sig_size = desc->sig_size;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc->sig_size = 0;
 | 
				
			||||||
 | 
						err = fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), measurement);
 | 
				
			||||||
 | 
						desc->sig_size = sig_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Validate the given fsverity_descriptor and create a new fsverity_info from
 | 
					 * Validate the given fsverity_descriptor and create a new fsverity_info from
 | 
				
			||||||
 * it.
 | 
					 * it.  The signature (if present) is also checked.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct fsverity_info *fsverity_create_info(const struct inode *inode,
 | 
					struct fsverity_info *fsverity_create_info(const struct inode *inode,
 | 
				
			||||||
					   const void *_desc, size_t desc_size)
 | 
										   void *_desc, size_t desc_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct fsverity_descriptor *desc = _desc;
 | 
						struct fsverity_descriptor *desc = _desc;
 | 
				
			||||||
	struct fsverity_info *vi;
 | 
						struct fsverity_info *vi;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -153,8 +163,7 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode,
 | 
				
			||||||
		return ERR_PTR(-EINVAL);
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (desc->sig_size ||
 | 
						if (memchr_inv(desc->__reserved, 0, sizeof(desc->__reserved))) {
 | 
				
			||||||
	    memchr_inv(desc->__reserved, 0, sizeof(desc->__reserved))) {
 | 
					 | 
				
			||||||
		fsverity_err(inode, "Reserved bits set in descriptor");
 | 
							fsverity_err(inode, "Reserved bits set in descriptor");
 | 
				
			||||||
		return ERR_PTR(-EINVAL);
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -198,6 +207,8 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode,
 | 
				
			||||||
	pr_debug("Computed file measurement: %s:%*phN\n",
 | 
						pr_debug("Computed file measurement: %s:%*phN\n",
 | 
				
			||||||
		 vi->tree_params.hash_alg->name,
 | 
							 vi->tree_params.hash_alg->name,
 | 
				
			||||||
		 vi->tree_params.digest_size, vi->measurement);
 | 
							 vi->tree_params.digest_size, vi->measurement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = fsverity_verify_signature(vi, desc, desc_size);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		fsverity_free_info(vi);
 | 
							fsverity_free_info(vi);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										157
									
								
								fs/verity/signature.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								fs/verity/signature.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,157 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * fs/verity/signature.c: verification of builtin signatures
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2019 Google LLC
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fsverity_private.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/cred.h>
 | 
				
			||||||
 | 
					#include <linux/key.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/verification.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * /proc/sys/fs/verity/require_signatures
 | 
				
			||||||
 | 
					 * If 1, all verity files must have a valid builtin signature.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int fsverity_require_signatures;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Keyring that contains the trusted X.509 certificates.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Only root (kuid=0) can modify this.  Also, root may use
 | 
				
			||||||
 | 
					 * keyctl_restrict_keyring() to prevent any more additions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct key *fsverity_keyring;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * fsverity_verify_signature() - check a verity file's signature
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the file's fs-verity descriptor includes a signature of the file
 | 
				
			||||||
 | 
					 * measurement, verify it against the certificates in the fs-verity keyring.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return: 0 on success (signature valid or not required); -errno on failure
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int fsverity_verify_signature(const struct fsverity_info *vi,
 | 
				
			||||||
 | 
								      const struct fsverity_descriptor *desc,
 | 
				
			||||||
 | 
								      size_t desc_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct inode *inode = vi->inode;
 | 
				
			||||||
 | 
						const struct fsverity_hash_alg *hash_alg = vi->tree_params.hash_alg;
 | 
				
			||||||
 | 
						const u32 sig_size = le32_to_cpu(desc->sig_size);
 | 
				
			||||||
 | 
						struct fsverity_signed_digest *d;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sig_size == 0) {
 | 
				
			||||||
 | 
							if (fsverity_require_signatures) {
 | 
				
			||||||
 | 
								fsverity_err(inode,
 | 
				
			||||||
 | 
									     "require_signatures=1, rejecting unsigned file!");
 | 
				
			||||||
 | 
								return -EPERM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sig_size > desc_size - sizeof(*desc)) {
 | 
				
			||||||
 | 
							fsverity_err(inode, "Signature overflows verity descriptor");
 | 
				
			||||||
 | 
							return -EBADMSG;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!d)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						memcpy(d->magic, "FSVerity", 8);
 | 
				
			||||||
 | 
						d->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs);
 | 
				
			||||||
 | 
						d->digest_size = cpu_to_le16(hash_alg->digest_size);
 | 
				
			||||||
 | 
						memcpy(d->digest, vi->measurement, hash_alg->digest_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size,
 | 
				
			||||||
 | 
									     desc->signature, sig_size,
 | 
				
			||||||
 | 
									     fsverity_keyring,
 | 
				
			||||||
 | 
									     VERIFYING_UNSPECIFIED_SIGNATURE,
 | 
				
			||||||
 | 
									     NULL, NULL);
 | 
				
			||||||
 | 
						kfree(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							if (err == -ENOKEY)
 | 
				
			||||||
 | 
								fsverity_err(inode,
 | 
				
			||||||
 | 
									     "File's signing cert isn't in the fs-verity keyring");
 | 
				
			||||||
 | 
							else if (err == -EKEYREJECTED)
 | 
				
			||||||
 | 
								fsverity_err(inode, "Incorrect file signature");
 | 
				
			||||||
 | 
							else if (err == -EBADMSG)
 | 
				
			||||||
 | 
								fsverity_err(inode, "Malformed file signature");
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								fsverity_err(inode, "Error %d verifying file signature",
 | 
				
			||||||
 | 
									     err);
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pr_debug("Valid signature for file measurement %s:%*phN\n",
 | 
				
			||||||
 | 
							 hash_alg->name, hash_alg->digest_size, vi->measurement);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_SYSCTL
 | 
				
			||||||
 | 
					static struct ctl_table_header *fsverity_sysctl_header;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct ctl_path fsverity_sysctl_path[] = {
 | 
				
			||||||
 | 
						{ .procname = "fs", },
 | 
				
			||||||
 | 
						{ .procname = "verity", },
 | 
				
			||||||
 | 
						{ }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ctl_table fsverity_sysctl_table[] = {
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.procname       = "require_signatures",
 | 
				
			||||||
 | 
							.data           = &fsverity_require_signatures,
 | 
				
			||||||
 | 
							.maxlen         = sizeof(int),
 | 
				
			||||||
 | 
							.mode           = 0644,
 | 
				
			||||||
 | 
							.proc_handler   = proc_dointvec_minmax,
 | 
				
			||||||
 | 
							.extra1         = SYSCTL_ZERO,
 | 
				
			||||||
 | 
							.extra2         = SYSCTL_ONE,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{ }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init fsverity_sysctl_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path,
 | 
				
			||||||
 | 
											       fsverity_sysctl_table);
 | 
				
			||||||
 | 
						if (!fsverity_sysctl_header) {
 | 
				
			||||||
 | 
							pr_err("sysctl registration failed!\n");
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else /* !CONFIG_SYSCTL */
 | 
				
			||||||
 | 
					static inline int __init fsverity_sysctl_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* !CONFIG_SYSCTL */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __init fsverity_init_signature(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct key *ring;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ring = keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
 | 
				
			||||||
 | 
								     current_cred(), KEY_POS_SEARCH |
 | 
				
			||||||
 | 
									KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE |
 | 
				
			||||||
 | 
									KEY_USR_SEARCH | KEY_USR_SETATTR,
 | 
				
			||||||
 | 
								     KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
 | 
				
			||||||
 | 
						if (IS_ERR(ring))
 | 
				
			||||||
 | 
							return PTR_ERR(ring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = fsverity_sysctl_init();
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto err_put_ring;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fsverity_keyring = ring;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_put_ring:
 | 
				
			||||||
 | 
						key_put(ring);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -273,3 +273,9 @@ int __init fsverity_init_workqueue(void)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __init fsverity_exit_workqueue(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						destroy_workqueue(fsverity_read_workqueue);
 | 
				
			||||||
 | 
						fsverity_read_workqueue = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue