integrity-v6.7

-----BEGIN PGP SIGNATURE-----
 
 iIoEABYIADIWIQQdXVVFGN5XqKr1Hj7LwZzRsCrn5QUCZUDyWhQcem9oYXJAbGlu
 dXguaWJtLmNvbQAKCRDLwZzRsCrn5QtIAPwLSdHw2qix1A6lMhbRiXqFOWINHcTF
 DMtZkiPmpeuTKAEA0KaXfddKq5OC5S/ixPEEZCVqOq2ixxfMDhudyoh/qQs=
 =lh3g
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2023-11-02 06:53:22 -10:00
commit ca219be012
8 changed files with 101 additions and 36 deletions

View file

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

View file

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

View file

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

View file

@ -34,10 +34,10 @@ config INTEGRITY_ASYMMETRIC_KEYS
bool "Enable asymmetric keys support" bool "Enable asymmetric keys support"
depends on INTEGRITY_SIGNATURE depends on INTEGRITY_SIGNATURE
default n default n
select ASYMMETRIC_KEY_TYPE select ASYMMETRIC_KEY_TYPE
select ASYMMETRIC_PUBLIC_KEY_SUBTYPE select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select CRYPTO_RSA select CRYPTO_RSA
select X509_CERTIFICATE_PARSER select X509_CERTIFICATE_PARSER
help help
This option enables digital signature verification using This option enables digital signature verification using
asymmetric keys. asymmetric keys.
@ -53,14 +53,14 @@ config INTEGRITY_TRUSTED_KEYRING
keyring. keyring.
config INTEGRITY_PLATFORM_KEYRING config INTEGRITY_PLATFORM_KEYRING
bool "Provide keyring for platform/firmware trusted keys" bool "Provide keyring for platform/firmware trusted keys"
depends on INTEGRITY_ASYMMETRIC_KEYS depends on INTEGRITY_ASYMMETRIC_KEYS
depends on SYSTEM_BLACKLIST_KEYRING depends on SYSTEM_BLACKLIST_KEYRING
help help
Provide a separate, distinct keyring for platform trusted keys, which Provide a separate, distinct keyring for platform trusted keys, which
the kernel automatically populates during initialization from values the kernel automatically populates during initialization from values
provided by the platform for verifying the kexec'ed kerned image provided by the platform for verifying the kexec'ed kerned image
and, possibly, the initramfs signature. and, possibly, the initramfs signature.
config INTEGRITY_MACHINE_KEYRING config INTEGRITY_MACHINE_KEYRING
bool "Provide a keyring to which Machine Owner Keys may be added" bool "Provide a keyring to which Machine Owner Keys may be added"
@ -69,10 +69,10 @@ config INTEGRITY_MACHINE_KEYRING
depends on SYSTEM_BLACKLIST_KEYRING depends on SYSTEM_BLACKLIST_KEYRING
depends on LOAD_UEFI_KEYS || LOAD_PPC_KEYS depends on LOAD_UEFI_KEYS || LOAD_PPC_KEYS
help help
If set, provide a keyring to which Machine Owner Keys (MOK) may If set, provide a keyring to which Machine Owner Keys (MOK) may
be added. This keyring shall contain just MOK keys. Unlike keys be added. This keyring shall contain just MOK keys. Unlike keys
in the platform keyring, keys contained in the .machine keyring will in the platform keyring, keys contained in the .machine keyring will
be trusted within the kernel. be trusted within the kernel.
config INTEGRITY_CA_MACHINE_KEYRING config INTEGRITY_CA_MACHINE_KEYRING
bool "Enforce Machine Keyring CA Restrictions" bool "Enforce Machine Keyring CA Restrictions"
@ -97,14 +97,14 @@ config INTEGRITY_CA_MACHINE_KEYRING_MAX
.platform keyring. .platform keyring.
config LOAD_UEFI_KEYS config LOAD_UEFI_KEYS
depends on INTEGRITY_PLATFORM_KEYRING depends on INTEGRITY_PLATFORM_KEYRING
depends on EFI depends on EFI
def_bool y def_bool y
config LOAD_IPL_KEYS config LOAD_IPL_KEYS
depends on INTEGRITY_PLATFORM_KEYRING depends on INTEGRITY_PLATFORM_KEYRING
depends on S390 depends on S390
def_bool y def_bool y
config LOAD_PPC_KEYS config LOAD_PPC_KEYS
bool "Enable loading of platform and blacklisted keys for POWER" bool "Enable loading of platform and blacklisted keys for POWER"

View file

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

View file

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

View file

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

View file

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