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

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
...@@ -118,16 +118,16 @@ void fsverity_free_info(struct fsverity_info *vi); ...@@ -118,16 +118,16 @@ void fsverity_free_info(struct fsverity_info *vi);
int fsverity_get_descriptor(struct inode *inode, int fsverity_get_descriptor(struct inode *inode,
struct fsverity_descriptor **desc_ret); struct fsverity_descriptor **desc_ret);
int __init fsverity_init_info_cache(void); void __init fsverity_init_info_cache(void);
void __init fsverity_exit_info_cache(void);
/* signature.c */ /* signature.c */
#ifdef CONFIG_FS_VERITY_BUILTIN_SIGNATURES #ifdef CONFIG_FS_VERITY_BUILTIN_SIGNATURES
extern int fsverity_require_signatures;
int fsverity_verify_signature(const struct fsverity_info *vi, int fsverity_verify_signature(const struct fsverity_info *vi,
const u8 *signature, size_t sig_size); 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 */ #else /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
static inline int static inline int
fsverity_verify_signature(const struct fsverity_info *vi, fsverity_verify_signature(const struct fsverity_info *vi,
...@@ -136,15 +136,13 @@ fsverity_verify_signature(const struct fsverity_info *vi, ...@@ -136,15 +136,13 @@ fsverity_verify_signature(const struct fsverity_info *vi,
return 0; return 0;
} }
static inline int fsverity_init_signature(void) static inline void fsverity_init_signature(void)
{ {
return 0;
} }
#endif /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */ #endif /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
/* verify.c */ /* verify.c */
int __init fsverity_init_workqueue(void); void __init fsverity_init_workqueue(void);
void __init fsverity_exit_workqueue(void);
#endif /* _FSVERITY_PRIVATE_H */ #endif /* _FSVERITY_PRIVATE_H */
...@@ -226,6 +226,14 @@ void __init fsverity_check_hash_algs(void) ...@@ -226,6 +226,14 @@ void __init fsverity_check_hash_algs(void)
if (!alg->name) if (!alg->name)
continue; 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); BUG_ON(alg->digest_size > FS_VERITY_MAX_DIGEST_SIZE);
/* /*
......
...@@ -9,6 +9,37 @@ ...@@ -9,6 +9,37 @@
#include <linux/ratelimit.h> #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, void fsverity_msg(const struct inode *inode, const char *level,
const char *fmt, ...) const char *fmt, ...)
{ {
...@@ -33,28 +64,11 @@ void fsverity_msg(const struct inode *inode, const char *level, ...@@ -33,28 +64,11 @@ void fsverity_msg(const struct inode *inode, const char *level,
static int __init fsverity_init(void) static int __init fsverity_init(void)
{ {
int err;
fsverity_check_hash_algs(); fsverity_check_hash_algs();
fsverity_init_info_cache();
err = fsverity_init_info_cache(); fsverity_init_workqueue();
if (err) fsverity_init_sysctl();
return err; fsverity_init_signature();
err = fsverity_init_workqueue();
if (err)
goto err_exit_info_cache;
err = fsverity_init_signature();
if (err)
goto err_exit_workqueue;
return 0; return 0;
err_exit_workqueue:
fsverity_exit_workqueue();
err_exit_info_cache:
fsverity_exit_info_cache();
return err;
} }
late_initcall(fsverity_init) late_initcall(fsverity_init)
...@@ -408,18 +408,10 @@ void __fsverity_cleanup_inode(struct inode *inode) ...@@ -408,18 +408,10 @@ void __fsverity_cleanup_inode(struct inode *inode)
} }
EXPORT_SYMBOL_GPL(__fsverity_cleanup_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, fsverity_info_cachep = KMEM_CACHE_USERCOPY(
SLAB_RECLAIM_ACCOUNT, fsverity_info,
file_digest); SLAB_RECLAIM_ACCOUNT | SLAB_PANIC,
if (!fsverity_info_cachep) file_digest);
return -ENOMEM;
return 0;
}
void __init fsverity_exit_info_cache(void)
{
kmem_cache_destroy(fsverity_info_cachep);
fsverity_info_cachep = NULL;
} }
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* /proc/sys/fs/verity/require_signatures * /proc/sys/fs/verity/require_signatures
* If 1, all verity files must have a valid builtin signature. * 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. * Keyring that contains the trusted X.509 certificates.
...@@ -62,6 +62,22 @@ int fsverity_verify_signature(const struct fsverity_info *vi, ...@@ -62,6 +62,22 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
return 0; 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); d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL);
if (!d) if (!d)
return -ENOMEM; return -ENOMEM;
...@@ -93,59 +109,14 @@ int fsverity_verify_signature(const struct fsverity_info *vi, ...@@ -93,59 +109,14 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
return 0; return 0;
} }
#ifdef CONFIG_SYSCTL void __init fsverity_init_signature(void)
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; fsverity_keyring =
} keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
#endif /* !CONFIG_SYSCTL */ current_cred(), KEY_POS_SEARCH |
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_VIEW | KEY_USR_READ | KEY_USR_WRITE |
KEY_USR_SEARCH | KEY_USR_SETATTR, KEY_USR_SEARCH | KEY_USR_SETATTR,
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(ring)) if (IS_ERR(fsverity_keyring))
return PTR_ERR(ring); panic("failed to allocate \".fs-verity\" keyring");
err = fsverity_sysctl_init();
if (err)
goto err_put_ring;
fsverity_keyring = ring;
return 0;
err_put_ring:
key_put(ring);
return err;
} }
...@@ -346,7 +346,7 @@ void fsverity_enqueue_verify_work(struct work_struct *work) ...@@ -346,7 +346,7 @@ void fsverity_enqueue_verify_work(struct work_struct *work)
} }
EXPORT_SYMBOL_GPL(fsverity_enqueue_verify_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 * Use a high-priority workqueue to prioritize verification work, which
...@@ -360,12 +360,5 @@ int __init fsverity_init_workqueue(void) ...@@ -360,12 +360,5 @@ int __init fsverity_init_workqueue(void)
WQ_HIGHPRI, WQ_HIGHPRI,
num_online_cpus()); num_online_cpus());
if (!fsverity_read_workqueue) if (!fsverity_read_workqueue)
return -ENOMEM; panic("failed to allocate fsverity_read_queue");
return 0;
}
void __init fsverity_exit_workqueue(void)
{
destroy_workqueue(fsverity_read_workqueue);
fsverity_read_workqueue = NULL;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment