diff options
Diffstat (limited to 'security')
27 files changed, 192 insertions, 176 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index bd6a910f6528..53a0070ff5df 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -226,7 +226,7 @@ static int __aafs_setup_d_inode(struct inode *dir, struct dentry *dentry, inode->i_ino = get_next_ino(); inode->i_mode = mode; - inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); + simple_inode_init_ts(inode); inode->i_private = data; if (S_ISDIR(mode)) { inode->i_op = iops ? iops : &simple_dir_inode_operations; @@ -1557,7 +1557,8 @@ void __aafs_profile_migrate_dents(struct aa_profile *old, if (new->dents[i]) { struct inode *inode = d_inode(new->dents[i]); - inode->i_mtime = inode_set_ctime_current(inode); + inode_set_mtime_to_ts(inode, + inode_set_ctime_current(inode)); } old->dents[i] = NULL; } @@ -2543,7 +2544,7 @@ static int aa_mk_null_file(struct dentry *parent) inode->i_ino = get_next_ino(); inode->i_mode = S_IFCHR | S_IRUGO | S_IWUGO; - inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); + simple_inode_init_ts(inode); init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3)); d_instantiate(dentry, inode); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 108eccc5ada5..3fa325d5efac 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -734,7 +734,7 @@ fail: * apparmor_bprm_committing_creds - do task cleanup on committing new creds * @bprm: binprm for the exec (NOT NULL) */ -static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) +static void apparmor_bprm_committing_creds(const struct linux_binprm *bprm) { struct aa_label *label = aa_current_raw_label(); struct aa_label *new_label = cred_label(bprm->cred); @@ -756,7 +756,7 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) * apparmor_bprm_committed_creds() - do cleanup after new creds committed * @bprm: binprm for the exec (NOT NULL) */ -static void apparmor_bprm_committed_creds(struct linux_binprm *bprm) +static void apparmor_bprm_committed_creds(const struct linux_binprm *bprm) { /* clear out temporary/transitional state from the context */ aa_clear_task_ctx_trans(task_ctx(current)); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 8b8846073e14..913ec8d0eb63 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -89,10 +89,10 @@ void __aa_loaddata_update(struct aa_loaddata *data, long revision) struct inode *inode; inode = d_inode(data->dents[AAFS_LOADDATA_DIR]); - inode->i_mtime = inode_set_ctime_current(inode); + inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); inode = d_inode(data->dents[AAFS_LOADDATA_REVISION]); - inode->i_mtime = inode_set_ctime_current(inode); + inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); } } diff --git a/security/commoncap.c b/security/commoncap.c index bc0521104197..8e8c630ce204 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -720,7 +720,7 @@ int get_vfs_caps_from_disk(struct mnt_idmap *idmap, * its xattrs and, if present, apply them to the proposed credentials being * constructed by execve(). */ -static int get_file_caps(struct linux_binprm *bprm, struct file *file, +static int get_file_caps(struct linux_binprm *bprm, const struct file *file, bool *effective, bool *has_fcap) { int rc = 0; @@ -882,7 +882,7 @@ static inline bool nonroot_raised_pE(struct cred *new, const struct cred *old, * * Return: 0 if successful, -ve on error. */ -int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) +int cap_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file) { /* Process setpcap binaries and capabilities for uid 0 */ const struct cred *old = current_cred(); diff --git a/security/inode.c b/security/inode.c index 3aa75fffa8c9..9e7cde913667 100644 --- a/security/inode.c +++ b/security/inode.c @@ -145,7 +145,7 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode, inode->i_ino = get_next_ino(); inode->i_mode = mode; - inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); + simple_inode_init_ts(inode); inode->i_private = data; if (S_ISDIR(mode)) { inode->i_op = &simple_dir_inode_operations; diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 232191ee09e3..3c45f4f3455f 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -34,10 +34,10 @@ config INTEGRITY_ASYMMETRIC_KEYS bool "Enable asymmetric keys support" depends on INTEGRITY_SIGNATURE default n - select ASYMMETRIC_KEY_TYPE - select ASYMMETRIC_PUBLIC_KEY_SUBTYPE - select CRYPTO_RSA - select X509_CERTIFICATE_PARSER + select ASYMMETRIC_KEY_TYPE + select ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select CRYPTO_RSA + select X509_CERTIFICATE_PARSER help This option enables digital signature verification using asymmetric keys. @@ -53,14 +53,14 @@ config INTEGRITY_TRUSTED_KEYRING keyring. config INTEGRITY_PLATFORM_KEYRING - bool "Provide keyring for platform/firmware trusted keys" - depends on INTEGRITY_ASYMMETRIC_KEYS - depends on SYSTEM_BLACKLIST_KEYRING - help - Provide a separate, distinct keyring for platform trusted keys, which - the kernel automatically populates during initialization from values - provided by the platform for verifying the kexec'ed kerned image - and, possibly, the initramfs signature. + bool "Provide keyring for platform/firmware trusted keys" + depends on INTEGRITY_ASYMMETRIC_KEYS + depends on SYSTEM_BLACKLIST_KEYRING + help + Provide a separate, distinct keyring for platform trusted keys, which + the kernel automatically populates during initialization from values + provided by the platform for verifying the kexec'ed kerned image + and, possibly, the initramfs signature. config INTEGRITY_MACHINE_KEYRING bool "Provide a keyring to which Machine Owner Keys may be added" @@ -68,13 +68,11 @@ config INTEGRITY_MACHINE_KEYRING depends on INTEGRITY_ASYMMETRIC_KEYS depends on SYSTEM_BLACKLIST_KEYRING depends on LOAD_UEFI_KEYS || LOAD_PPC_KEYS - select INTEGRITY_CA_MACHINE_KEYRING if LOAD_PPC_KEYS - select INTEGRITY_CA_MACHINE_KEYRING_MAX if LOAD_PPC_KEYS help - If set, provide a keyring to which Machine Owner Keys (MOK) may - be added. This keyring shall contain just MOK keys. Unlike keys - in the platform keyring, keys contained in the .machine keyring will - be trusted within the kernel. + If set, provide a keyring to which Machine Owner Keys (MOK) may + be added. This keyring shall contain just MOK keys. Unlike keys + in the platform keyring, keys contained in the .machine keyring will + be trusted within the kernel. config INTEGRITY_CA_MACHINE_KEYRING bool "Enforce Machine Keyring CA Restrictions" @@ -99,14 +97,14 @@ config INTEGRITY_CA_MACHINE_KEYRING_MAX .platform keyring. config LOAD_UEFI_KEYS - depends on INTEGRITY_PLATFORM_KEYRING - depends on EFI - def_bool y + depends on INTEGRITY_PLATFORM_KEYRING + depends on EFI + def_bool y config LOAD_IPL_KEYS - depends on INTEGRITY_PLATFORM_KEYRING - depends on S390 - def_bool y + depends on INTEGRITY_PLATFORM_KEYRING + depends on S390 + def_bool y config LOAD_PPC_KEYS bool "Enable loading of platform and blacklisted keys for POWER" diff --git a/security/integrity/iint.c b/security/integrity/iint.c index a462df827de2..27ea19fb1f54 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -66,9 +66,32 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode) 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->version = 0; iint->flags = 0UL; @@ -80,6 +103,14 @@ static void iint_free(struct integrity_iint_cache *iint) iint->ima_creds_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; 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); } @@ -104,6 +135,8 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode) if (!iint) return NULL; + iint_init_always(iint, inode); + write_lock(&integrity_iint_lock); p = &integrity_iint_tree.rb_node; @@ -153,25 +186,18 @@ void integrity_inode_free(struct inode *inode) 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; 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) { 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; } DEFINE_LSM(integrity) = { diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index ecddc807c536..a6bd817efc1a 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -29,9 +29,11 @@ config IMA to learn more about IMA. If unsure, say N. +if IMA + config IMA_KEXEC bool "Enable carrying the IMA measurement list across a soft boot" - depends on IMA && TCG_TPM && HAVE_IMA_KEXEC + depends on TCG_TPM && HAVE_IMA_KEXEC default n help TPM PCRs are only reset on a hard reboot. In order to validate @@ -43,7 +45,6 @@ config IMA_KEXEC config IMA_MEASURE_PCR_IDX int - depends on IMA range 8 14 default 10 help @@ -53,7 +54,7 @@ config IMA_MEASURE_PCR_IDX config IMA_LSM_RULES bool - depends on IMA && AUDIT && (SECURITY_SELINUX || SECURITY_SMACK || SECURITY_APPARMOR) + depends on AUDIT && (SECURITY_SELINUX || SECURITY_SMACK || SECURITY_APPARMOR) default y help Disabling this option will disregard LSM based policy rules. @@ -61,7 +62,6 @@ config IMA_LSM_RULES choice prompt "Default template" default IMA_NG_TEMPLATE - depends on IMA help Select the default IMA measurement template. @@ -80,14 +80,12 @@ endchoice config IMA_DEFAULT_TEMPLATE string - depends on IMA default "ima-ng" if IMA_NG_TEMPLATE default "ima-sig" if IMA_SIG_TEMPLATE choice prompt "Default integrity hash algorithm" default IMA_DEFAULT_HASH_SHA1 - depends on IMA help Select the default hash algorithm used for the measurement list, integrity appraisal and audit log. The compiled default @@ -117,7 +115,6 @@ endchoice config IMA_DEFAULT_HASH string - depends on IMA default "sha1" if IMA_DEFAULT_HASH_SHA1 default "sha256" if IMA_DEFAULT_HASH_SHA256 default "sha512" if IMA_DEFAULT_HASH_SHA512 @@ -126,7 +123,6 @@ config IMA_DEFAULT_HASH config IMA_WRITE_POLICY bool "Enable multiple writes to the IMA policy" - depends on IMA default n help IMA policy can now be updated multiple times. The new rules get @@ -137,7 +133,6 @@ config IMA_WRITE_POLICY config IMA_READ_POLICY bool "Enable reading back the current IMA policy" - depends on IMA default y if IMA_WRITE_POLICY default n if !IMA_WRITE_POLICY help @@ -147,7 +142,6 @@ config IMA_READ_POLICY config IMA_APPRAISE bool "Appraise integrity measurements" - depends on IMA default n help This option enables local measurement integrity appraisal. @@ -269,7 +263,7 @@ config IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY config IMA_BLACKLIST_KEYRING bool "Create IMA machine owner blacklist keyrings (EXPERIMENTAL)" depends on SYSTEM_TRUSTED_KEYRING - depends on IMA_TRUSTED_KEYRING + depends on INTEGRITY_TRUSTED_KEYRING default n help This option creates an IMA blacklist keyring, which contains all @@ -279,7 +273,7 @@ config IMA_BLACKLIST_KEYRING config IMA_LOAD_X509 bool "Load X509 certificate onto the '.ima' trusted keyring" - depends on IMA_TRUSTED_KEYRING + depends on INTEGRITY_TRUSTED_KEYRING default n help File signature verification is based on the public keys @@ -304,7 +298,6 @@ config IMA_APPRAISE_SIGNED_INIT config IMA_MEASURE_ASYMMETRIC_KEYS bool - depends on IMA depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y default y @@ -323,7 +316,8 @@ config IMA_SECURE_AND_OR_TRUSTED_BOOT config IMA_DISABLE_HTABLE bool "Disable htable to allow measurement of duplicate records" - depends on IMA default n help This option disables htable to allow measurement of duplicate records. + +endif diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 452e80b541e5..597ea0c4d72f 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -243,6 +243,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, { const char *audit_cause = "failed"; 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; struct ima_max_digest_data hash; struct kstat stat; @@ -302,6 +303,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, iint->ima_hash = tmpbuf; memcpy(iint->ima_hash, &hash, length); 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) */ if (!result) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 365db0e43d7c..cc1217ac2c6f 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -25,6 +25,7 @@ #include <linux/xattr.h> #include <linux/ima.h> #include <linux/fs.h> +#include <linux/iversion.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, 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 ima_template_desc *template_desc = NULL; char *pathbuf = NULL; @@ -284,6 +285,19 @@ static int process_measurement(struct file *file, const struct cred *cred, 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 * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, * IMA_AUDIT, IMA_AUDITED) diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c index 3e7bee30080f..3265d744d5ce 100644 --- a/security/integrity/ima/ima_modsig.c +++ b/security/integrity/ima/ima_modsig.c @@ -29,7 +29,7 @@ struct modsig { * storing the signature. */ int raw_pkcs7_len; - u8 raw_pkcs7[]; + u8 raw_pkcs7[] __counted_by(raw_pkcs7_len); }; /* @@ -65,10 +65,11 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, buf_len -= sig_len + sizeof(*sig); /* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */ - hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL); + hdr = kzalloc(struct_size(hdr, raw_pkcs7, sig_len), GFP_KERNEL); if (!hdr) return -ENOMEM; + hdr->raw_pkcs7_len = sig_len; hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len); if (IS_ERR(hdr->pkcs7_msg)) { rc = PTR_ERR(hdr->pkcs7_msg); @@ -77,7 +78,6 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, } memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len); - hdr->raw_pkcs7_len = sig_len; /* We don't know the hash algorithm yet. */ hdr->hash_algo = HASH_ALGO__LAST; diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index d7553c93f5c0..9561db7cf6b4 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -164,6 +164,8 @@ struct integrity_iint_cache { unsigned long flags; unsigned long measured_pcrs; unsigned long atomic_flags; + unsigned long real_ino; + dev_t real_dev; enum integrity_status ima_file_status:4; enum integrity_status ima_mmap_status:4; enum integrity_status ima_bprm_status:4; diff --git a/security/keys/internal.h b/security/keys/internal.h index 3c1e7122076b..471cf36dedc0 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -109,13 +109,6 @@ extern void __key_link_end(struct key *keyring, extern key_ref_t find_key_to_update(key_ref_t keyring_ref, const struct keyring_index_key *index_key); -extern struct key *keyring_search_instkey(struct key *keyring, - key_serial_t target_id); - -extern int iterate_over_keyring(const struct key *keyring, - int (*func)(const struct key *key, void *data), - void *data); - struct keyring_search_context { struct keyring_index_key index_key; const struct cred *cred; diff --git a/security/keys/key.c b/security/keys/key.c index 5c0c7df833f8..0260a1902922 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -693,6 +693,7 @@ error: spin_unlock(&key_serial_lock); return key; } +EXPORT_SYMBOL(key_lookup); /* * Find and lock the specified key type against removal. diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c index c6fc50d67214..fee1ab2c734d 100644 --- a/security/keys/trusted-keys/trusted_core.c +++ b/security/keys/trusted-keys/trusted_core.c @@ -44,13 +44,12 @@ static const struct trusted_key_source trusted_key_sources[] = { #endif }; -DEFINE_STATIC_CALL_NULL(trusted_key_init, *trusted_key_sources[0].ops->init); DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->seal); DEFINE_STATIC_CALL_NULL(trusted_key_unseal, *trusted_key_sources[0].ops->unseal); DEFINE_STATIC_CALL_NULL(trusted_key_get_random, *trusted_key_sources[0].ops->get_random); -DEFINE_STATIC_CALL_NULL(trusted_key_exit, *trusted_key_sources[0].ops->exit); +static void (*trusted_key_exit)(void); static unsigned char migratable; enum { @@ -359,20 +358,17 @@ static int __init init_trusted(void) if (!get_random) get_random = kernel_get_random; - static_call_update(trusted_key_init, - trusted_key_sources[i].ops->init); - static_call_update(trusted_key_seal, - trusted_key_sources[i].ops->seal); - static_call_update(trusted_key_unseal, - trusted_key_sources[i].ops->unseal); - static_call_update(trusted_key_get_random, - get_random); - static_call_update(trusted_key_exit, - trusted_key_sources[i].ops->exit); - migratable = trusted_key_sources[i].ops->migratable; - - ret = static_call(trusted_key_init)(); - if (!ret) + ret = trusted_key_sources[i].ops->init(); + if (!ret) { + static_call_update(trusted_key_seal, trusted_key_sources[i].ops->seal); + static_call_update(trusted_key_unseal, trusted_key_sources[i].ops->unseal); + static_call_update(trusted_key_get_random, get_random); + + trusted_key_exit = trusted_key_sources[i].ops->exit; + migratable = trusted_key_sources[i].ops->migratable; + } + + if (!ret || ret != -ENODEV) break; } @@ -388,7 +384,8 @@ static int __init init_trusted(void) static void __exit cleanup_trusted(void) { - static_call_cond(trusted_key_exit)(); + if (trusted_key_exit) + (*trusted_key_exit)(); } late_initcall(init_trusted); diff --git a/security/keys/trusted-keys/trusted_tee.c b/security/keys/trusted-keys/trusted_tee.c index ac3e270ade69..aa3d477de6db 100644 --- a/security/keys/trusted-keys/trusted_tee.c +++ b/security/keys/trusted-keys/trusted_tee.c @@ -65,24 +65,16 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob) int ret; struct tee_ioctl_invoke_arg inv_arg; struct tee_param param[4]; - struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL; + struct tee_shm *reg_shm = NULL; memset(&inv_arg, 0, sizeof(inv_arg)); memset(¶m, 0, sizeof(param)); - reg_shm_in = tee_shm_register_kernel_buf(pvt_data.ctx, p->key, - p->key_len); - if (IS_ERR(reg_shm_in)) { - dev_err(pvt_data.dev, "key shm register failed\n"); - return PTR_ERR(reg_shm_in); - } - - reg_shm_out = tee_shm_register_kernel_buf(pvt_data.ctx, p->blob, - sizeof(p->blob)); - if (IS_ERR(reg_shm_out)) { - dev_err(pvt_data.dev, "blob shm register failed\n"); - ret = PTR_ERR(reg_shm_out); - goto out; + reg_shm = tee_shm_register_kernel_buf(pvt_data.ctx, p->key, + sizeof(p->key) + sizeof(p->blob)); + if (IS_ERR(reg_shm)) { + dev_err(pvt_data.dev, "shm register failed\n"); + return PTR_ERR(reg_shm); } inv_arg.func = TA_CMD_SEAL; @@ -90,13 +82,13 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob) inv_arg.num_params = 4; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; - param[0].u.memref.shm = reg_shm_in; + param[0].u.memref.shm = reg_shm; param[0].u.memref.size = p->key_len; param[0].u.memref.shm_offs = 0; param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; - param[1].u.memref.shm = reg_shm_out; + param[1].u.memref.shm = reg_shm; param[1].u.memref.size = sizeof(p->blob); - param[1].u.memref.shm_offs = 0; + param[1].u.memref.shm_offs = sizeof(p->key); ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param); if ((ret < 0) || (inv_arg.ret != 0)) { @@ -107,11 +99,7 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob) p->blob_len = param[1].u.memref.size; } -out: - if (reg_shm_out) - tee_shm_free(reg_shm_out); - if (reg_shm_in) - tee_shm_free(reg_shm_in); + tee_shm_free(reg_shm); return ret; } @@ -124,24 +112,16 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob) int ret; struct tee_ioctl_invoke_arg inv_arg; struct tee_param param[4]; - struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL; + struct tee_shm *reg_shm = NULL; memset(&inv_arg, 0, sizeof(inv_arg)); memset(¶m, 0, sizeof(param)); - reg_shm_in = tee_shm_register_kernel_buf(pvt_data.ctx, p->blob, - p->blob_len); - if (IS_ERR(reg_shm_in)) { - dev_err(pvt_data.dev, "blob shm register failed\n"); - return PTR_ERR(reg_shm_in); - } - - reg_shm_out = tee_shm_register_kernel_buf(pvt_data.ctx, p->key, - sizeof(p->key)); - if (IS_ERR(reg_shm_out)) { - dev_err(pvt_data.dev, "key shm register failed\n"); - ret = PTR_ERR(reg_shm_out); - goto out; + reg_shm = tee_shm_register_kernel_buf(pvt_data.ctx, p->key, + sizeof(p->key) + sizeof(p->blob)); + if (IS_ERR(reg_shm)) { + dev_err(pvt_data.dev, "shm register failed\n"); + return PTR_ERR(reg_shm); } inv_arg.func = TA_CMD_UNSEAL; @@ -149,11 +129,11 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob) inv_arg.num_params = 4; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; - param[0].u.memref.shm = reg_shm_in; + param[0].u.memref.shm = reg_shm; param[0].u.memref.size = p->blob_len; - param[0].u.memref.shm_offs = 0; + param[0].u.memref.shm_offs = sizeof(p->key); param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; - param[1].u.memref.shm = reg_shm_out; + param[1].u.memref.shm = reg_shm; param[1].u.memref.size = sizeof(p->key); param[1].u.memref.shm_offs = 0; @@ -166,11 +146,7 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob) p->key_len = param[1].u.memref.size; } -out: - if (reg_shm_out) - tee_shm_free(reg_shm_out); - if (reg_shm_in) - tee_shm_free(reg_shm_in); + tee_shm_free(reg_shm); return ret; } diff --git a/security/security.c b/security/security.c index 23b129d482a7..dcb3e7014f9b 100644 --- a/security/security.c +++ b/security/security.c @@ -957,7 +957,7 @@ int security_capable(const struct cred *cred, * * Return: Returns 0 if permission is granted. */ -int security_quotactl(int cmds, int type, int id, struct super_block *sb) +int security_quotactl(int cmds, int type, int id, const struct super_block *sb) { return call_int_hook(quotactl, 0, cmds, type, id, sb); } @@ -1079,7 +1079,7 @@ int security_bprm_creds_for_exec(struct linux_binprm *bprm) * * Return: Returns 0 if the hook is successful and permission is granted. */ -int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) +int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file) { return call_int_hook(bprm_creds_from_file, 0, bprm, file); } @@ -1118,7 +1118,7 @@ int security_bprm_check(struct linux_binprm *bprm) * open file descriptors to which access will no longer be granted when the * attributes are changed. This is called immediately before commit_creds(). */ -void security_bprm_committing_creds(struct linux_binprm *bprm) +void security_bprm_committing_creds(const struct linux_binprm *bprm) { call_void_hook(bprm_committing_creds, bprm); } @@ -1134,7 +1134,7 @@ void security_bprm_committing_creds(struct linux_binprm *bprm) * process such as clearing out non-inheritable signal state. This is called * immediately after commit_creds(). */ -void security_bprm_committed_creds(struct linux_binprm *bprm) +void security_bprm_committed_creds(const struct linux_binprm *bprm) { call_void_hook(bprm_committed_creds, bprm); } @@ -1319,7 +1319,7 @@ EXPORT_SYMBOL(security_sb_remount); * * Return: Returns 0 if permission is granted. */ -int security_sb_kern_mount(struct super_block *sb) +int security_sb_kern_mount(const struct super_block *sb) { return call_int_hook(sb_kern_mount, 0, sb); } @@ -3957,7 +3957,7 @@ void security_inode_invalidate_secctx(struct inode *inode) EXPORT_SYMBOL(security_inode_invalidate_secctx); /** - * security_inode_notifysecctx() - Nofify the LSM of an inode's security label + * security_inode_notifysecctx() - Notify the LSM of an inode's security label * @inode: inode * @ctx: secctx * @ctxlen: length of secctx diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index d30348fbe0df..61abc1e094a8 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -77,3 +77,13 @@ config SECURITY_SELINUX_DEBUG This enables debugging code designed to help SELinux kernel developers, unless you know what this does in the kernel code you should leave this disabled. + + To fine control the messages to be printed enable + CONFIG_DYNAMIC_DEBUG and see + Documentation/admin-guide/dynamic-debug-howto.rst for additional + information. + + Example usage: + + echo -n 'file "security/selinux/*" +p' > \ + /proc/dynamic_debug/control diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 836379639058..c47519ed8156 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -12,6 +12,8 @@ obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include +ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG + selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ netnode.o netport.o status.o \ ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 10350534de6d..feda711c6b7b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1937,7 +1937,7 @@ static inline int may_rename(struct inode *old_dir, /* Check whether a task can perform a filesystem operation. */ static int superblock_has_perm(const struct cred *cred, - struct super_block *sb, + const struct super_block *sb, u32 perms, struct common_audit_data *ad) { @@ -2139,7 +2139,7 @@ static int selinux_capable(const struct cred *cred, struct user_namespace *ns, return cred_has_capability(cred, cap, opts, ns == &init_user_ns); } -static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) +static int selinux_quotactl(int cmds, int type, int id, const struct super_block *sb) { const struct cred *cred = current_cred(); int rc = 0; @@ -2455,7 +2455,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, /* * Prepare a process for imminent new credential changes due to exec */ -static void selinux_bprm_committing_creds(struct linux_binprm *bprm) +static void selinux_bprm_committing_creds(const struct linux_binprm *bprm) { struct task_security_struct *new_tsec; struct rlimit *rlim, *initrlim; @@ -2501,7 +2501,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) * Clean up the process immediately after the installation of new credentials * due to exec */ -static void selinux_bprm_committed_creds(struct linux_binprm *bprm) +static void selinux_bprm_committed_creds(const struct linux_binprm *bprm) { const struct task_security_struct *tsec = selinux_cred(current_cred()); u32 osid, sid; @@ -2721,7 +2721,7 @@ out_bad_option: return -EINVAL; } -static int selinux_sb_kern_mount(struct super_block *sb) +static int selinux_sb_kern_mount(const struct super_block *sb) { const struct cred *cred = current_cred(); struct common_audit_data ad; @@ -2775,14 +2775,20 @@ static int selinux_umount(struct vfsmount *mnt, int flags) static int selinux_fs_context_submount(struct fs_context *fc, struct super_block *reference) { - const struct superblock_security_struct *sbsec; + const struct superblock_security_struct *sbsec = selinux_superblock(reference); struct selinux_mnt_opts *opts; + /* + * Ensure that fc->security remains NULL when no options are set + * as expected by selinux_set_mnt_opts(). + */ + if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT))) + return 0; + opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return -ENOMEM; - sbsec = selinux_superblock(reference); if (sbsec->flags & FSCONTEXT_MNT) opts->fscontext_sid = sbsec->sid; if (sbsec->flags & CONTEXT_MNT) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 6fa640263216..6c596ae7fef9 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1198,7 +1198,7 @@ static struct inode *sel_make_inode(struct super_block *sb, umode_t mode) if (ret) { ret->i_mode = mode; - ret->i_atime = ret->i_mtime = inode_set_ctime_current(ret); + simple_inode_init_ts(ret); } return ret; } diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 86d98a8e291b..8751a602ead2 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -17,6 +17,7 @@ * Tuned number of hash slots for avtab to reduce memory usage */ +#include <linux/bitops.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/errno.h> @@ -66,8 +67,7 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask) } static struct avtab_node* -avtab_insert_node(struct avtab *h, u32 hvalue, - struct avtab_node *prev, +avtab_insert_node(struct avtab *h, struct avtab_node **dst, const struct avtab_key *key, const struct avtab_datum *datum) { struct avtab_node *newnode; @@ -89,15 +89,8 @@ avtab_insert_node(struct avtab *h, u32 hvalue, newnode->datum.u.data = datum->u.data; } - if (prev) { - newnode->next = prev->next; - prev->next = newnode; - } else { - struct avtab_node **n = &h->htable[hvalue]; - - newnode->next = *n; - *n = newnode; - } + newnode->next = *dst; + *dst = newnode; h->nel++; return newnode; @@ -137,7 +130,8 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key, break; } - newnode = avtab_insert_node(h, hvalue, prev, key, datum); + newnode = avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue], + key, datum); if (!newnode) return -ENOMEM; @@ -177,7 +171,8 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h, key->target_class < cur->key.target_class) break; } - return avtab_insert_node(h, hvalue, prev, key, datum); + return avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue], + key, datum); } /* This search function returns a node pointer, and can be used in @@ -298,13 +293,7 @@ int avtab_alloc(struct avtab *h, u32 nrules) u32 nslot = 0; if (nrules != 0) { - u32 shift = 1; - u32 work = nrules >> 3; - while (work) { - work >>= 1; - shift++; - } - nslot = 1 << shift; + nslot = nrules > 3 ? rounddown_pow_of_two(nrules / 2) : 2; if (nslot > MAX_AVTAB_HASH_BUCKETS) nslot = MAX_AVTAB_HASH_BUCKETS; @@ -349,7 +338,7 @@ void avtab_hash_eval(struct avtab *h, const char *tag) } pr_debug("SELinux: %s: %d entries and %d/%d buckets used, " - "longest chain length %d sum of chain length^2 %llu\n", + "longest chain length %d, sum of chain length^2 %llu\n", tag, h->nel, slots_used, h->nslot, max_chain_len, chain2_len_sum); } @@ -477,11 +466,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return -EINVAL; } - set = 0; - for (i = 0; i < ARRAY_SIZE(spec_order); i++) { - if (key.specified & spec_order[i]) - set++; - } + set = hweight16(key.specified & (AVTAB_XPERMS | AVTAB_TYPE | AVTAB_AV)); if (!set || set > 1) { pr_err("SELinux: avtab: more than one specifier\n"); return -EINVAL; diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index ac5cdddfbf78..c05d8346a94a 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -107,10 +107,12 @@ int hashtab_map(struct hashtab *h, void hashtab_stat(struct hashtab *h, struct hashtab_info *info) { u32 i, chain_len, slots_used, max_chain_len; + u64 chain2_len_sum; struct hashtab_node *cur; slots_used = 0; max_chain_len = 0; + chain2_len_sum = 0; for (i = 0; i < h->size; i++) { cur = h->htable[i]; if (cur) { @@ -123,11 +125,14 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info) if (chain_len > max_chain_len) max_chain_len = chain_len; + + chain2_len_sum += (u64)chain_len * chain_len; } } info->slots_used = slots_used; info->max_chain_len = max_chain_len; + info->chain2_len_sum = chain2_len_sum; } #endif /* CONFIG_SECURITY_SELINUX_DEBUG */ diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h index f9713b56d3d0..09b0a3744937 100644 --- a/security/selinux/ss/hashtab.h +++ b/security/selinux/ss/hashtab.h @@ -38,6 +38,7 @@ struct hashtab { struct hashtab_info { u32 slots_used; u32 max_chain_len; + u64 chain2_len_sum; }; /* diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 2d528f699a22..595a435ea9c8 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -491,7 +491,7 @@ static u32 role_trans_hash(const void *k) { const struct role_trans_key *key = k; - return key->role + (key->type << 3) + (key->tclass << 5); + return jhash_3words(key->role, key->type, (u32)key->tclass << 16 | key->tclass, 0); } static int role_trans_cmp(const void *k1, const void *k2) @@ -684,9 +684,9 @@ static void hash_eval(struct hashtab *h, const char *hash_name) struct hashtab_info info; hashtab_stat(h, &info); - pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n", + pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n", hash_name, h->nel, info.slots_used, h->size, - info.max_chain_len); + info.max_chain_len, info.chain2_len_sum); } static void symtab_hash_eval(struct symtab *s) diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index d8ead463b8df..732fd8e22a12 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -25,7 +25,7 @@ struct sidtab_str_cache { struct list_head lru_member; struct sidtab_entry *parent; u32 len; - char str[]; + char str[] __counted_by(len); }; #define index_to_sid(index) ((index) + SECINITSID_NUM + 1) diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 25006fddc964..255f1b470295 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -52,7 +52,7 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, * * @bprm: Pointer to "struct linux_binprm". */ -static void tomoyo_bprm_committed_creds(struct linux_binprm *bprm) +static void tomoyo_bprm_committed_creds(const struct linux_binprm *bprm) { /* Clear old_domain_info saved by execve() request. */ struct tomoyo_task *s = tomoyo_task(current); |