Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c22f68f authored by Eric Biggers's avatar Eric Biggers Committed by Jaegeuk Kim
Browse files

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: default avatarTheodore Ts'o <tytso@mit.edu>
Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
parent 9b8425a7
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -36,3 +36,20 @@ config FS_VERITY_DEBUG
	  Enable debugging messages related to fs-verity by default.

	  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.
+2 −0
Original line number Diff line number Diff line
@@ -6,3 +6,5 @@ obj-$(CONFIG_FS_VERITY) += enable.o \
			   measure.o \
			   open.o \
			   verify.o

obj-$(CONFIG_FS_VERITY_BUILTIN_SIGNATURES) += signature.o
+17 −3
Original line number Diff line number Diff line
@@ -161,7 +161,7 @@ static int enable_verity(struct file *filp,
	const struct fsverity_operations *vops = inode->i_sb->s_vop;
	struct merkle_tree_params params = { };
	struct fsverity_descriptor *desc;
	size_t desc_size = sizeof(*desc);
	size_t desc_size = sizeof(*desc) + arg->sig_size;
	struct fsverity_info *vi;
	int err;

@@ -183,6 +183,16 @@ static int enable_verity(struct file *filp,
	}
	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);

	/* Prepare the Merkle tree parameters */
@@ -238,6 +248,10 @@ static int enable_verity(struct file *filp,
		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.
	 * 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))
		return -EMSGSIZE;

	if (arg.sig_size)
		return -EINVAL;
	if (arg.sig_size > FS_VERITY_MAX_SIGNATURE_SIZE)
		return -EMSGSIZE;

	/*
	 * Require a regular file with write access.  But the actual fd must
+45 −3
Original line number Diff line number Diff line
@@ -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 {
	__u8 version;		/* must be 1 */
	__u8 hash_algorithm;	/* Merkle tree hash algorithm */
	__u8 log_blocksize;	/* log2 of size of data and tree blocks */
	__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 */
	__u8 root_hash[64];	/* Merkle tree root hash */
	__u8 salt[32];		/* salt prepended to each hashed block */
	__u8 __reserved[144];	/* must be 0's */
	__u8 signature[];	/* optional PKCS#7 signature */
};

/* Arbitrary limit to bound the kmalloc() size.  Can be changed. */
#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 */

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);

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);

@@ -136,8 +154,32 @@ void fsverity_free_info(struct fsverity_info *vi);
int __init fsverity_init_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 */

int __init fsverity_init_workqueue(void);
void __init fsverity_exit_workqueue(void);

#endif /* _FSVERITY_PRIVATE_H */
+6 −0
Original line number Diff line number Diff line
@@ -45,9 +45,15 @@ static int __init fsverity_init(void)
	if (err)
		goto err_exit_info_cache;

	err = fsverity_init_signature();
	if (err)
		goto err_exit_workqueue;

	pr_debug("Initialized fs-verity\n");
	return 0;

err_exit_workqueue:
	fsverity_exit_workqueue();
err_exit_info_cache:
	fsverity_exit_info_cache();
	return err;
Loading