Commit ca219be0 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'integrity-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity

Pull integrity updates from Mimi Zohar:
 "Four integrity changes: two IMA-overlay updates, an integrity Kconfig
  cleanup, and a secondary keyring update"

* tag 'integrity-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
  ima: detect changes to the backing overlay file
  certs: Only allow certs signed by keys on the builtin keyring
  integrity: fix indentation of config attributes
  ima: annotate iint mutex to avoid lockdep false positive warnings
parents 21e80f38 b836c4d2
...@@ -88,7 +88,21 @@ config SECONDARY_TRUSTED_KEYRING ...@@ -88,7 +88,21 @@ config SECONDARY_TRUSTED_KEYRING
help help
If set, provide a keyring to which extra keys may be added, provided If set, provide a keyring to which extra keys may be added, provided
those keys are not blacklisted and are vouched for by a key built those keys are not blacklisted and are vouched for by a key built
into the kernel or already in the secondary trusted keyring. into the kernel, machine keyring (if configured), or already in the
secondary trusted keyring.
config SECONDARY_TRUSTED_KEYRING_SIGNED_BY_BUILTIN
bool "Only allow additional certs signed by keys on the builtin trusted keyring"
depends on SECONDARY_TRUSTED_KEYRING
help
If set, only certificates signed by keys on the builtin trusted
keyring may be loaded onto the secondary trusted keyring.
Note: The machine keyring, if configured, will be linked to the
secondary keyring. When enabling this option, it is recommended
to also configure INTEGRITY_CA_MACHINE_KEYRING_MAX to prevent
linking code signing keys with imputed trust to the secondary
trusted keyring.
config SYSTEM_BLACKLIST_KEYRING config SYSTEM_BLACKLIST_KEYRING
bool "Provide system-wide ring of blacklisted keys" bool "Provide system-wide ring of blacklisted keys"
......
...@@ -102,6 +102,10 @@ int restrict_link_by_signature(struct key *dest_keyring, ...@@ -102,6 +102,10 @@ int restrict_link_by_signature(struct key *dest_keyring,
if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags)) if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags))
ret = -ENOKEY; ret = -ENOKEY;
else if (IS_BUILTIN(CONFIG_SECONDARY_TRUSTED_KEYRING_SIGNED_BY_BUILTIN) &&
!strcmp(dest_keyring->description, ".secondary_trusted_keys") &&
!test_bit(KEY_FLAG_BUILTIN, &key->flags))
ret = -ENOKEY;
else else
ret = verify_signature(key, sig); ret = verify_signature(key, sig);
key_put(key); key_put(key);
......
...@@ -1499,7 +1499,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1499,7 +1499,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
#ifdef CONFIG_FS_POSIX_ACL #ifdef CONFIG_FS_POSIX_ACL
sb->s_flags |= SB_POSIXACL; sb->s_flags |= SB_POSIXACL;
#endif #endif
sb->s_iflags |= SB_I_SKIP_SYNC | SB_I_IMA_UNVERIFIABLE_SIGNATURE; sb->s_iflags |= SB_I_SKIP_SYNC;
/* /*
* Ensure that umask handling is done by the filesystems used * Ensure that umask handling is done by the filesystems used
* for the the upper layer instead of overlayfs as that would * for the the upper layer instead of overlayfs as that would
......
...@@ -66,9 +66,32 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode) ...@@ -66,9 +66,32 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
return iint; return iint;
} }
static void iint_free(struct integrity_iint_cache *iint) #define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH+1)
/*
* It is not clear that IMA should be nested at all, but as long is it measures
* files both on overlayfs and on underlying fs, we need to annotate the iint
* mutex to avoid lockdep false positives related to IMA + overlayfs.
* See ovl_lockdep_annotate_inode_mutex_key() for more details.
*/
static inline void iint_lockdep_annotate(struct integrity_iint_cache *iint,
struct inode *inode)
{
#ifdef CONFIG_LOCKDEP
static struct lock_class_key iint_mutex_key[IMA_MAX_NESTING];
int depth = inode->i_sb->s_stack_depth;
if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING))
depth = 0;
lockdep_set_class(&iint->mutex, &iint_mutex_key[depth]);
#endif
}
static void iint_init_always(struct integrity_iint_cache *iint,
struct inode *inode)
{ {
kfree(iint->ima_hash);
iint->ima_hash = NULL; iint->ima_hash = NULL;
iint->version = 0; iint->version = 0;
iint->flags = 0UL; iint->flags = 0UL;
...@@ -80,6 +103,14 @@ static void iint_free(struct integrity_iint_cache *iint) ...@@ -80,6 +103,14 @@ static void iint_free(struct integrity_iint_cache *iint)
iint->ima_creds_status = INTEGRITY_UNKNOWN; iint->ima_creds_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN;
iint->measured_pcrs = 0; iint->measured_pcrs = 0;
mutex_init(&iint->mutex);
iint_lockdep_annotate(iint, inode);
}
static void iint_free(struct integrity_iint_cache *iint)
{
kfree(iint->ima_hash);
mutex_destroy(&iint->mutex);
kmem_cache_free(iint_cache, iint); kmem_cache_free(iint_cache, iint);
} }
...@@ -104,6 +135,8 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode) ...@@ -104,6 +135,8 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
if (!iint) if (!iint)
return NULL; return NULL;
iint_init_always(iint, inode);
write_lock(&integrity_iint_lock); write_lock(&integrity_iint_lock);
p = &integrity_iint_tree.rb_node; p = &integrity_iint_tree.rb_node;
...@@ -153,25 +186,18 @@ void integrity_inode_free(struct inode *inode) ...@@ -153,25 +186,18 @@ void integrity_inode_free(struct inode *inode)
iint_free(iint); iint_free(iint);
} }
static void init_once(void *foo) static void iint_init_once(void *foo)
{ {
struct integrity_iint_cache *iint = (struct integrity_iint_cache *) foo; struct integrity_iint_cache *iint = (struct integrity_iint_cache *) foo;
memset(iint, 0, sizeof(*iint)); memset(iint, 0, sizeof(*iint));
iint->ima_file_status = INTEGRITY_UNKNOWN;
iint->ima_mmap_status = INTEGRITY_UNKNOWN;
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
iint->ima_read_status = INTEGRITY_UNKNOWN;
iint->ima_creds_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
mutex_init(&iint->mutex);
} }
static int __init integrity_iintcache_init(void) static int __init integrity_iintcache_init(void)
{ {
iint_cache = iint_cache =
kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache), kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
0, SLAB_PANIC, init_once); 0, SLAB_PANIC, iint_init_once);
return 0; return 0;
} }
DEFINE_LSM(integrity) = { DEFINE_LSM(integrity) = {
......
...@@ -243,6 +243,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -243,6 +243,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
{ {
const char *audit_cause = "failed"; const char *audit_cause = "failed";
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct inode *real_inode = d_real_inode(file_dentry(file));
const char *filename = file->f_path.dentry->d_name.name; const char *filename = file->f_path.dentry->d_name.name;
struct ima_max_digest_data hash; struct ima_max_digest_data hash;
struct kstat stat; struct kstat stat;
...@@ -302,6 +303,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -302,6 +303,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
iint->ima_hash = tmpbuf; iint->ima_hash = tmpbuf;
memcpy(iint->ima_hash, &hash, length); memcpy(iint->ima_hash, &hash, length);
iint->version = i_version; iint->version = i_version;
if (real_inode != inode) {
iint->real_ino = real_inode->i_ino;
iint->real_dev = real_inode->i_sb->s_dev;
}
/* Possibly temporary failure due to type of read (eg. O_DIRECT) */ /* Possibly temporary failure due to type of read (eg. O_DIRECT) */
if (!result) if (!result)
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/ima.h> #include <linux/ima.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/iversion.h>
#include "ima.h" #include "ima.h"
...@@ -207,7 +208,7 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -207,7 +208,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
u32 secid, char *buf, loff_t size, int mask, u32 secid, char *buf, loff_t size, int mask,
enum ima_hooks func) enum ima_hooks func)
{ {
struct inode *inode = file_inode(file); struct inode *backing_inode, *inode = file_inode(file);
struct integrity_iint_cache *iint = NULL; struct integrity_iint_cache *iint = NULL;
struct ima_template_desc *template_desc = NULL; struct ima_template_desc *template_desc = NULL;
char *pathbuf = NULL; char *pathbuf = NULL;
...@@ -284,6 +285,19 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -284,6 +285,19 @@ static int process_measurement(struct file *file, const struct cred *cred,
iint->measured_pcrs = 0; iint->measured_pcrs = 0;
} }
/* Detect and re-evaluate changes made to the backing file. */
backing_inode = d_real_inode(file_dentry(file));
if (backing_inode != inode &&
(action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
if (!IS_I_VERSION(backing_inode) ||
backing_inode->i_sb->s_dev != iint->real_dev ||
backing_inode->i_ino != iint->real_ino ||
!inode_eq_iversion(backing_inode, iint->version)) {
iint->flags &= ~IMA_DONE_MASK;
iint->measured_pcrs = 0;
}
}
/* Determine if already appraised/measured based on bitmask /* Determine if already appraised/measured based on bitmask
* (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
* IMA_AUDIT, IMA_AUDITED) * IMA_AUDIT, IMA_AUDITED)
......
...@@ -164,6 +164,8 @@ struct integrity_iint_cache { ...@@ -164,6 +164,8 @@ struct integrity_iint_cache {
unsigned long flags; unsigned long flags;
unsigned long measured_pcrs; unsigned long measured_pcrs;
unsigned long atomic_flags; unsigned long atomic_flags;
unsigned long real_ino;
dev_t real_dev;
enum integrity_status ima_file_status:4; enum integrity_status ima_file_status:4;
enum integrity_status ima_mmap_status:4; enum integrity_status ima_mmap_status:4;
enum integrity_status ima_bprm_status:4; enum integrity_status ima_bprm_status:4;
......
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