diff options
Diffstat (limited to 'security')
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(¶m, 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(¶m, 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(¶m, 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(¤t->sighand->siglock); + spin_lock_irq(&unrcu_pointer(current->sighand)->siglock); if (!fatal_signal_pending(current)) { flush_sigqueue(¤t->pending); flush_sigqueue(¤t->signal->shared_pending); @@ -2543,13 +2529,13 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) sigemptyset(¤t->blocked); recalc_sigpending(); } - spin_unlock_irq(¤t->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); |