fsverity updates for 6.6

Several cleanups for fs/verity/, including two commits that make the
 builtin signature support more cleanly separated from the base feature.
 -----BEGIN PGP SIGNATURE-----
 
 iIoEABYIADIWIQSacvsUNc7UX4ntmEPzXCl4vpKOKwUCZOwXSRQcZWJpZ2dlcnNA
 Z29vZ2xlLmNvbQAKCRDzXCl4vpKOK+kzAP9UsTtZjjQLvEDF6OYlysFLQppDrmk0
 zh9iH/Z7qT8BQwEA0azRHW5/FDLvkHZWsU0QCLjDpUPrNHc712aeM1pLpgc=
 =zOdL
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2023-08-28 12:16:42 -07:00
commit 3bb156a556
6 changed files with 79 additions and 103 deletions

View file

@ -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 */

View file

@ -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);
/*

View file

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

View file

@ -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,
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;
fsverity_info_cachep = KMEM_CACHE_USERCOPY(
fsverity_info,
SLAB_RECLAIM_ACCOUNT | SLAB_PANIC,
file_digest);
}

View file

@ -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)
void __init fsverity_init_signature(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)
{
struct key *ring;
int err;
ring = keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
current_cred(), KEY_POS_SEARCH |
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;
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(fsverity_keyring))
panic("failed to allocate \".fs-verity\" keyring");
}

View file

@ -346,7 +346,7 @@ void fsverity_enqueue_verify_work(struct work_struct *work)
}
EXPORT_SYMBOL_GPL(fsverity_enqueue_verify_work);
int __init fsverity_init_workqueue(void)
void __init fsverity_init_workqueue(void)
{
/*
* Use a high-priority workqueue to prioritize verification work, which
@ -360,12 +360,5 @@ int __init fsverity_init_workqueue(void)
WQ_HIGHPRI,
num_online_cpus());
if (!fsverity_read_workqueue)
return -ENOMEM;
return 0;
}
void __init fsverity_exit_workqueue(void)
{
destroy_workqueue(fsverity_read_workqueue);
fsverity_read_workqueue = NULL;
panic("failed to allocate fsverity_read_queue");
}