Commit 3bb156a5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fsverity/linux

Pull fsverity updates from Eric Biggers:
 "Several cleanups for fs/verity/, including two commits that make the
  builtin signature support more cleanly separated from the base
  feature"

* tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fsverity/linux:
  fsverity: skip PKCS#7 parser when keyring is empty
  fsverity: move sysctl registration out of signature.c
  fsverity: simplify handling of errors during initcall
  fsverity: explicitly check that there is no algorithm 0
parents cc0a38d0 919dc320
Loading
Loading
Loading
Loading
+5 −7
Original line number Diff line number Diff line
@@ -118,16 +118,16 @@ void fsverity_free_info(struct fsverity_info *vi);
int fsverity_get_descriptor(struct inode *inode,
			    struct fsverity_descriptor **desc_ret);

int __init fsverity_init_info_cache(void);
void __init fsverity_exit_info_cache(void);
void __init fsverity_init_info_cache(void);

/* signature.c */

#ifdef CONFIG_FS_VERITY_BUILTIN_SIGNATURES
extern int fsverity_require_signatures;
int fsverity_verify_signature(const struct fsverity_info *vi,
			      const u8 *signature, size_t sig_size);

int __init fsverity_init_signature(void);
void __init fsverity_init_signature(void);
#else /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
static inline int
fsverity_verify_signature(const struct fsverity_info *vi,
@@ -136,15 +136,13 @@ fsverity_verify_signature(const struct fsverity_info *vi,
	return 0;
}

static inline int fsverity_init_signature(void)
static inline void 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);
void __init fsverity_init_workqueue(void);

#endif /* _FSVERITY_PRIVATE_H */
+8 −0
Original line number Diff line number Diff line
@@ -226,6 +226,14 @@ void __init fsverity_check_hash_algs(void)
		if (!alg->name)
			continue;

		/*
		 * 0 must never be allocated as an FS_VERITY_HASH_ALG_* value,
		 * as it is reserved for users that use 0 to mean unspecified or
		 * a default value.  fs/verity/ itself doesn't care and doesn't
		 * have a default algorithm, but some users make use of this.
		 */
		BUG_ON(i == 0);

		BUG_ON(alg->digest_size > FS_VERITY_MAX_DIGEST_SIZE);

		/*
+35 −21
Original line number Diff line number Diff line
@@ -9,6 +9,37 @@

#include <linux/ratelimit.h>

#ifdef CONFIG_SYSCTL
static struct ctl_table_header *fsverity_sysctl_header;

static struct ctl_table fsverity_sysctl_table[] = {
#ifdef CONFIG_FS_VERITY_BUILTIN_SIGNATURES
	{
		.procname       = "require_signatures",
		.data           = &fsverity_require_signatures,
		.maxlen         = sizeof(int),
		.mode           = 0644,
		.proc_handler   = proc_dointvec_minmax,
		.extra1         = SYSCTL_ZERO,
		.extra2         = SYSCTL_ONE,
	},
#endif
	{ }
};

static void __init fsverity_init_sysctl(void)
{
	fsverity_sysctl_header = register_sysctl("fs/verity",
						 fsverity_sysctl_table);
	if (!fsverity_sysctl_header)
		panic("fsverity sysctl registration failed");
}
#else /* CONFIG_SYSCTL */
static inline void fsverity_init_sysctl(void)
{
}
#endif /* !CONFIG_SYSCTL */

void fsverity_msg(const struct inode *inode, const char *level,
		  const char *fmt, ...)
{
@@ -33,28 +64,11 @@ void fsverity_msg(const struct inode *inode, const char *level,

static int __init fsverity_init(void)
{
	int err;

	fsverity_check_hash_algs();

	err = fsverity_init_info_cache();
	if (err)
		return err;

	err = fsverity_init_workqueue();
	if (err)
		goto err_exit_info_cache;

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

	fsverity_init_info_cache();
	fsverity_init_workqueue();
	fsverity_init_sysctl();
	fsverity_init_signature();
	return 0;

err_exit_workqueue:
	fsverity_exit_workqueue();
err_exit_info_cache:
	fsverity_exit_info_cache();
	return err;
}
late_initcall(fsverity_init)
+5 −13
Original line number Diff line number Diff line
@@ -408,18 +408,10 @@ void __fsverity_cleanup_inode(struct inode *inode)
}
EXPORT_SYMBOL_GPL(__fsverity_cleanup_inode);

int __init fsverity_init_info_cache(void)
void __init fsverity_init_info_cache(void)
{
	fsverity_info_cachep = KMEM_CACHE_USERCOPY(fsverity_info,
						   SLAB_RECLAIM_ACCOUNT,
	fsverity_info_cachep = KMEM_CACHE_USERCOPY(
					fsverity_info,
					SLAB_RECLAIM_ACCOUNT | SLAB_PANIC,
					file_digest);
	if (!fsverity_info_cachep)
		return -ENOMEM;
	return 0;
}

void __init fsverity_exit_info_cache(void)
{
	kmem_cache_destroy(fsverity_info_cachep);
	fsverity_info_cachep = NULL;
}
+24 −53
Original line number Diff line number Diff line
@@ -24,7 +24,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.
@@ -62,6 +62,22 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
		return 0;
	}

	if (fsverity_keyring->keys.nr_leaves_on_tree == 0) {
		/*
		 * The ".fs-verity" keyring is empty, due to builtin signatures
		 * being supported by the kernel but not actually being used.
		 * In this case, verify_pkcs7_signature() would always return an
		 * error, usually ENOKEY.  It could also be EBADMSG if the
		 * PKCS#7 is malformed, but that isn't very important to
		 * distinguish.  So, just skip to ENOKEY to avoid the attack
		 * surface of the PKCS#7 parser, which would otherwise be
		 * reachable by any task able to execute FS_IOC_ENABLE_VERITY.
		 */
		fsverity_err(inode,
			     "fs-verity keyring is empty, rejecting signed file!");
		return -ENOKEY;
	}

	d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL);
	if (!d)
		return -ENOMEM;
@@ -93,59 +109,14 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
	return 0;
}

#ifdef CONFIG_SYSCTL
static struct ctl_table_header *fsverity_sysctl_header;

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("fs/verity", 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)
void __init fsverity_init_signature(void)
{
	struct key *ring;
	int err;

	ring = keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
	fsverity_keyring =
		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;
	if (IS_ERR(fsverity_keyring))
		panic("failed to allocate \".fs-verity\" keyring");
}
Loading