aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig.hardening10
-rw-r--r--security/device_cgroup.c2
-rw-r--r--security/integrity/Kconfig13
-rw-r--r--security/integrity/Makefile1
-rw-r--r--security/integrity/digsig.c15
-rw-r--r--security/integrity/evm/evm_main.c2
-rw-r--r--security/integrity/ima/ima_api.c12
-rw-r--r--security/integrity/ima/ima_fs.c31
-rw-r--r--security/integrity/ima/ima_init.c5
-rw-r--r--security/integrity/ima/ima_main.c66
-rw-r--r--security/integrity/ima/ima_policy.c5
-rw-r--r--security/integrity/ima/ima_template_lib.c7
-rw-r--r--security/integrity/integrity.h31
-rw-r--r--security/integrity/platform_certs/keyring_handler.c18
-rw-r--r--security/integrity/platform_certs/keyring_handler.h5
-rw-r--r--security/integrity/platform_certs/load_uefi.c4
-rw-r--r--security/integrity/platform_certs/machine_keyring.c77
-rw-r--r--security/keys/Kconfig19
-rw-r--r--security/keys/dh.c2
-rw-r--r--security/keys/encrypted-keys/encrypted.c71
-rw-r--r--security/keys/keyctl_pkey.c14
-rw-r--r--security/keys/trusted-keys/trusted_core.c6
-rw-r--r--security/keys/trusted-keys/trusted_tee.c23
-rw-r--r--security/security.c24
-rw-r--r--security/selinux/hooks.c299
-rw-r--r--security/selinux/ibpkey.c2
-rw-r--r--security/selinux/ima.c4
-rw-r--r--security/selinux/include/policycap.h21
-rw-r--r--security/selinux/include/policycap_names.h5
-rw-r--r--security/selinux/include/security.h31
-rw-r--r--security/selinux/netnode.c9
-rw-r--r--security/selinux/netport.c2
-rw-r--r--security/selinux/nlmsgtab.c6
-rw-r--r--security/selinux/selinuxfs.c4
-rw-r--r--security/selinux/ss/avtab.c6
-rw-r--r--security/selinux/ss/conditional.c2
-rw-r--r--security/selinux/ss/ebitmap.c1
-rw-r--r--security/selinux/ss/ebitmap.h6
-rw-r--r--security/selinux/ss/mls.c1
-rw-r--r--security/selinux/ss/policydb.c4
-rw-r--r--security/selinux/ss/services.c10
-rw-r--r--security/selinux/ss/sidtab.c4
-rw-r--r--security/selinux/xfrm.c2
-rw-r--r--security/smack/smack_lsm.c2
-rw-r--r--security/tomoyo/load_policy.c4
45 files changed, 565 insertions, 323 deletions
diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening
index d051f8ceefdd..ded4d7c0d132 100644
--- a/security/Kconfig.hardening
+++ b/security/Kconfig.hardening
@@ -174,6 +174,16 @@ config GCC_PLUGIN_STACKLEAK
* https://grsecurity.net/
* https://pax.grsecurity.net/
+config GCC_PLUGIN_STACKLEAK_VERBOSE
+ bool "Report stack depth analysis instrumentation" if EXPERT
+ depends on GCC_PLUGIN_STACKLEAK
+ depends on !COMPILE_TEST # too noisy
+ help
+ This option will cause a warning to be printed each time the
+ stackleak plugin finds a function it thinks needs to be
+ instrumented. This is useful for comparing coverage between
+ builds.
+
config STACKLEAK_TRACK_MIN_SIZE
int "Minimum stack frame size of functions tracked by STACKLEAK"
default 100
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 842889f3dcb7..a9f8c63a96d1 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -838,7 +838,7 @@ int devcgroup_check_permission(short type, u32 major, u32 minor, short access)
int rc = BPF_CGROUP_RUN_PROG_DEVICE_CGROUP(type, major, minor, access);
if (rc)
- return -EPERM;
+ return rc;
#ifdef CONFIG_CGROUP_DEVICE
return devcgroup_legacy_check_permission(type, major, minor, access);
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 71f0177e8716..599429f99f99 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -62,6 +62,19 @@ config INTEGRITY_PLATFORM_KEYRING
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"
+ depends on SECONDARY_TRUSTED_KEYRING
+ depends on INTEGRITY_ASYMMETRIC_KEYS
+ depends on SYSTEM_BLACKLIST_KEYRING
+ depends on LOAD_UEFI_KEYS
+ depends on !IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
+ 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.
+
config LOAD_UEFI_KEYS
depends on INTEGRITY_PLATFORM_KEYRING
depends on EFI
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 7ee39d66cf16..d0ffe37dc1d6 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -10,6 +10,7 @@ integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o
+integrity-$(CONFIG_INTEGRITY_MACHINE_KEYRING) += platform_certs/machine_keyring.o
integrity-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/efi_parser.o \
platform_certs/load_uefi.o \
platform_certs/keyring_handler.o
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 3b06a01bd0fd..c8c8a4a4e7a0 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -30,6 +30,7 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
".ima",
#endif
".platform",
+ ".machine",
};
#ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
@@ -111,6 +112,8 @@ static int __init __integrity_init_keyring(const unsigned int id,
} else {
if (id == INTEGRITY_KEYRING_PLATFORM)
set_platform_trusted_keys(keyring[id]);
+ if (id == INTEGRITY_KEYRING_MACHINE && trust_moklist())
+ set_machine_trusted_keys(keyring[id]);
if (id == INTEGRITY_KEYRING_IMA)
load_module_cert(keyring[id]);
}
@@ -126,7 +129,8 @@ int __init integrity_init_keyring(const unsigned int id)
perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW
| KEY_USR_READ | KEY_USR_SEARCH;
- if (id == INTEGRITY_KEYRING_PLATFORM) {
+ if (id == INTEGRITY_KEYRING_PLATFORM ||
+ id == INTEGRITY_KEYRING_MACHINE) {
restriction = NULL;
goto out;
}
@@ -139,7 +143,14 @@ int __init integrity_init_keyring(const unsigned int id)
return -ENOMEM;
restriction->check = restrict_link_to_ima;
- perm |= KEY_USR_WRITE;
+
+ /*
+ * MOK keys can only be added through a read-only runtime services
+ * UEFI variable during boot. No additional keys shall be allowed to
+ * load into the machine keyring following init from userspace.
+ */
+ if (id != INTEGRITY_KEYRING_MACHINE)
+ perm |= KEY_USR_WRITE;
out:
return __integrity_init_keyring(id, perm, restriction);
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 08f907382c61..7d87772f0ce6 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -86,7 +86,7 @@ static int __init evm_set_fixmode(char *str)
else
pr_err("invalid \"%s\" mode", str);
- return 0;
+ return 1;
}
__setup("evm=", evm_set_fixmode);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index a64fb0130b01..c6805af46211 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -217,14 +217,11 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
const char *audit_cause = "failed";
struct inode *inode = file_inode(file);
const char *filename = file->f_path.dentry->d_name.name;
+ struct ima_max_digest_data hash;
int result = 0;
int length;
void *tmpbuf;
u64 i_version;
- struct {
- struct ima_digest_data hdr;
- char digest[IMA_MAX_DIGEST_SIZE];
- } hash;
/*
* Always collect the modsig, because IMA might have already collected
@@ -238,9 +235,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
goto out;
/*
- * Dectecting file change is based on i_version. On filesystems
- * which do not support i_version, support is limited to an initial
- * measurement/appraisal/audit.
+ * Detecting file change is based on i_version. On filesystems
+ * which do not support i_version, support was originally limited
+ * to an initial measurement/appraisal/audit, but was modified to
+ * assume the file changed.
*/
i_version = inode_query_iversion(inode);
hash.hdr.algo = algo;
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 3ad8f7734208..cd1683dad3bf 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -452,47 +452,61 @@ static const struct file_operations ima_measure_policy_ops = {
int __init ima_fs_init(void)
{
+ int ret;
+
ima_dir = securityfs_create_dir("ima", integrity_dir);
if (IS_ERR(ima_dir))
- return -1;
+ return PTR_ERR(ima_dir);
ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
NULL);
- if (IS_ERR(ima_symlink))
+ if (IS_ERR(ima_symlink)) {
+ ret = PTR_ERR(ima_symlink);
goto out;
+ }
binary_runtime_measurements =
securityfs_create_file("binary_runtime_measurements",
S_IRUSR | S_IRGRP, ima_dir, NULL,
&ima_measurements_ops);
- if (IS_ERR(binary_runtime_measurements))
+ if (IS_ERR(binary_runtime_measurements)) {
+ ret = PTR_ERR(binary_runtime_measurements);
goto out;
+ }
ascii_runtime_measurements =
securityfs_create_file("ascii_runtime_measurements",
S_IRUSR | S_IRGRP, ima_dir, NULL,
&ima_ascii_measurements_ops);
- if (IS_ERR(ascii_runtime_measurements))
+ if (IS_ERR(ascii_runtime_measurements)) {
+ ret = PTR_ERR(ascii_runtime_measurements);
goto out;
+ }
runtime_measurements_count =
securityfs_create_file("runtime_measurements_count",
S_IRUSR | S_IRGRP, ima_dir, NULL,
&ima_measurements_count_ops);
- if (IS_ERR(runtime_measurements_count))
+ if (IS_ERR(runtime_measurements_count)) {
+ ret = PTR_ERR(runtime_measurements_count);
goto out;
+ }
violations =
securityfs_create_file("violations", S_IRUSR | S_IRGRP,
ima_dir, NULL, &ima_htable_violations_ops);
- if (IS_ERR(violations))
+ if (IS_ERR(violations)) {
+ ret = PTR_ERR(violations);
goto out;
+ }
ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL,
&ima_measure_policy_ops);
- if (IS_ERR(ima_policy))
+ if (IS_ERR(ima_policy)) {
+ ret = PTR_ERR(ima_policy);
goto out;
+ }
return 0;
out:
@@ -503,5 +517,6 @@ out:
securityfs_remove(binary_runtime_measurements);
securityfs_remove(ima_symlink);
securityfs_remove(ima_dir);
- return -1;
+
+ return ret;
}
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index b26fa67476b4..63979aefc95f 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -47,12 +47,9 @@ static int __init ima_add_boot_aggregate(void)
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
struct ima_event_data event_data = { .iint = iint,
.filename = boot_aggregate_name };
+ struct ima_max_digest_data hash;
int result = -ENOMEM;
int violation = 0;
- struct {
- struct ima_digest_data hdr;
- char digest[TPM_MAX_DIGEST_SIZE];
- } hash;
memset(iint, 0, sizeof(*iint));
memset(&hash, 0, sizeof(hash));
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 8c6e4514d494..3d3f8c5c502b 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -263,7 +263,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
/* reset appraisal flags if ima_inode_post_setattr was called */
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
- IMA_ACTION_FLAGS);
+ IMA_NONACTION_FLAGS);
/*
* Re-evaulate the file if either the xattr has changed or the
@@ -418,6 +418,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
/**
* ima_file_mprotect - based on policy, limit mprotect change
+ * @vma: vm_area_struct protection is set to
* @prot: contains the protection that will be applied by the kernel.
*
* Files can be mmap'ed read/write and later changed to execute to circumvent
@@ -519,20 +520,38 @@ int ima_file_check(struct file *file, int mask)
}
EXPORT_SYMBOL_GPL(ima_file_check);
-static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
+static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
+ size_t buf_size)
{
- struct integrity_iint_cache *iint;
- int hash_algo;
+ struct integrity_iint_cache *iint = NULL, tmp_iint;
+ int rc, hash_algo;
- if (!ima_policy_flag)
- return -EOPNOTSUPP;
+ if (ima_policy_flag) {
+ iint = integrity_iint_find(inode);
+ if (iint)
+ mutex_lock(&iint->mutex);
+ }
+
+ if ((!iint || !(iint->flags & IMA_COLLECTED)) && file) {
+ if (iint)
+ mutex_unlock(&iint->mutex);
+
+ memset(&tmp_iint, 0, sizeof(tmp_iint));
+ tmp_iint.inode = inode;
+ mutex_init(&tmp_iint.mutex);
+
+ rc = ima_collect_measurement(&tmp_iint, file, NULL, 0,
+ ima_hash_algo, NULL);
+ if (rc < 0)
+ return -EOPNOTSUPP;
+
+ iint = &tmp_iint;
+ mutex_lock(&iint->mutex);
+ }
- iint = integrity_iint_find(inode);
if (!iint)
return -EOPNOTSUPP;
- mutex_lock(&iint->mutex);
-
/*
* ima_file_hash can be called when ima_collect_measurement has still
* not been called, we might not always have a hash.
@@ -551,12 +570,14 @@ static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
hash_algo = iint->ima_hash->algo;
mutex_unlock(&iint->mutex);
+ if (iint == &tmp_iint)
+ kfree(iint->ima_hash);
+
return hash_algo;
}
/**
- * ima_file_hash - return the stored measurement if a file has been hashed and
- * is in the iint cache.
+ * ima_file_hash - return a measurement of the file
* @file: pointer to the file
* @buf: buffer in which to store the hash
* @buf_size: length of the buffer
@@ -569,7 +590,7 @@ static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
* The file hash returned is based on the entire file, including the appended
* signature.
*
- * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP.
+ * If the measurement cannot be performed, return -EOPNOTSUPP.
* If the parameters are incorrect, return -EINVAL.
*/
int ima_file_hash(struct file *file, char *buf, size_t buf_size)
@@ -577,7 +598,7 @@ int ima_file_hash(struct file *file, char *buf, size_t buf_size)
if (!file)
return -EINVAL;
- return __ima_inode_hash(file_inode(file), buf, buf_size);
+ return __ima_inode_hash(file_inode(file), file, buf, buf_size);
}
EXPORT_SYMBOL_GPL(ima_file_hash);
@@ -604,14 +625,14 @@ int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
if (!inode)
return -EINVAL;
- return __ima_inode_hash(inode, buf, buf_size);
+ return __ima_inode_hash(inode, NULL, buf, buf_size);
}
EXPORT_SYMBOL_GPL(ima_inode_hash);
/**
* ima_post_create_tmpfile - mark newly created tmpfile as new
- * @mnt_userns: user namespace of the mount the inode was found from
- * @file : newly created tmpfile
+ * @mnt_userns: user namespace of the mount the inode was found from
+ * @inode: inode of the newly created tmpfile
*
* No measuring, appraising or auditing of newly created tmpfiles is needed.
* Skip calling process_measurement(), but indicate which newly, created
@@ -643,7 +664,7 @@ void ima_post_create_tmpfile(struct user_namespace *mnt_userns,
/**
* ima_post_path_mknod - mark as a new inode
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @mnt_userns: user namespace of the mount the inode was found from
* @dentry: newly created dentry
*
* Mark files created via the mknodat syscall as new, so that the
@@ -764,7 +785,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
* call to ima_post_load_data().
*
* Callers of this LSM hook can not measure, appraise, or audit the
- * data provided by userspace. Enforce policy rules requring a file
+ * data provided by userspace. Enforce policy rules requiring a file
* signature (eg. kexec'ed kernel image).
*
* For permission return 0, otherwise return -EACCES.
@@ -814,8 +835,8 @@ int ima_load_data(enum kernel_load_data_id id, bool contents)
* ima_post_load_data - appraise decision based on policy
* @buf: pointer to in memory file contents
* @size: size of in memory file contents
- * @id: kernel load data caller identifier
- * @description: @id-specific description of contents
+ * @load_id: kernel load data caller identifier
+ * @description: @load_id-specific description of contents
*
* Measure/appraise/audit in memory buffer based on policy. Policy rules
* are written in terms of a policy identifier.
@@ -874,10 +895,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
.buf = buf,
.buf_len = size};
struct ima_template_desc *template;
- struct {
- struct ima_digest_data hdr;
- char digest[IMA_MAX_DIGEST_SIZE];
- } hash = {};
+ struct ima_max_digest_data hash;
char digest_hash[IMA_MAX_DIGEST_SIZE];
int digest_hash_len = hash_digest_size[ima_hash_algo];
int violation = 0;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 2a1f6418b10a..eea6e92500b8 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -16,7 +16,6 @@
#include <linux/parser.h>
#include <linux/slab.h>
#include <linux/rculist.h>
-#include <linux/genhd.h>
#include <linux/seq_file.h>
#include <linux/ima.h>
@@ -429,7 +428,7 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry)
/*
* ima_lsm_copy_rule() shallow copied all references, except for the
* LSM references, from entry to nentry so we only want to free the LSM
- * references and the entry itself. All other memory refrences will now
+ * references and the entry itself. All other memory references will now
* be owned by nentry.
*/
ima_lsm_free_rule(entry);
@@ -712,7 +711,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
func, mask, func_data))
continue;
- action |= entry->flags & IMA_ACTION_FLAGS;
+ action |= entry->flags & IMA_NONACTION_FLAGS;
action |= entry->action & IMA_DO_MASK;
if (entry->action & IMA_APPRAISE) {
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index ca017cae73eb..7155d17a3b75 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -272,7 +272,7 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
* digest formats:
* - DATA_FMT_DIGEST: digest
* - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest,
- * where <hash algo> is provided if the hash algoritm is not
+ * where <hash algo> is provided if the hash algorithm is not
* SHA1 or MD5
*/
u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 };
@@ -307,10 +307,7 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
int ima_eventdigest_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
- struct {
- struct ima_digest_data hdr;
- char digest[IMA_MAX_DIGEST_SIZE];
- } hash;
+ struct ima_max_digest_data hash;
u8 *cur_digest = NULL;
u32 cur_digestsize = 0;
struct inode *inode;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 547425c20e11..3510e413ea17 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/integrity.h>
#include <crypto/sha1.h>
+#include <crypto/hash.h>
#include <linux/key.h>
#include <linux/audit.h>
@@ -30,8 +31,8 @@
#define IMA_HASH 0x00000100
#define IMA_HASHED 0x00000200
-/* iint cache flags */
-#define IMA_ACTION_FLAGS 0xff000000
+/* iint policy rule cache flags */
+#define IMA_NONACTION_FLAGS 0xff000000
#define IMA_DIGSIG_REQUIRED 0x01000000
#define IMA_PERMIT_DIRECTIO 0x02000000
#define IMA_NEW_FILE 0x04000000
@@ -111,6 +112,15 @@ struct ima_digest_data {
} __packed;
/*
+ * Instead of wrapping the ima_digest_data struct inside a local structure
+ * with the maximum hash size, define ima_max_digest_data struct.
+ */
+struct ima_max_digest_data {
+ struct ima_digest_data hdr;
+ u8 digest[HASH_MAX_DIGESTSIZE];
+} __packed;
+
+/*
* signature format v2 - for using with asymmetric keys
*/
struct signature_v2_hdr {
@@ -151,7 +161,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,
#define INTEGRITY_KEYRING_EVM 0
#define INTEGRITY_KEYRING_IMA 1
#define INTEGRITY_KEYRING_PLATFORM 2
-#define INTEGRITY_KEYRING_MAX 3
+#define INTEGRITY_KEYRING_MACHINE 3
+#define INTEGRITY_KEYRING_MAX 4
extern struct dentry *integrity_dir;
@@ -283,3 +294,17 @@ static inline void __init add_to_platform_keyring(const char *source,
{
}
#endif
+
+#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
+void __init add_to_machine_keyring(const char *source, const void *data, size_t len);
+bool __init trust_moklist(void);
+#else
+static inline void __init add_to_machine_keyring(const char *source,
+ const void *data, size_t len)
+{
+}
+static inline bool __init trust_moklist(void)
+{
+ return false;
+}
+#endif
diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c
index 5604bd57c990..1db4d3b4356d 100644
--- a/security/integrity/platform_certs/keyring_handler.c
+++ b/security/integrity/platform_certs/keyring_handler.c
@@ -9,6 +9,7 @@
#include <keys/asymmetric-type.h>
#include <keys/system_keyring.h>
#include "../integrity.h"
+#include "keyring_handler.h"
static efi_guid_t efi_cert_x509_guid __initdata = EFI_CERT_X509_GUID;
static efi_guid_t efi_cert_x509_sha256_guid __initdata =
@@ -66,7 +67,7 @@ static __init void uefi_revocation_list_x509(const char *source,
/*
* Return the appropriate handler for particular signature list types found in
- * the UEFI db and MokListRT tables.
+ * the UEFI db tables.
*/
__init efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type)
{
@@ -77,6 +78,21 @@ __init efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type)
/*
* Return the appropriate handler for particular signature list types found in
+ * the MokListRT tables.
+ */
+__init efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type)
+{
+ if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) {
+ if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) && trust_moklist())
+ return add_to_machine_keyring;
+ else
+ return add_to_platform_keyring;
+ }
+ return 0;
+}
+
+/*
+ * Return the appropriate handler for particular signature list types found in
* the UEFI dbx and MokListXRT tables.
*/
__init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type)
diff --git a/security/integrity/platform_certs/keyring_handler.h b/security/integrity/platform_certs/keyring_handler.h
index 2462bfa08fe3..284558f30411 100644
--- a/security/integrity/platform_certs/keyring_handler.h
+++ b/security/integrity/platform_certs/keyring_handler.h
@@ -25,6 +25,11 @@ void blacklist_binary(const char *source, const void *data, size_t len);
efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type);
/*
+ * Return the handler for particular signature list types found in the mok.
+ */
+efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type);
+
+/*
* Return the handler for particular signature list types found in the dbx.
*/
efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type);
diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
index 08b6d12f99b4..5f45c3c07dbd 100644
--- a/security/integrity/platform_certs/load_uefi.c
+++ b/security/integrity/platform_certs/load_uefi.c
@@ -95,7 +95,7 @@ static int __init load_moklist_certs(void)
rc = parse_efi_signature_list("UEFI:MokListRT (MOKvar table)",
mokvar_entry->data,
mokvar_entry->data_size,
- get_handler_for_db);
+ get_handler_for_mok);
/* All done if that worked. */
if (!rc)
return rc;
@@ -110,7 +110,7 @@ static int __init load_moklist_certs(void)
mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
if (mok) {
rc = parse_efi_signature_list("UEFI:MokListRT",
- mok, moksize, get_handler_for_db);
+ mok, moksize, get_handler_for_mok);
kfree(mok);
if (rc)
pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
diff --git a/security/integrity/platform_certs/machine_keyring.c b/security/integrity/platform_certs/machine_keyring.c
new file mode 100644
index 000000000000..7aaed7950b6e
--- /dev/null
+++ b/security/integrity/platform_certs/machine_keyring.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Machine keyring routines.
+ *
+ * Copyright (c) 2021, Oracle and/or its affiliates.
+ */
+
+#include <linux/efi.h>
+#include "../integrity.h"
+
+static bool trust_mok;
+
+static __init int machine_keyring_init(void)
+{
+ int rc;
+
+ rc = integrity_init_keyring(INTEGRITY_KEYRING_MACHINE);
+ if (rc)
+ return rc;
+
+ pr_notice("Machine keyring initialized\n");
+ return 0;
+}
+device_initcall(machine_keyring_init);
+
+void __init add_to_machine_keyring(const char *source, const void *data, size_t len)
+{
+ key_perm_t perm;
+ int rc;
+
+ perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW;
+ rc = integrity_load_cert(INTEGRITY_KEYRING_MACHINE, source, data, len, perm);
+
+ /*
+ * Some MOKList keys may not pass the machine keyring restrictions.
+ * If the restriction check does not pass and the platform keyring
+ * is configured, try to add it into that keyring instead.
+ */
+ if (rc && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING))
+ rc = integrity_load_cert(INTEGRITY_KEYRING_PLATFORM, source,
+ data, len, perm);
+
+ if (rc)
+ pr_info("Error adding keys to machine keyring %s\n", source);
+}
+
+/*
+ * Try to load the MokListTrustedRT MOK variable to see if we should trust
+ * the MOK keys within the kernel. It is not an error if this variable
+ * does not exist. If it does not exist, MOK keys should not be trusted
+ * within the machine keyring.
+ */
+static __init bool uefi_check_trust_mok_keys(void)
+{
+ struct efi_mokvar_table_entry *mokvar_entry;
+
+ mokvar_entry = efi_mokvar_entry_find("MokListTrustedRT");
+
+ if (mokvar_entry)
+ return true;
+
+ return false;
+}
+
+bool __init trust_moklist(void)
+{
+ static bool initialized;
+
+ if (!initialized) {
+ initialized = true;
+
+ if (uefi_check_trust_mok_keys())
+ trust_mok = true;
+ }
+
+ return trust_mok;
+}
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index 969122c7b92f..0e30b361e1c1 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -98,10 +98,21 @@ config ENCRYPTED_KEYS
select CRYPTO_RNG
help
This option provides support for create/encrypting/decrypting keys
- in the kernel. Encrypted keys are kernel generated random numbers,
- which are encrypted/decrypted with a 'master' symmetric key. The
- 'master' key can be either a trusted-key or user-key type.
- Userspace only ever sees/stores encrypted blobs.
+ in the kernel. Encrypted keys are instantiated using kernel
+ generated random numbers or provided decrypted data, and are
+ encrypted/decrypted with a 'master' symmetric key. The 'master'
+ key can be either a trusted-key or user-key type. Only encrypted
+ blobs are ever output to Userspace.
+
+ If you are unsure as to whether this is required, answer N.
+
+config USER_DECRYPTED_DATA
+ bool "Allow encrypted keys with user decrypted data"
+ depends on ENCRYPTED_KEYS
+ help
+ This option provides support for instantiating encrypted keys using
+ user-provided decrypted data. The decrypted data must be hex-ascii
+ encoded.
If you are unsure as to whether this is required, answer N.
diff --git a/security/keys/dh.c b/security/keys/dh.c
index 4573fc15617d..b339760a31dd 100644
--- a/security/keys/dh.c
+++ b/security/keys/dh.c
@@ -15,7 +15,7 @@
#include <keys/user-type.h>
#include "internal.h"
-static ssize_t dh_data_from_key(key_serial_t keyid, void **data)
+static ssize_t dh_data_from_key(key_serial_t keyid, const void **data)
{
struct key *key;
key_ref_t key_ref;
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 87432b35d771..e05cfc2e49ae 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -78,6 +78,11 @@ static const match_table_t key_tokens = {
{Opt_err, NULL}
};
+static bool user_decrypted_data = IS_ENABLED(CONFIG_USER_DECRYPTED_DATA);
+module_param(user_decrypted_data, bool, 0);
+MODULE_PARM_DESC(user_decrypted_data,
+ "Allow instantiation of encrypted keys using provided decrypted data");
+
static int aes_get_sizes(void)
{
struct crypto_skcipher *tfm;
@@ -158,7 +163,7 @@ static int valid_master_desc(const char *new_desc, const char *orig_desc)
* datablob_parse - parse the keyctl data
*
* datablob format:
- * new [<format>] <master-key name> <decrypted data length>
+ * new [<format>] <master-key name> <decrypted data length> [<decrypted data>]
* load [<format>] <master-key name> <decrypted data length>
* <encrypted iv + data>
* update <new-master-key name>
@@ -170,7 +175,7 @@ static int valid_master_desc(const char *new_desc, const char *orig_desc)
*/
static int datablob_parse(char *datablob, const char **format,
char **master_desc, char **decrypted_datalen,
- char **hex_encoded_iv)
+ char **hex_encoded_iv, char **decrypted_data)
{
substring_t args[MAX_OPT_ARGS];
int ret = -EINVAL;
@@ -231,6 +236,7 @@ static int datablob_parse(char *datablob, const char **format,
"when called from .update method\n", keyword);
break;
}
+ *decrypted_data = strsep(&datablob, " \t");
ret = 0;
break;
case Opt_load:
@@ -595,7 +601,8 @@ out:
static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
const char *format,
const char *master_desc,
- const char *datalen)
+ const char *datalen,
+ const char *decrypted_data)
{
struct encrypted_key_payload *epayload = NULL;
unsigned short datablob_len;
@@ -604,6 +611,7 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
unsigned int encrypted_datalen;
unsigned int format_len;
long dlen;
+ int i;
int ret;
ret = kstrtol(datalen, 10, &dlen);
@@ -613,6 +621,24 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
format_len = (!format) ? strlen(key_format_default) : strlen(format);
decrypted_datalen = dlen;
payload_datalen = decrypted_datalen;
+
+ if (decrypted_data) {
+ if (!user_decrypted_data) {
+ pr_err("encrypted key: instantiation of keys using provided decrypted data is disabled since CONFIG_USER_DECRYPTED_DATA is set to false\n");
+ return ERR_PTR(-EINVAL);
+ }
+ if (strlen(decrypted_data) != decrypted_datalen) {
+ pr_err("encrypted key: decrypted data provided does not match decrypted data length provided\n");
+ return ERR_PTR(-EINVAL);
+ }
+ for (i = 0; i < strlen(decrypted_data); i++) {
+ if (!isxdigit(decrypted_data[i])) {
+ pr_err("encrypted key: decrypted data provided must contain only hexadecimal characters\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+ }
+
if (format) {
if (!strcmp(format, key_format_ecryptfs)) {
if (dlen != ECRYPTFS_MAX_KEY_BYTES) {
@@ -740,13 +766,14 @@ static void __ekey_init(struct encrypted_key_payload *epayload,
/*
* encrypted_init - initialize an encrypted key
*
- * For a new key, use a random number for both the iv and data
- * itself. For an old key, decrypt the hex encoded data.
+ * For a new key, use either a random number or user-provided decrypted data in
+ * case it is provided. A random number is used for the iv in both cases. For
+ * an old key, decrypt the hex encoded data.
*/
static int encrypted_init(struct encrypted_key_payload *epayload,
const char *key_desc, const char *format,
const char *master_desc, const char *datalen,
- const char *hex_encoded_iv)
+ const char *hex_encoded_iv, const char *decrypted_data)
{
int ret = 0;
@@ -760,21 +787,26 @@ static int encrypted_init(struct encrypted_key_payload *epayload,
}
__ekey_init(epayload, format, master_desc, datalen);
- if (!hex_encoded_iv) {
- get_random_bytes(epayload->iv, ivsize);
-
- get_random_bytes(epayload->decrypted_data,
- epayload->decrypted_datalen);
- } else
+ if (hex_encoded_iv) {
ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv);
+ } else if (decrypted_data) {
+ get_random_bytes(epayload->iv, ivsize);
+ memcpy(epayload->decrypted_data, decrypted_data,
+ epayload->decrypted_datalen);
+ } else {
+ get_random_bytes(epayload->iv, ivsize);
+ get_random_bytes(epayload->decrypted_data, epayload->decrypted_datalen);
+ }
return ret;
}
/*
* encrypted_instantiate - instantiate an encrypted key
*
- * Decrypt an existing encrypted datablob or create a new encrypted key
- * based on a kernel random number.
+ * Instantiates the key:
+ * - by decrypting an existing encrypted datablob, or
+ * - by creating a new encrypted key based on a kernel random number, or
+ * - using provided decrypted data.
*
* On success, return 0. Otherwise return errno.
*/
@@ -787,6 +819,7 @@ static int encrypted_instantiate(struct key *key,
char *master_desc = NULL;
char *decrypted_datalen = NULL;
char *hex_encoded_iv = NULL;
+ char *decrypted_data = NULL;
size_t datalen = prep->datalen;
int ret;
@@ -799,18 +832,18 @@ static int encrypted_instantiate(struct key *key,
datablob[datalen] = 0;
memcpy(datablob, prep->data, datalen);
ret = datablob_parse(datablob, &format, &master_desc,
- &decrypted_datalen, &hex_encoded_iv);
+ &decrypted_datalen, &hex_encoded_iv, &decrypted_data);
if (ret < 0)
goto out;
epayload = encrypted_key_alloc(key, format, master_desc,
- decrypted_datalen);
+ decrypted_datalen, decrypted_data);
if (IS_ERR(epayload)) {
ret = PTR_ERR(epayload);
goto out;
}
ret = encrypted_init(epayload, key->description, format, master_desc,
- decrypted_datalen, hex_encoded_iv);
+ decrypted_datalen, hex_encoded_iv, decrypted_data);
if (ret < 0) {
kfree_sensitive(epayload);
goto out;
@@ -860,7 +893,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
buf[datalen] = 0;
memcpy(buf, prep->data, datalen);
- ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
+ ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL, NULL);
if (ret < 0)
goto out;
@@ -869,7 +902,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
goto out;
new_epayload = encrypted_key_alloc(key, epayload->format,
- new_master_desc, epayload->datalen);
+ new_master_desc, epayload->datalen, NULL);
if (IS_ERR(new_epayload)) {
ret = PTR_ERR(new_epayload);
goto out;
diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c
index 5de0d599a274..97bc27bbf079 100644
--- a/security/keys/keyctl_pkey.c
+++ b/security/keys/keyctl_pkey.c
@@ -135,15 +135,23 @@ static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_par
switch (op) {
case KEYCTL_PKEY_ENCRYPT:
+ if (uparams.in_len > info.max_dec_size ||
+ uparams.out_len > info.max_enc_size)
+ return -EINVAL;
+ break;
case KEYCTL_PKEY_DECRYPT:
if (uparams.in_len > info.max_enc_size ||
uparams.out_len > info.max_dec_size)
return -EINVAL;
break;
case KEYCTL_PKEY_SIGN:
+ if (uparams.in_len > info.max_data_size ||
+ uparams.out_len > info.max_sig_size)
+ return -EINVAL;
+ break;
case KEYCTL_PKEY_VERIFY:
- if (uparams.in_len > info.max_sig_size ||
- uparams.out_len > info.max_data_size)
+ if (uparams.in_len > info.max_data_size ||
+ uparams.in2_len > info.max_sig_size)
return -EINVAL;
break;
default:
@@ -151,7 +159,7 @@ static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_par
}
params->in_len = uparams.in_len;
- params->out_len = uparams.out_len;
+ params->out_len = uparams.out_len; /* Note: same as in2_len */
return 0;
}
diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c
index d5c891d8d353..9b9d3ef79cbe 100644
--- a/security/keys/trusted-keys/trusted_core.c
+++ b/security/keys/trusted-keys/trusted_core.c
@@ -27,10 +27,10 @@ module_param_named(source, trusted_key_source, charp, 0);
MODULE_PARM_DESC(source, "Select trusted keys source (tpm or tee)");
static const struct trusted_key_source trusted_key_sources[] = {
-#if defined(CONFIG_TCG_TPM)
+#if IS_REACHABLE(CONFIG_TCG_TPM)
{ "tpm", &trusted_key_tpm_ops },
#endif
-#if defined(CONFIG_TEE)
+#if IS_REACHABLE(CONFIG_TEE)
{ "tee", &trusted_key_tee_ops },
#endif
};
@@ -351,7 +351,7 @@ static int __init init_trusted(void)
static void __exit cleanup_trusted(void)
{
- static_call(trusted_key_exit)();
+ static_call_cond(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 2ce66c199e1d..c8626686ee1b 100644
--- a/security/keys/trusted-keys/trusted_tee.c
+++ b/security/keys/trusted-keys/trusted_tee.c
@@ -70,17 +70,15 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
memset(&inv_arg, 0, sizeof(inv_arg));
memset(&param, 0, sizeof(param));
- reg_shm_in = tee_shm_register(pvt_data.ctx, (unsigned long)p->key,
- p->key_len, TEE_SHM_DMA_BUF |
- TEE_SHM_KERNEL_MAPPED);
+ 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(pvt_data.ctx, (unsigned long)p->blob,
- sizeof(p->blob), TEE_SHM_DMA_BUF |
- TEE_SHM_KERNEL_MAPPED);
+ 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);
@@ -131,17 +129,15 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
memset(&inv_arg, 0, sizeof(inv_arg));
memset(&param, 0, sizeof(param));
- reg_shm_in = tee_shm_register(pvt_data.ctx, (unsigned long)p->blob,
- p->blob_len, TEE_SHM_DMA_BUF |
- TEE_SHM_KERNEL_MAPPED);
+ 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(pvt_data.ctx, (unsigned long)p->key,
- sizeof(p->key), TEE_SHM_DMA_BUF |
- TEE_SHM_KERNEL_MAPPED);
+ 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);
@@ -192,8 +188,7 @@ static int trusted_tee_get_random(unsigned char *key, size_t key_len)
memset(&inv_arg, 0, sizeof(inv_arg));
memset(&param, 0, sizeof(param));
- reg_shm = tee_shm_register(pvt_data.ctx, (unsigned long)key, key_len,
- TEE_SHM_DMA_BUF | TEE_SHM_KERNEL_MAPPED);
+ reg_shm = tee_shm_register_kernel_buf(pvt_data.ctx, key, key_len);
if (IS_ERR(reg_shm)) {
dev_err(pvt_data.dev, "key shm register failed\n");
return PTR_ERR(reg_shm);
diff --git a/security/security.c b/security/security.c
index 22261d79f333..b7cf5cbfdc67 100644
--- a/security/security.c
+++ b/security/security.c
@@ -884,9 +884,22 @@ int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
return call_int_hook(fs_context_dup, 0, fc, src_fc);
}
-int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param)
+int security_fs_context_parse_param(struct fs_context *fc,
+ struct fs_parameter *param)
{
- return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param);
+ struct security_hook_list *hp;
+ int trc;
+ int rc = -ENOPARAM;
+
+ hlist_for_each_entry(hp, &security_hook_heads.fs_context_parse_param,
+ list) {
+ trc = hp->hook.fs_context_parse_param(fc, param);
+ if (trc == 0)
+ rc = 0;
+ else if (trc != -ENOPARAM)
+ return trc;
+ }
+ return rc;
}
int security_sb_alloc(struct super_block *sb)
@@ -2391,6 +2404,13 @@ void security_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk,
}
EXPORT_SYMBOL(security_sctp_sk_clone);
+int security_sctp_assoc_established(struct sctp_association *asoc,
+ struct sk_buff *skb)
+{
+ return call_int_hook(sctp_assoc_established, 0, asoc, skb);
+}
+EXPORT_SYMBOL(security_sctp_assoc_established);
+
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5b6895e4fc29..b12e14b2797b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -211,10 +211,9 @@ static int selinux_lsm_notifier_avc_callback(u32 event)
*/
static void cred_init_security(void)
{
- struct cred *cred = (struct cred *) current->real_cred;
struct task_security_struct *tsec;
- tsec = selinux_cred(cred);
+ tsec = selinux_cred(unrcu_pointer(current->real_cred));
tsec->osid = tsec->sid = SECINITSID_KERNEL;
}
@@ -341,17 +340,15 @@ static void inode_free_security(struct inode *inode)
}
struct selinux_mnt_opts {
- const char *fscontext, *context, *rootcontext, *defcontext;
+ u32 fscontext_sid;
+ u32 context_sid;
+ u32 rootcontext_sid;
+ u32 defcontext_sid;
};
static void selinux_free_mnt_opts(void *mnt_opts)
{
- struct selinux_mnt_opts *opts = mnt_opts;
- kfree(opts->fscontext);
- kfree(opts->context);
- kfree(opts->rootcontext);
- kfree(opts->defcontext);
- kfree(opts);
+ kfree(mnt_opts);
}
enum {
@@ -479,7 +476,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
static int sb_check_xattr_support(struct super_block *sb)
{
- struct superblock_security_struct *sbsec = sb->s_security;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
struct dentry *root = sb->s_root;
struct inode *root_inode = d_backing_inode(root);
u32 sid;
@@ -598,18 +595,6 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
return 0;
}
-static int parse_sid(struct super_block *sb, const char *s, u32 *sid,
- gfp_t gfp)
-{
- int rc = security_context_str_to_sid(&selinux_state, s,
- sid, gfp);
- if (rc)
- pr_warn("SELinux: security_context_str_to_sid"
- "(%s) failed for (dev %s, type %s) errno=%d\n",
- s, sb->s_id, sb->s_type->name, rc);
- return rc;
-}
-
/*
* Allow filesystems with binary mount data to explicitly set mount point
* labeling information.
@@ -672,41 +657,29 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* than once with different security options.
*/
if (opts) {
- if (opts->fscontext) {
- rc = parse_sid(sb, opts->fscontext, &fscontext_sid,
- GFP_KERNEL);
- if (rc)
- goto out;
+ if (opts->fscontext_sid) {
+ fscontext_sid = opts->fscontext_sid;
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
fscontext_sid))
goto out_double_mount;
sbsec->flags |= FSCONTEXT_MNT;
}
- if (opts->context) {
- rc = parse_sid(sb, opts->context, &context_sid,
- GFP_KERNEL);
- if (rc)
- goto out;
+ if (opts->context_sid) {
+ context_sid = opts->context_sid;
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
context_sid))
goto out_double_mount;
sbsec->flags |= CONTEXT_MNT;
}
- if (opts->rootcontext) {
- rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid,
- GFP_KERNEL);
- if (rc)
- goto out;
+ if (opts->rootcontext_sid) {
+ rootcontext_sid = opts->rootcontext_sid;
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
rootcontext_sid))
goto out_double_mount;
sbsec->flags |= ROOTCONTEXT_MNT;
}
- if (opts->defcontext) {
- rc = parse_sid(sb, opts->defcontext, &defcontext_sid,
- GFP_KERNEL);
- if (rc)
- goto out;
+ if (opts->defcontext_sid) {
+ defcontext_sid = opts->defcontext_sid;
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
defcontext_sid))
goto out_double_mount;
@@ -976,6 +949,8 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
{
struct selinux_mnt_opts *opts = *mnt_opts;
bool is_alloc_opts = false;
+ u32 *dst_sid;
+ int rc;
if (token == Opt_seclabel)
/* eaten and completely ignored */
@@ -983,6 +958,11 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
if (!s)
return -ENOMEM;
+ if (!selinux_initialized(&selinux_state)) {
+ pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
+ return -EINVAL;
+ }
+
if (!opts) {
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
@@ -993,28 +973,34 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
switch (token) {
case Opt_context:
- if (opts->context || opts->defcontext)
+ if (opts->context_sid || opts->defcontext_sid)
goto err;
- opts->context = s;
+ dst_sid = &opts->context_sid;
break;
case Opt_fscontext:
- if (opts->fscontext)
+ if (opts->fscontext_sid)
goto err;
- opts->fscontext = s;
+ dst_sid = &opts->fscontext_sid;
break;
case Opt_rootcontext:
- if (opts->rootcontext)
+ if (opts->rootcontext_sid)
goto err;
- opts->rootcontext = s;
+ dst_sid = &opts->rootcontext_sid;
break;
case Opt_defcontext:
- if (opts->context || opts->defcontext)
+ if (opts->context_sid || opts->defcontext_sid)
goto err;
- opts->defcontext = s;
+ dst_sid = &opts->defcontext_sid;
break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
}
-
- return 0;
+ rc = security_context_str_to_sid(&selinux_state, s, dst_sid, GFP_KERNEL);
+ if (rc)
+ pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
+ s, rc);
+ return rc;
err:
if (is_alloc_opts) {
@@ -2535,7 +2521,7 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
if (rc) {
clear_itimer();
- spin_lock_irq(&current->sighand->siglock);
+ spin_lock_irq(&unrcu_pointer(current->sighand)->siglock);
if (!fatal_signal_pending(current)) {
flush_sigqueue(&current->pending);
flush_sigqueue(&current->signal->shared_pending);
@@ -2543,13 +2529,13 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
sigemptyset(&current->blocked);
recalc_sigpending();
}
- spin_unlock_irq(&current->sighand->siglock);
+ spin_unlock_irq(&unrcu_pointer(current->sighand)->siglock);
}
/* Wake up the parent if it is waiting so that it can recheck
* wait permission to the new task SID. */
read_lock(&tasklist_lock);
- __wake_up_parent(current, current->real_parent);
+ __wake_up_parent(current, unrcu_pointer(current->real_parent));
read_unlock(&tasklist_lock);
}
@@ -2647,9 +2633,7 @@ free_opt:
static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
{
struct selinux_mnt_opts *opts = mnt_opts;
- struct superblock_security_struct *sbsec = sb->s_security;
- u32 sid;
- int rc;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
/*
* Superblock not initialized (i.e. no options) - reject if any
@@ -2665,35 +2649,27 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
if (!opts)
return (sbsec->flags & SE_MNTMASK) ? 1 : 0;
- if (opts->fscontext) {
- rc = parse_sid(sb, opts->fscontext, &sid, GFP_NOWAIT);
- if (rc)
- return 1;
- if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+ if (opts->fscontext_sid) {
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+ opts->fscontext_sid))
return 1;
}
- if (opts->context) {
- rc = parse_sid(sb, opts->context, &sid, GFP_NOWAIT);
- if (rc)
- return 1;
- if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+ if (opts->context_sid) {
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+ opts->context_sid))
return 1;
}
- if (opts->rootcontext) {
+ if (opts->rootcontext_sid) {
struct inode_security_struct *root_isec;
root_isec = backing_inode_security(sb->s_root);
- rc = parse_sid(sb, opts->rootcontext, &sid, GFP_NOWAIT);
- if (rc)
- return 1;
- if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+ opts->rootcontext_sid))
return 1;
}
- if (opts->defcontext) {
- rc = parse_sid(sb, opts->defcontext, &sid, GFP_NOWAIT);
- if (rc)
- return 1;
- if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+ if (opts->defcontext_sid) {
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+ opts->defcontext_sid))
return 1;
}
return 0;
@@ -2703,8 +2679,6 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
{
struct selinux_mnt_opts *opts = mnt_opts;
struct superblock_security_struct *sbsec = selinux_superblock(sb);
- u32 sid;
- int rc;
if (!(sbsec->flags & SE_SBINITIALIZED))
return 0;
@@ -2712,34 +2686,26 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
if (!opts)
return 0;
- if (opts->fscontext) {
- rc = parse_sid(sb, opts->fscontext, &sid, GFP_KERNEL);
- if (rc)
- return rc;
- if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+ if (opts->fscontext_sid) {
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+ opts->fscontext_sid))
goto out_bad_option;
}
- if (opts->context) {
- rc = parse_sid(sb, opts->context, &sid, GFP_KERNEL);
- if (rc)
- return rc;
- if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+ if (opts->context_sid) {
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+ opts->context_sid))
goto out_bad_option;
}
- if (opts->rootcontext) {
+ if (opts->rootcontext_sid) {
struct inode_security_struct *root_isec;
root_isec = backing_inode_security(sb->s_root);
- rc = parse_sid(sb, opts->rootcontext, &sid, GFP_KERNEL);
- if (rc)
- return rc;
- if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+ opts->rootcontext_sid))
goto out_bad_option;
}
- if (opts->defcontext) {
- rc = parse_sid(sb, opts->defcontext, &sid, GFP_KERNEL);
- if (rc)
- return rc;
- if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+ if (opts->defcontext_sid) {
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+ opts->defcontext_sid))
goto out_bad_option;
}
return 0;
@@ -2806,38 +2772,12 @@ static int selinux_fs_context_dup(struct fs_context *fc,
struct fs_context *src_fc)
{
const struct selinux_mnt_opts *src = src_fc->security;
- struct selinux_mnt_opts *opts;
if (!src)
return 0;
- fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
- if (!fc->security)
- return -ENOMEM;
-
- opts = fc->security;
-
- if (src->fscontext) {
- opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL);
- if (!opts->fscontext)
- return -ENOMEM;
- }
- if (src->context) {
- opts->context = kstrdup(src->context, GFP_KERNEL);
- if (!opts->context)
- return -ENOMEM;
- }
- if (src->rootcontext) {
- opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL);
- if (!opts->rootcontext)
- return -ENOMEM;
- }
- if (src->defcontext) {
- opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL);
- if (!opts->defcontext)
- return -ENOMEM;
- }
- return 0;
+ fc->security = kmemdup(src, sizeof(*src), GFP_KERNEL);
+ return fc->security ? 0 : -ENOMEM;
}
static const struct fs_parameter_spec selinux_fs_parameters[] = {
@@ -2860,10 +2800,9 @@ static int selinux_fs_context_parse_param(struct fs_context *fc,
return opt;
rc = selinux_add_opt(opt, param->string, &fc->security);
- if (!rc) {
+ if (!rc)
param->string = NULL;
- rc = 1;
- }
+
return rc;
}
@@ -3345,8 +3284,6 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
isec->sid = newsid;
isec->initialized = LABEL_INITIALIZED;
spin_unlock(&isec->lock);
-
- return;
}
static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
@@ -3745,6 +3682,12 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
CAP_OPT_NONE, true);
break;
+ case FIOCLEX:
+ case FIONCLEX:
+ if (!selinux_policycap_ioctl_skip_cloexec())
+ error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
+ break;
+
/* default case assumes that the command will go
* to the file's ioctl() function.
*/
@@ -5299,37 +5242,38 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
sksec->sclass = isec->sclass;
}
-/* Called whenever SCTP receives an INIT chunk. This happens when an incoming
- * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association
- * already present).
+/*
+ * Determines peer_secid for the asoc and updates socket's peer label
+ * if it's the first association on the socket.
*/
-static int selinux_sctp_assoc_request(struct sctp_association *asoc,
- struct sk_buff *skb)
+static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
+ struct sk_buff *skb)
{
- struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ struct sock *sk = asoc->base.sk;
+ u16 family = sk->sk_family;
+ struct sk_security_struct *sksec = sk->sk_security;
struct common_audit_data ad;
struct lsm_network_audit net = {0,};
- u8 peerlbl_active;
- u32 peer_sid = SECINITSID_UNLABELED;
- u32 conn_sid;
- int err = 0;
+ int err;
- if (!selinux_policycap_extsockclass())
- return 0;
+ /* handle mapped IPv4 packets arriving via IPv6 sockets */
+ if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+ family = PF_INET;
- peerlbl_active = selinux_peerlbl_enabled();
+ if (selinux_peerlbl_enabled()) {
+ asoc->peer_secid = SECSID_NULL;
- if (peerlbl_active) {
/* This will return peer_sid = SECSID_NULL if there are
* no peer labels, see security_net_peersid_resolve().
*/
- err = selinux_skb_peerlbl_sid(skb, asoc->base.sk->sk_family,
- &peer_sid);
+ err = selinux_skb_peerlbl_sid(skb, family, &asoc->peer_secid);
if (err)
return err;
- if (peer_sid == SECSID_NULL)
- peer_sid = SECINITSID_UNLABELED;
+ if (asoc->peer_secid == SECSID_NULL)
+ asoc->peer_secid = SECINITSID_UNLABELED;
+ } else {
+ asoc->peer_secid = SECINITSID_UNLABELED;
}
if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
@@ -5340,8 +5284,8 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
* then it is approved by policy and used as the primary
* peer SID for getpeercon(3).
*/
- sksec->peer_sid = peer_sid;
- } else if (sksec->peer_sid != peer_sid) {
+ sksec->peer_sid = asoc->peer_secid;
+ } else if (sksec->peer_sid != asoc->peer_secid) {
/* Other association peer SIDs are checked to enforce
* consistency among the peer SIDs.
*/
@@ -5349,11 +5293,32 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
ad.u.net = &net;
ad.u.net->sk = asoc->base.sk;
err = avc_has_perm(&selinux_state,
- sksec->peer_sid, peer_sid, sksec->sclass,
- SCTP_SOCKET__ASSOCIATION, &ad);
+ sksec->peer_sid, asoc->peer_secid,
+ sksec->sclass, SCTP_SOCKET__ASSOCIATION,
+ &ad);
if (err)
return err;
}
+ return 0;
+}
+
+/* Called whenever SCTP receives an INIT or COOKIE ECHO chunk. This
+ * happens on an incoming connect(2), sctp_connectx(3) or
+ * sctp_sendmsg(3) (with no association already present).
+ */
+static int selinux_sctp_assoc_request(struct sctp_association *asoc,
+ struct sk_buff *skb)
+{
+ struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ u32 conn_sid;
+ int err;
+
+ if (!selinux_policycap_extsockclass())
+ return 0;
+
+ err = selinux_sctp_process_new_assoc(asoc, skb);
+ if (err)
+ return err;
/* Compute the MLS component for the connection and store
* the information in asoc. This will be used by SCTP TCP type
@@ -5361,17 +5326,36 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
* socket to be generated. selinux_sctp_sk_clone() will then
* plug this into the new socket.
*/
- err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid);
+ err = selinux_conn_sid(sksec->sid, asoc->peer_secid, &conn_sid);
if (err)
return err;
asoc->secid = conn_sid;
- asoc->peer_secid = peer_sid;
/* Set any NetLabel labels including CIPSO/CALIPSO options. */
return selinux_netlbl_sctp_assoc_request(asoc, skb);
}
+/* Called when SCTP receives a COOKIE ACK chunk as the final
+ * response to an association request (initited by us).
+ */
+static int selinux_sctp_assoc_established(struct sctp_association *asoc,
+ struct sk_buff *skb)
+{
+ struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+
+ if (!selinux_policycap_extsockclass())
+ return 0;
+
+ /* Inherit secid from the parent socket - this will be picked up
+ * by selinux_sctp_sk_clone() if the association gets peeled off
+ * into a new socket.
+ */
+ asoc->secid = sksec->sid;
+
+ return selinux_sctp_process_new_assoc(asoc, skb);
+}
+
/* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
* based on their @optname.
*/
@@ -7192,6 +7176,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
+ LSM_HOOK_INIT(sctp_assoc_established, selinux_sctp_assoc_established),
LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c
index 20b3b2243820..5839ca7bb9c7 100644
--- a/security/selinux/ibpkey.c
+++ b/security/selinux/ibpkey.c
@@ -104,7 +104,7 @@ static void sel_ib_pkey_insert(struct sel_ib_pkey *pkey)
tail = list_entry(
rcu_dereference_protected(
- sel_ib_pkey_hash[idx].list.prev,
+ list_tail_rcu(&sel_ib_pkey_hash[idx].list),
lockdep_is_held(&sel_ib_pkey_lock)),
struct sel_ib_pkey, list);
list_del_rcu(&tail->list);
diff --git a/security/selinux/ima.c b/security/selinux/ima.c
index ff7aea6b3774..a915b89d55b0 100644
--- a/security/selinux/ima.c
+++ b/security/selinux/ima.c
@@ -29,7 +29,7 @@ static char *selinux_ima_collect_state(struct selinux_state *state)
buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
len = strlen(on);
- for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++)
+ for (i = 0; i < __POLICYDB_CAP_MAX; i++)
buf_len += strlen(selinux_policycap_names[i]) + len;
buf = kzalloc(buf_len, GFP_KERNEL);
@@ -54,7 +54,7 @@ static char *selinux_ima_collect_state(struct selinux_state *state)
rc = strlcat(buf, checkreqprot_get(state) ? on : off, buf_len);
WARN_ON(rc >= buf_len);
- for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++) {
+ for (i = 0; i < __POLICYDB_CAP_MAX; i++) {
rc = strlcat(buf, selinux_policycap_names[i], buf_len);
WARN_ON(rc >= buf_len);
diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h
index 2ec038efbb03..2680aa21205c 100644
--- a/security/selinux/include/policycap.h
+++ b/security/selinux/include/policycap.h
@@ -4,17 +4,18 @@
/* Policy capabilities */
enum {
- POLICYDB_CAPABILITY_NETPEER,
- POLICYDB_CAPABILITY_OPENPERM,
- POLICYDB_CAPABILITY_EXTSOCKCLASS,
- POLICYDB_CAPABILITY_ALWAYSNETWORK,
- POLICYDB_CAPABILITY_CGROUPSECLABEL,
- POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
- POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS,
- __POLICYDB_CAPABILITY_MAX
+ POLICYDB_CAP_NETPEER,
+ POLICYDB_CAP_OPENPERM,
+ POLICYDB_CAP_EXTSOCKCLASS,
+ POLICYDB_CAP_ALWAYSNETWORK,
+ POLICYDB_CAP_CGROUPSECLABEL,
+ POLICYDB_CAP_NNP_NOSUID_TRANSITION,
+ POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS,
+ POLICYDB_CAP_IOCTL_SKIP_CLOEXEC,
+ __POLICYDB_CAP_MAX
};
-#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
+#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)
-extern const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
+extern const char *selinux_policycap_names[__POLICYDB_CAP_MAX];
#endif /* _SELINUX_POLICYCAP_H_ */
diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h
index b89289f092c9..100da7d043db 100644
--- a/security/selinux/include/policycap_names.h
+++ b/security/selinux/include/policycap_names.h
@@ -5,14 +5,15 @@
#include "policycap.h"
/* Policy capability names */
-const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
+const char *selinux_policycap_names[__POLICYDB_CAP_MAX] = {
"network_peer_controls",
"open_perms",
"extended_socket_class",
"always_check_network",
"cgroup_seclabel",
"nnp_nosuid_transition",
- "genfs_seclabel_symlinks"
+ "genfs_seclabel_symlinks",
+ "ioctl_skip_cloexec"
};
#endif /* _SELINUX_POLICYCAP_NAMES_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ac0ece01305a..ace4bd13e808 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -96,7 +96,7 @@ struct selinux_state {
#endif
bool checkreqprot;
bool initialized;
- bool policycap[__POLICYDB_CAPABILITY_MAX];
+ bool policycap[__POLICYDB_CAP_MAX];
struct page *status_page;
struct mutex status_lock;
@@ -174,49 +174,56 @@ static inline bool selinux_policycap_netpeer(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_NETPEER]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_NETPEER]);
}
static inline bool selinux_policycap_openperm(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_OPENPERM]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_OPENPERM]);
}
static inline bool selinux_policycap_extsockclass(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_EXTSOCKCLASS]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_EXTSOCKCLASS]);
}
static inline bool selinux_policycap_alwaysnetwork(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_ALWAYSNETWORK]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_ALWAYSNETWORK]);
}
static inline bool selinux_policycap_cgroupseclabel(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_CGROUPSECLABEL]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_CGROUPSECLABEL]);
}
static inline bool selinux_policycap_nnp_nosuid_transition(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_NNP_NOSUID_TRANSITION]);
}
static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS]);
+}
+
+static inline bool selinux_policycap_ioctl_skip_cloexec(void)
+{
+ struct selinux_state *state = &selinux_state;
+
+ return READ_ONCE(state->policycap[POLICYDB_CAP_IOCTL_SKIP_CLOEXEC]);
}
struct selinux_policy_convert_data;
@@ -254,8 +261,8 @@ struct av_decision {
#define XPERMS_AUDITALLOW 2
#define XPERMS_DONTAUDIT 4
-#define security_xperm_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f))
-#define security_xperm_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f)))
+#define security_xperm_set(perms, x) ((perms)[(x) >> 5] |= 1 << ((x) & 0x1f))
+#define security_xperm_test(perms, x) (1 & ((perms)[(x) >> 5] >> ((x) & 0x1f)))
struct extended_perms_data {
u32 p[8];
};
@@ -386,11 +393,11 @@ int security_get_allow_unknown(struct selinux_state *state);
int security_fs_use(struct selinux_state *state, struct super_block *sb);
int security_genfs_sid(struct selinux_state *state,
- const char *fstype, char *name, u16 sclass,
+ const char *fstype, const char *path, u16 sclass,
u32 *sid);
int selinux_policy_genfs_sid(struct selinux_policy *policy,
- const char *fstype, char *name, u16 sclass,
+ const char *fstype, const char *path, u16 sclass,
u32 *sid);
#ifdef CONFIG_NETLABEL
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 4a7d2ab5b960..0ac7df9a9367 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -107,7 +107,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
switch (family) {
case PF_INET:
- idx = sel_netnode_hashfn_ipv4(*(__be32 *)addr);
+ idx = sel_netnode_hashfn_ipv4(*(const __be32 *)addr);
break;
case PF_INET6:
idx = sel_netnode_hashfn_ipv6(addr);
@@ -121,7 +121,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
if (node->nsec.family == family)
switch (family) {
case PF_INET:
- if (node->nsec.addr.ipv4 == *(__be32 *)addr)
+ if (node->nsec.addr.ipv4 == *(const __be32 *)addr)
return node;
break;
case PF_INET6:
@@ -164,8 +164,9 @@ static void sel_netnode_insert(struct sel_netnode *node)
if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) {
struct sel_netnode *tail;
tail = list_entry(
- rcu_dereference_protected(sel_netnode_hash[idx].list.prev,
- lockdep_is_held(&sel_netnode_lock)),
+ rcu_dereference_protected(
+ list_tail_rcu(&sel_netnode_hash[idx].list),
+ lockdep_is_held(&sel_netnode_lock)),
struct sel_netnode, list);
list_del_rcu(&tail->list);
kfree_rcu(tail, rcu);
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 9ba09d11c0f5..8eec6347cf01 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -113,7 +113,7 @@ static void sel_netport_insert(struct sel_netport *port)
struct sel_netport *tail;
tail = list_entry(
rcu_dereference_protected(
- sel_netport_hash[idx].list.prev,
+ list_tail_rcu(&sel_netport_hash[idx].list),
lockdep_is_held(&sel_netport_lock)),
struct sel_netport, list);
list_del_rcu(&tail->list);
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 94ea2a8b2bb7..d8ceee9e0d6f 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -76,6 +76,7 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_GETNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_SETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_NEWCACHEREPORT, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
@@ -91,6 +92,9 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_NEWNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
};
static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
@@ -176,7 +180,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
* structures at the top of this file with the new mappings
* before updating the BUILD_BUG_ON() macro!
*/
- BUILD_BUG_ON(RTM_MAX != (RTM_NEWNEXTHOPBUCKET + 3));
+ BUILD_BUG_ON(RTM_MAX != (RTM_NEWTUNNEL + 3));
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
sizeof(nlmsg_route_perms));
break;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index e4cd7cb856f3..097c6d866ec4 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1983,7 +1983,7 @@ static int sel_make_policycap(struct selinux_fs_info *fsi)
struct dentry *dentry = NULL;
struct inode *inode = NULL;
- for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
+ for (iter = 0; iter <= POLICYDB_CAP_MAX; iter++) {
if (iter < ARRAY_SIZE(selinux_policycap_names))
dentry = d_alloc_name(fsi->policycap_dir,
selinux_policycap_names[iter]);
@@ -2127,6 +2127,8 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
}
ret = sel_make_avc_files(dentry);
+ if (ret)
+ goto err;
dentry = sel_make_dir(sb->s_root, "ss", &fsi->last_ino);
if (IS_ERR(dentry)) {
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index c97695ae508f..cfdae20792e1 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -67,7 +67,7 @@ static inline int avtab_hash(const struct avtab_key *keyp, u32 mask)
static struct avtab_node*
avtab_insert_node(struct avtab *h, int hvalue,
- struct avtab_node *prev, struct avtab_node *cur,
+ struct avtab_node *prev,
const struct avtab_key *key, const struct avtab_datum *datum)
{
struct avtab_node *newnode;
@@ -137,7 +137,7 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key,
break;
}
- newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
+ newnode = avtab_insert_node(h, hvalue, prev, key, datum);
if (!newnode)
return -ENOMEM;
@@ -177,7 +177,7 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h,
key->target_class < cur->key.target_class)
break;
}
- return avtab_insert_node(h, hvalue, prev, cur, key, datum);
+ return avtab_insert_node(h, hvalue, prev, key, datum);
}
struct avtab_datum *avtab_search(struct avtab *h, const struct avtab_key *key)
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index feb206f3acb4..e11219fdf9f7 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -567,8 +567,6 @@ void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
if (node->key.specified & AVTAB_ENABLED)
services_compute_xperms_decision(xpermd, node);
}
- return;
-
}
/* Determine whether additional permissions are granted by the conditional
* av table, and if so, add them to the result
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 61fcbb8d0f88..abde349c8321 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -359,7 +359,6 @@ void ebitmap_destroy(struct ebitmap *e)
e->highbit = 0;
e->node = NULL;
- return;
}
int ebitmap_read(struct ebitmap *e, void *fp)
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 9eb2d0af2805..58eb822f11ee 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -118,9 +118,9 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
}
#define ebitmap_for_each_positive_bit(e, n, bit) \
- for (bit = ebitmap_start_positive(e, &n); \
- bit < ebitmap_length(e); \
- bit = ebitmap_next_positive(e, &n, bit)) \
+ for ((bit) = ebitmap_start_positive(e, &(n)); \
+ (bit) < ebitmap_length(e); \
+ (bit) = ebitmap_next_positive(e, &(n), bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 3f5fd124342c..99571b19d4a9 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -156,7 +156,6 @@ void mls_sid_to_context(struct policydb *p,
}
*scontext = scontextp;
- return;
}
int mls_level_isvalid(struct policydb *p, struct mls_level *l)
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 0ae1b718194a..d036e1238e77 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -41,8 +41,6 @@
#include "mls.h"
#include "services.h"
-#define _DEBUG_HASHES
-
#ifdef DEBUG_HASHES
static const char *symtab_name[SYM_NUM] = {
"common prefixes",
@@ -704,7 +702,7 @@ static void symtab_hash_eval(struct symtab *s)
}
#else
-static inline void hash_eval(struct hashtab *h, char *hash_name)
+static inline void hash_eval(struct hashtab *h, const char *hash_name)
{
}
#endif
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 8e92af7dd284..6901dc07680d 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -529,8 +529,6 @@ out:
/* release scontext/tcontext */
kfree(tcontext_name);
kfree(scontext_name);
-
- return;
}
/*
@@ -1452,7 +1450,7 @@ static int string_to_context_struct(struct policydb *pol,
/* Parse the security context. */
rc = -EINVAL;
- scontextp = (char *) scontext;
+ scontextp = scontext;
/* Extract the user. */
p = scontextp;
@@ -2875,7 +2873,7 @@ out_unlock:
*/
static inline int __security_genfs_sid(struct selinux_policy *policy,
const char *fstype,
- char *path,
+ const char *path,
u16 orig_sclass,
u32 *sid)
{
@@ -2928,7 +2926,7 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
*/
int security_genfs_sid(struct selinux_state *state,
const char *fstype,
- char *path,
+ const char *path,
u16 orig_sclass,
u32 *sid)
{
@@ -2952,7 +2950,7 @@ int security_genfs_sid(struct selinux_state *state,
int selinux_policy_genfs_sid(struct selinux_policy *policy,
const char *fstype,
- char *path,
+ const char *path,
u16 orig_sclass,
u32 *sid)
{
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 293ec048af08..a54b8652bfb5 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -27,8 +27,8 @@ struct sidtab_str_cache {
char str[];
};
-#define index_to_sid(index) (index + SECINITSID_NUM + 1)
-#define sid_to_index(sid) (sid - (SECINITSID_NUM + 1))
+#define index_to_sid(index) ((index) + SECINITSID_NUM + 1)
+#define sid_to_index(sid) ((sid) - (SECINITSID_NUM + 1))
int sidtab_init(struct sidtab *s)
{
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 90697317895f..c576832febc6 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -347,7 +347,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
int rc;
struct xfrm_sec_ctx *ctx;
char *ctx_str = NULL;
- int str_len;
+ u32 str_len;
if (!polsec)
return 0;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 14b279cc75c9..6207762dbdb1 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2510,7 +2510,7 @@ static int smk_ipv6_check(struct smack_known *subject,
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
ad.a.u.net->family = PF_INET6;
- ad.a.u.net->dport = ntohs(address->sin6_port);
+ ad.a.u.net->dport = address->sin6_port;
if (act == SMK_RECEIVING)
ad.a.u.net->v6info.saddr = address->sin6_addr;
else
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c
index 3445ae6fd479..363b65be87ab 100644
--- a/security/tomoyo/load_policy.c
+++ b/security/tomoyo/load_policy.c
@@ -24,7 +24,7 @@ static const char *tomoyo_loader;
static int __init tomoyo_loader_setup(char *str)
{
tomoyo_loader = str;
- return 0;
+ return 1;
}
__setup("TOMOYO_loader=", tomoyo_loader_setup);
@@ -64,7 +64,7 @@ static const char *tomoyo_trigger;
static int __init tomoyo_trigger_setup(char *str)
{
tomoyo_trigger = str;
- return 0;
+ return 1;
}
__setup("TOMOYO_trigger=", tomoyo_trigger_setup);