summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/apparmorfs.c7
-rw-r--r--security/apparmor/lsm.c4
-rw-r--r--security/apparmor/policy_unpack.c4
-rw-r--r--security/commoncap.c4
-rw-r--r--security/inode.c2
-rw-r--r--security/integrity/Kconfig46
-rw-r--r--security/integrity/iint.c48
-rw-r--r--security/integrity/ima/Kconfig22
-rw-r--r--security/integrity/ima/ima_api.c5
-rw-r--r--security/integrity/ima/ima_main.c16
-rw-r--r--security/integrity/ima/ima_modsig.c6
-rw-r--r--security/integrity/integrity.h2
-rw-r--r--security/keys/internal.h7
-rw-r--r--security/keys/key.c1
-rw-r--r--security/keys/trusted-keys/trusted_core.c31
-rw-r--r--security/keys/trusted-keys/trusted_tee.c64
-rw-r--r--security/security.c12
-rw-r--r--security/selinux/Kconfig10
-rw-r--r--security/selinux/Makefile2
-rw-r--r--security/selinux/hooks.c20
-rw-r--r--security/selinux/selinuxfs.c2
-rw-r--r--security/selinux/ss/avtab.c37
-rw-r--r--security/selinux/ss/hashtab.c5
-rw-r--r--security/selinux/ss/hashtab.h1
-rw-r--r--security/selinux/ss/policydb.c6
-rw-r--r--security/selinux/ss/sidtab.c2
-rw-r--r--security/tomoyo/tomoyo.c2
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(&param, 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(&param, 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);