From b20732900e4636a467c0183a47f7396700f5f743 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 7 Aug 2024 15:11:22 +0200 Subject: Adding upstream version 6.9.7. Signed-off-by: Daniel Baumann --- security/Kconfig | 2 - security/apparmor/audit.c | 6 +- security/apparmor/include/audit.h | 2 +- security/integrity/Makefile | 1 + security/integrity/digsig_asymmetric.c | 23 - security/integrity/evm/Kconfig | 1 + security/integrity/evm/evm.h | 19 + security/integrity/evm/evm_crypto.c | 4 +- security/integrity/evm/evm_main.c | 195 +++++-- security/integrity/iint.c | 197 +------ security/integrity/ima/Kconfig | 1 + security/integrity/ima/Makefile | 2 +- security/integrity/ima/ima.h | 150 ++++- security/integrity/ima/ima_api.c | 39 +- security/integrity/ima/ima_appraise.c | 66 ++- security/integrity/ima/ima_iint.c | 142 +++++ security/integrity/ima/ima_init.c | 2 +- security/integrity/ima/ima_main.c | 148 +++-- security/integrity/ima/ima_policy.c | 17 +- security/integrity/ima/ima_template_lib.c | 17 +- security/integrity/integrity.h | 80 +-- security/keys/key.c | 10 +- security/landlock/.kunitconfig | 4 + security/landlock/Kconfig | 15 + security/landlock/Makefile | 2 +- security/landlock/common.h | 2 + security/landlock/fs.c | 265 ++++++++- security/landlock/net.c | 7 +- security/landlock/ptrace.c | 120 ---- security/landlock/ptrace.h | 14 - security/landlock/setup.c | 4 +- security/landlock/task.c | 120 ++++ security/landlock/task.h | 14 + security/security.c | 876 ++++++++++++++++-------------- security/selinux/hooks.c | 78 ++- security/selinux/include/audit.h | 4 +- security/selinux/ss/avtab.c | 105 ++-- security/selinux/ss/avtab.h | 74 +-- security/selinux/ss/conditional.c | 68 ++- security/selinux/ss/conditional.h | 23 +- security/selinux/ss/constraint.h | 67 +-- security/selinux/ss/context.c | 2 +- security/selinux/ss/context.h | 41 +- security/selinux/ss/ebitmap.c | 56 +- security/selinux/ss/ebitmap.h | 42 +- security/selinux/ss/hashtab.c | 23 +- security/selinux/ss/hashtab.h | 35 +- security/selinux/ss/mls.c | 83 ++- security/selinux/ss/mls.h | 58 +- security/selinux/ss/mls_types.h | 32 +- security/selinux/ss/policydb.c | 405 +++++++------- security/selinux/ss/policydb.h | 192 ++++--- security/selinux/ss/services.c | 5 +- security/selinux/ss/services.h | 3 +- security/selinux/ss/sidtab.c | 69 +-- security/selinux/ss/sidtab.h | 36 +- security/selinux/ss/symtab.c | 4 +- security/selinux/ss/symtab.h | 9 +- security/smack/smack_lsm.c | 98 ++-- 59 files changed, 2375 insertions(+), 1804 deletions(-) create mode 100644 security/integrity/ima/ima_iint.c create mode 100644 security/landlock/.kunitconfig delete mode 100644 security/landlock/ptrace.c delete mode 100644 security/landlock/ptrace.h create mode 100644 security/landlock/task.c create mode 100644 security/landlock/task.h (limited to 'security') diff --git a/security/Kconfig b/security/Kconfig index 52c9af08ad..412e76f157 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -142,8 +142,6 @@ config HARDENED_USERCOPY config FORTIFY_SOURCE bool "Harden common str/mem functions against buffer overflows" depends on ARCH_HAS_FORTIFY_SOURCE - # https://bugs.llvm.org/show_bug.cgi?id=41459 - depends on !CC_IS_CLANG || CLANG_VERSION >= 120001 # https://github.com/llvm/llvm-project/issues/53645 depends on !CC_IS_CLANG || !X86_32 help diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 45beb1c5f7..6b5181c668 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -217,7 +217,7 @@ void aa_audit_rule_free(void *vrule) } } -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, gfp_t gfp) { struct aa_audit_rule *rule; @@ -230,14 +230,14 @@ int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) return -EINVAL; } - rule = kzalloc(sizeof(struct aa_audit_rule), GFP_KERNEL); + rule = kzalloc(sizeof(struct aa_audit_rule), gfp); if (!rule) return -ENOMEM; /* Currently rules are treated as coming from the root ns */ rule->label = aa_label_parse(&root_ns->unconfined->label, rulestr, - GFP_KERNEL, true, false); + gfp, true, false); if (IS_ERR(rule->label)) { int err = PTR_ERR(rule->label); aa_audit_rule_free(rule); diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index acbb03b9bd..0c8cc86b41 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -200,7 +200,7 @@ static inline int complain_error(int error) } void aa_audit_rule_free(void *vrule); -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule); +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, gfp_t gfp); int aa_audit_rule_known(struct audit_krule *rule); int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule); diff --git a/security/integrity/Makefile b/security/integrity/Makefile index d0ffe37dc1..92b63039c6 100644 --- a/security/integrity/Makefile +++ b/security/integrity/Makefile @@ -18,5 +18,6 @@ integrity-$(CONFIG_LOAD_IPL_KEYS) += platform_certs/load_ipl_s390.o integrity-$(CONFIG_LOAD_PPC_KEYS) += platform_certs/efi_parser.o \ platform_certs/load_powerpc.o \ platform_certs/keyring_handler.o +# The relative order of the 'ima' and 'evm' LSMs depends on the order below. obj-$(CONFIG_IMA) += ima/ obj-$(CONFIG_EVM) += evm/ diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 895f4b9ce8..de603cf42a 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -132,26 +132,3 @@ out: pr_debug("%s() = %d\n", __func__, ret); return ret; } - -/** - * integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests - * @kmod_name: kernel module name - * - * We have situation, when public_key_verify_signature() in case of RSA - * algorithm use alg_name to store internal information in order to - * construct an algorithm on the fly, but crypto_larval_lookup() will try - * to use alg_name in order to load kernel module with same name. - * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules, - * we are safe to fail such module request from crypto_larval_lookup(). - * - * In this way we prevent modprobe execution during digsig verification - * and avoid possible deadlock if modprobe and/or it's dependencies - * also signed with digsig. - */ -int integrity_kernel_module_request(char *kmod_name) -{ - if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0) - return -EINVAL; - - return 0; -} diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index fba9ee359b..861b3bacab 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -6,6 +6,7 @@ config EVM select CRYPTO_HMAC select CRYPTO_SHA1 select CRYPTO_HASH_INFO + select SECURITY_PATH default n help EVM protects a file's security extended attributes against diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 53bd7fec93..eb1a2c343b 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -32,6 +32,25 @@ struct xattr_list { bool enabled; }; +#define EVM_NEW_FILE 0x00000001 +#define EVM_IMMUTABLE_DIGSIG 0x00000002 + +/* EVM integrity metadata associated with an inode */ +struct evm_iint_cache { + unsigned long flags; + enum integrity_status evm_status:4; +}; + +extern struct lsm_blob_sizes evm_blob_sizes; + +static inline struct evm_iint_cache *evm_iint_inode(const struct inode *inode) +{ + if (unlikely(!inode->i_security)) + return NULL; + + return inode->i_security + evm_blob_sizes.lbs_inode; +} + extern int evm_initialized; #define EVM_ATTR_FSUUID 0x0001 diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index b1ffd4cc0b..7552d49d07 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -322,10 +322,10 @@ int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, static int evm_is_immutable(struct dentry *dentry, struct inode *inode) { const struct evm_ima_xattr_data *xattr_data = NULL; - struct integrity_iint_cache *iint; + struct evm_iint_cache *iint; int rc = 0; - iint = integrity_iint_find(inode); + iint = evm_iint_inode(inode); if (iint && (iint->flags & EVM_IMMUTABLE_DIGSIG)) return 1; diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index cc7956d787..81dbade5b9 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -178,14 +178,14 @@ static int is_unsupported_fs(struct dentry *dentry) static enum integrity_status evm_verify_hmac(struct dentry *dentry, const char *xattr_name, char *xattr_value, - size_t xattr_value_len, - struct integrity_iint_cache *iint) + size_t xattr_value_len) { struct evm_ima_xattr_data *xattr_data = NULL; struct signature_v2_hdr *hdr; enum integrity_status evm_status = INTEGRITY_PASS; struct evm_digest digest; - struct inode *inode; + struct inode *inode = d_backing_inode(dentry); + struct evm_iint_cache *iint = evm_iint_inode(inode); int rc, xattr_len, evm_immutable = 0; if (iint && (iint->evm_status == INTEGRITY_PASS || @@ -254,8 +254,6 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, (const char *)xattr_data, xattr_len, digest.digest, digest.hdr.length); if (!rc) { - inode = d_backing_inode(dentry); - if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) { if (iint) iint->flags |= EVM_IMMUTABLE_DIGSIG; @@ -403,7 +401,6 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, * @xattr_name: requested xattr * @xattr_value: requested xattr value * @xattr_value_len: requested xattr value length - * @iint: inode integrity metadata * * Calculate the HMAC for the given dentry and verify it against the stored * security.evm xattr. For performance, use the xattr value and length @@ -416,8 +413,7 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, */ enum integrity_status evm_verifyxattr(struct dentry *dentry, const char *xattr_name, - void *xattr_value, size_t xattr_value_len, - struct integrity_iint_cache *iint) + void *xattr_value, size_t xattr_value_len) { if (!evm_key_loaded() || !evm_protected_xattr(xattr_name)) return INTEGRITY_UNKNOWN; @@ -425,13 +421,8 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry, if (is_unsupported_fs(dentry)) return INTEGRITY_UNKNOWN; - if (!iint) { - iint = integrity_iint_find(d_backing_inode(dentry)); - if (!iint) - return INTEGRITY_UNKNOWN; - } return evm_verify_hmac(dentry, xattr_name, xattr_value, - xattr_value_len, iint); + xattr_value_len); } EXPORT_SYMBOL_GPL(evm_verifyxattr); @@ -448,7 +439,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry) if (!evm_key_loaded() || !S_ISREG(inode->i_mode) || evm_fixmode) return INTEGRITY_PASS; - return evm_verify_hmac(dentry, NULL, NULL, 0, NULL); + return evm_verify_hmac(dentry, NULL, NULL, 0); } /* @@ -526,14 +517,14 @@ static int evm_protect_xattr(struct mnt_idmap *idmap, evm_status = evm_verify_current_integrity(dentry); if (evm_status == INTEGRITY_NOXATTRS) { - struct integrity_iint_cache *iint; + struct evm_iint_cache *iint; /* Exception if the HMAC is not going to be calculated. */ if (evm_hmac_disabled()) return 0; - iint = integrity_iint_find(d_backing_inode(dentry)); - if (iint && (iint->flags & IMA_NEW_FILE)) + iint = evm_iint_inode(d_backing_inode(dentry)); + if (iint && (iint->flags & EVM_NEW_FILE)) return 0; /* exception for pseudo filesystems */ @@ -581,6 +572,7 @@ out: * @xattr_name: pointer to the affected extended attribute name * @xattr_value: pointer to the new extended attribute value * @xattr_value_len: pointer to the new extended attribute value length + * @flags: flags to pass into filesystem operations * * Before allowing the 'security.evm' protected xattr to be updated, * verify the existing value is valid. As only the kernel should have @@ -588,9 +580,9 @@ out: * userspace from writing HMAC value. Writing 'security.evm' requires * requires CAP_SYS_ADMIN privileges. */ -int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, - const char *xattr_name, const void *xattr_value, - size_t xattr_value_len) +static int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, + const char *xattr_name, const void *xattr_value, + size_t xattr_value_len, int flags) { const struct evm_ima_xattr_data *xattr_data = xattr_value; @@ -620,8 +612,8 @@ int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that * the current value is valid. */ -int evm_inode_removexattr(struct mnt_idmap *idmap, - struct dentry *dentry, const char *xattr_name) +static int evm_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry, + const char *xattr_name) { /* Policy permits modification of the protected xattrs even though * there's no HMAC key loaded @@ -671,9 +663,11 @@ static inline int evm_inode_set_acl_change(struct mnt_idmap *idmap, * Prevent modifying posix acls causing the EVM HMAC to be re-calculated * and 'security.evm' xattr updated, unless the existing 'security.evm' is * valid. + * + * Return: zero on success, -EPERM on failure. */ -int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, - const char *acl_name, struct posix_acl *kacl) +static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, + const char *acl_name, struct posix_acl *kacl) { enum integrity_status evm_status; @@ -712,11 +706,29 @@ int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, return -EPERM; } +/** + * evm_inode_remove_acl - Protect the EVM extended attribute from posix acls + * @idmap: idmap of the mount + * @dentry: pointer to the affected dentry + * @acl_name: name of the posix acl + * + * Prevent removing posix acls causing the EVM HMAC to be re-calculated + * and 'security.evm' xattr updated, unless the existing 'security.evm' is + * valid. + * + * Return: zero on success, -EPERM on failure. + */ +static int evm_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry, + const char *acl_name) +{ + return evm_inode_set_acl(idmap, dentry, acl_name, NULL); +} + static void evm_reset_status(struct inode *inode) { - struct integrity_iint_cache *iint; + struct evm_iint_cache *iint; - iint = integrity_iint_find(inode); + iint = evm_iint_inode(inode); if (iint) iint->evm_status = INTEGRITY_UNKNOWN; } @@ -752,6 +764,7 @@ bool evm_revalidate_status(const char *xattr_name) * @xattr_name: pointer to the affected extended attribute name * @xattr_value: pointer to the new extended attribute value * @xattr_value_len: pointer to the new extended attribute value length + * @flags: flags to pass into filesystem operations * * Update the HMAC stored in 'security.evm' to reflect the change. * @@ -759,8 +772,11 @@ bool evm_revalidate_status(const char *xattr_name) * __vfs_setxattr_noperm(). The caller of which has taken the inode's * i_mutex lock. */ -void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, - const void *xattr_value, size_t xattr_value_len) +static void evm_inode_post_setxattr(struct dentry *dentry, + const char *xattr_name, + const void *xattr_value, + size_t xattr_value_len, + int flags) { if (!evm_revalidate_status(xattr_name)) return; @@ -779,6 +795,21 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len); } +/** + * evm_inode_post_set_acl - Update the EVM extended attribute from posix acls + * @dentry: pointer to the affected dentry + * @acl_name: name of the posix acl + * @kacl: pointer to the posix acls + * + * Update the 'security.evm' xattr with the EVM HMAC re-calculated after setting + * posix acls. + */ +static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name, + struct posix_acl *kacl) +{ + return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0); +} + /** * evm_inode_post_removexattr - update 'security.evm' after removing the xattr * @dentry: pointer to the affected dentry @@ -789,7 +820,8 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, * No need to take the i_mutex lock here, as this function is called from * vfs_removexattr() which takes the i_mutex. */ -void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) +static void evm_inode_post_removexattr(struct dentry *dentry, + const char *xattr_name) { if (!evm_revalidate_status(xattr_name)) return; @@ -805,6 +837,22 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) evm_update_evmxattr(dentry, xattr_name, NULL, 0); } +/** + * evm_inode_post_remove_acl - Update the EVM extended attribute from posix acls + * @idmap: idmap of the mount + * @dentry: pointer to the affected dentry + * @acl_name: name of the posix acl + * + * Update the 'security.evm' xattr with the EVM HMAC re-calculated after + * removing posix acls. + */ +static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap, + struct dentry *dentry, + const char *acl_name) +{ + evm_inode_post_removexattr(dentry, acl_name); +} + static int evm_attr_change(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr) { @@ -828,8 +876,8 @@ static int evm_attr_change(struct mnt_idmap *idmap, * Permit update of file attributes when files have a valid EVM signature, * except in the case of them having an immutable portable signature. */ -int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, - struct iattr *attr) +static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + struct iattr *attr) { unsigned int ia_valid = attr->ia_valid; enum integrity_status evm_status; @@ -870,6 +918,7 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, /** * evm_inode_post_setattr - update 'security.evm' after modifying metadata + * @idmap: idmap of the idmapped mount * @dentry: pointer to the affected dentry * @ia_valid: for the UID and GID status * @@ -879,7 +928,8 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, * This function is called from notify_change(), which expects the caller * to lock the inode's i_mutex. */ -void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) +static void evm_inode_post_setattr(struct mnt_idmap *idmap, + struct dentry *dentry, int ia_valid) { if (!evm_revalidate_status(NULL)) return; @@ -896,7 +946,7 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) evm_update_evmxattr(dentry, NULL, NULL, 0); } -int evm_inode_copy_up_xattr(const char *name) +static int evm_inode_copy_up_xattr(const char *name) { if (strcmp(name, XATTR_NAME_EVM) == 0) return 1; /* Discard */ @@ -960,6 +1010,42 @@ out: } EXPORT_SYMBOL_GPL(evm_inode_init_security); +static int evm_inode_alloc_security(struct inode *inode) +{ + struct evm_iint_cache *iint = evm_iint_inode(inode); + + /* Called by security_inode_alloc(), it cannot be NULL. */ + iint->flags = 0UL; + iint->evm_status = INTEGRITY_UNKNOWN; + + return 0; +} + +static void evm_file_release(struct file *file) +{ + struct inode *inode = file_inode(file); + struct evm_iint_cache *iint = evm_iint_inode(inode); + fmode_t mode = file->f_mode; + + if (!S_ISREG(inode->i_mode) || !(mode & FMODE_WRITE)) + return; + + if (iint && atomic_read(&inode->i_writecount) == 1) + iint->flags &= ~EVM_NEW_FILE; +} + +static void evm_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry) +{ + struct inode *inode = d_backing_inode(dentry); + struct evm_iint_cache *iint = evm_iint_inode(inode); + + if (!S_ISREG(inode->i_mode)) + return; + + if (iint) + iint->flags |= EVM_NEW_FILE; +} + #ifdef CONFIG_EVM_LOAD_X509 void __init evm_load_x509(void) { @@ -999,4 +1085,45 @@ error: return error; } +static struct security_hook_list evm_hooks[] __ro_after_init = { + LSM_HOOK_INIT(inode_setattr, evm_inode_setattr), + LSM_HOOK_INIT(inode_post_setattr, evm_inode_post_setattr), + LSM_HOOK_INIT(inode_copy_up_xattr, evm_inode_copy_up_xattr), + LSM_HOOK_INIT(inode_setxattr, evm_inode_setxattr), + LSM_HOOK_INIT(inode_post_setxattr, evm_inode_post_setxattr), + LSM_HOOK_INIT(inode_set_acl, evm_inode_set_acl), + LSM_HOOK_INIT(inode_post_set_acl, evm_inode_post_set_acl), + LSM_HOOK_INIT(inode_remove_acl, evm_inode_remove_acl), + LSM_HOOK_INIT(inode_post_remove_acl, evm_inode_post_remove_acl), + LSM_HOOK_INIT(inode_removexattr, evm_inode_removexattr), + LSM_HOOK_INIT(inode_post_removexattr, evm_inode_post_removexattr), + LSM_HOOK_INIT(inode_init_security, evm_inode_init_security), + LSM_HOOK_INIT(inode_alloc_security, evm_inode_alloc_security), + LSM_HOOK_INIT(file_release, evm_file_release), + LSM_HOOK_INIT(path_post_mknod, evm_post_path_mknod), +}; + +static const struct lsm_id evm_lsmid = { + .name = "evm", + .id = LSM_ID_EVM, +}; + +static int __init init_evm_lsm(void) +{ + security_add_hooks(evm_hooks, ARRAY_SIZE(evm_hooks), &evm_lsmid); + return 0; +} + +struct lsm_blob_sizes evm_blob_sizes __ro_after_init = { + .lbs_inode = sizeof(struct evm_iint_cache), + .lbs_xattr_count = 1, +}; + +DEFINE_LSM(evm) = { + .name = "evm", + .init = init_evm_lsm, + .order = LSM_ORDER_LAST, + .blobs = &evm_blob_sizes, +}; + late_initcall(init_evm); diff --git a/security/integrity/iint.c b/security/integrity/iint.c index d4419a2a1e..068ac6c2ae 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -6,207 +6,14 @@ * Mimi Zohar * * File: integrity_iint.c - * - implements the integrity hooks: integrity_inode_alloc, - * integrity_inode_free - * - cache integrity information associated with an inode - * using a rbtree tree. + * - initialize the integrity directory in securityfs + * - load IMA and EVM keys */ -#include -#include -#include -#include -#include -#include #include -#include #include "integrity.h" -static struct rb_root integrity_iint_tree = RB_ROOT; -static DEFINE_RWLOCK(integrity_iint_lock); -static struct kmem_cache *iint_cache __ro_after_init; - struct dentry *integrity_dir; -/* - * __integrity_iint_find - return the iint associated with an inode - */ -static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode) -{ - struct integrity_iint_cache *iint; - struct rb_node *n = integrity_iint_tree.rb_node; - - while (n) { - iint = rb_entry(n, struct integrity_iint_cache, rb_node); - - if (inode < iint->inode) - n = n->rb_left; - else if (inode > iint->inode) - n = n->rb_right; - else - return iint; - } - - return NULL; -} - -/* - * integrity_iint_find - return the iint associated with an inode - */ -struct integrity_iint_cache *integrity_iint_find(struct inode *inode) -{ - struct integrity_iint_cache *iint; - - if (!IS_IMA(inode)) - return NULL; - - read_lock(&integrity_iint_lock); - iint = __integrity_iint_find(inode); - read_unlock(&integrity_iint_lock); - - return iint; -} - -#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH+1) - -/* - * It is not clear that IMA should be nested at all, but as long is it measures - * files both on overlayfs and on underlying fs, we need to annotate the iint - * mutex to avoid lockdep false positives related to IMA + overlayfs. - * See ovl_lockdep_annotate_inode_mutex_key() for more details. - */ -static inline void iint_lockdep_annotate(struct integrity_iint_cache *iint, - struct inode *inode) -{ -#ifdef CONFIG_LOCKDEP - static struct lock_class_key iint_mutex_key[IMA_MAX_NESTING]; - - int depth = inode->i_sb->s_stack_depth; - - if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING)) - depth = 0; - - lockdep_set_class(&iint->mutex, &iint_mutex_key[depth]); -#endif -} - -static void iint_init_always(struct integrity_iint_cache *iint, - struct inode *inode) -{ - iint->ima_hash = NULL; - iint->version = 0; - iint->flags = 0UL; - iint->atomic_flags = 0UL; - iint->ima_file_status = INTEGRITY_UNKNOWN; - iint->ima_mmap_status = INTEGRITY_UNKNOWN; - iint->ima_bprm_status = INTEGRITY_UNKNOWN; - iint->ima_read_status = INTEGRITY_UNKNOWN; - iint->ima_creds_status = INTEGRITY_UNKNOWN; - iint->evm_status = INTEGRITY_UNKNOWN; - iint->measured_pcrs = 0; - mutex_init(&iint->mutex); - iint_lockdep_annotate(iint, inode); -} - -static void iint_free(struct integrity_iint_cache *iint) -{ - kfree(iint->ima_hash); - mutex_destroy(&iint->mutex); - kmem_cache_free(iint_cache, iint); -} - -/** - * integrity_inode_get - find or allocate an iint associated with an inode - * @inode: pointer to the inode - * @return: allocated iint - * - * Caller must lock i_mutex - */ -struct integrity_iint_cache *integrity_inode_get(struct inode *inode) -{ - struct rb_node **p; - struct rb_node *node, *parent = NULL; - struct integrity_iint_cache *iint, *test_iint; - - iint = integrity_iint_find(inode); - if (iint) - return iint; - - iint = kmem_cache_alloc(iint_cache, GFP_NOFS); - if (!iint) - return NULL; - - iint_init_always(iint, inode); - - write_lock(&integrity_iint_lock); - - p = &integrity_iint_tree.rb_node; - while (*p) { - parent = *p; - test_iint = rb_entry(parent, struct integrity_iint_cache, - rb_node); - if (inode < test_iint->inode) { - p = &(*p)->rb_left; - } else if (inode > test_iint->inode) { - p = &(*p)->rb_right; - } else { - write_unlock(&integrity_iint_lock); - kmem_cache_free(iint_cache, iint); - return test_iint; - } - } - - iint->inode = inode; - node = &iint->rb_node; - inode->i_flags |= S_IMA; - rb_link_node(node, parent, p); - rb_insert_color(node, &integrity_iint_tree); - - write_unlock(&integrity_iint_lock); - return iint; -} - -/** - * integrity_inode_free - called on security_inode_free - * @inode: pointer to the inode - * - * Free the integrity information(iint) associated with an inode. - */ -void integrity_inode_free(struct inode *inode) -{ - struct integrity_iint_cache *iint; - - if (!IS_IMA(inode)) - return; - - write_lock(&integrity_iint_lock); - iint = __integrity_iint_find(inode); - rb_erase(&iint->rb_node, &integrity_iint_tree); - write_unlock(&integrity_iint_lock); - - iint_free(iint); -} - -static void iint_init_once(void *foo) -{ - struct integrity_iint_cache *iint = (struct integrity_iint_cache *) foo; - - memset(iint, 0, sizeof(*iint)); -} - -static int __init integrity_iintcache_init(void) -{ - iint_cache = - kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache), - 0, SLAB_PANIC, iint_init_once); - return 0; -} -DEFINE_LSM(integrity) = { - .name = "integrity", - .init = integrity_iintcache_init, - .order = LSM_ORDER_LAST, -}; - - /* * integrity_kernel_read - read data from the file * diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index b98bfe9efd..475c326150 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -8,6 +8,7 @@ config IMA select CRYPTO_HMAC select CRYPTO_SHA1 select CRYPTO_HASH_INFO + select SECURITY_PATH select TCG_TPM if HAS_IOMEM select TCG_TIS if TCG_TPM && X86 select TCG_CRB if TCG_TPM && ACPI diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index 2499f2485c..b376d38b4e 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -4,7 +4,7 @@ # Measurement Architecture(IMA). # -obj-$(CONFIG_IMA) += ima.o +obj-$(CONFIG_IMA) += ima.o ima_iint.o ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ ima_policy.o ima_template.o ima_template_lib.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c29db699c9..0a4f274f77 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -60,7 +60,7 @@ extern const char boot_aggregate_name[]; /* IMA event related data */ struct ima_event_data { - struct integrity_iint_cache *iint; + struct ima_iint_cache *iint; struct file *file; const unsigned char *filename; struct evm_ima_xattr_data *xattr_value; @@ -119,6 +119,107 @@ struct ima_kexec_hdr { u64 count; }; +/* IMA iint action cache flags */ +#define IMA_MEASURE 0x00000001 +#define IMA_MEASURED 0x00000002 +#define IMA_APPRAISE 0x00000004 +#define IMA_APPRAISED 0x00000008 +/*#define IMA_COLLECT 0x00000010 do not use this flag */ +#define IMA_COLLECTED 0x00000020 +#define IMA_AUDIT 0x00000040 +#define IMA_AUDITED 0x00000080 +#define IMA_HASH 0x00000100 +#define IMA_HASHED 0x00000200 + +/* IMA 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 +#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000 +#define IMA_MODSIG_ALLOWED 0x20000000 +#define IMA_CHECK_BLACKLIST 0x40000000 +#define IMA_VERITY_REQUIRED 0x80000000 + +#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ + IMA_HASH | IMA_APPRAISE_SUBMASK) +#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \ + IMA_HASHED | IMA_COLLECTED | \ + IMA_APPRAISED_SUBMASK) + +/* IMA iint subaction appraise cache flags */ +#define IMA_FILE_APPRAISE 0x00001000 +#define IMA_FILE_APPRAISED 0x00002000 +#define IMA_MMAP_APPRAISE 0x00004000 +#define IMA_MMAP_APPRAISED 0x00008000 +#define IMA_BPRM_APPRAISE 0x00010000 +#define IMA_BPRM_APPRAISED 0x00020000 +#define IMA_READ_APPRAISE 0x00040000 +#define IMA_READ_APPRAISED 0x00080000 +#define IMA_CREDS_APPRAISE 0x00100000 +#define IMA_CREDS_APPRAISED 0x00200000 +#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ + IMA_BPRM_APPRAISE | IMA_READ_APPRAISE | \ + IMA_CREDS_APPRAISE) +#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ + IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \ + IMA_CREDS_APPRAISED) + +/* IMA iint cache atomic_flags */ +#define IMA_CHANGE_XATTR 0 +#define IMA_UPDATE_XATTR 1 +#define IMA_CHANGE_ATTR 2 +#define IMA_DIGSIG 3 +#define IMA_MUST_MEASURE 4 + +/* IMA integrity metadata associated with an inode */ +struct ima_iint_cache { + struct mutex mutex; /* protects: version, flags, digest */ + u64 version; /* track inode changes */ + unsigned long flags; + unsigned long measured_pcrs; + unsigned long atomic_flags; + unsigned long real_ino; + dev_t real_dev; + enum integrity_status ima_file_status:4; + enum integrity_status ima_mmap_status:4; + enum integrity_status ima_bprm_status:4; + enum integrity_status ima_read_status:4; + enum integrity_status ima_creds_status:4; + struct ima_digest_data *ima_hash; +}; + +extern struct lsm_blob_sizes ima_blob_sizes; + +static inline struct ima_iint_cache * +ima_inode_get_iint(const struct inode *inode) +{ + struct ima_iint_cache **iint_sec; + + if (unlikely(!inode->i_security)) + return NULL; + + iint_sec = inode->i_security + ima_blob_sizes.lbs_inode; + return *iint_sec; +} + +static inline void ima_inode_set_iint(const struct inode *inode, + struct ima_iint_cache *iint) +{ + struct ima_iint_cache **iint_sec; + + if (unlikely(!inode->i_security)) + return; + + iint_sec = inode->i_security + ima_blob_sizes.lbs_inode; + *iint_sec = iint; +} + +struct ima_iint_cache *ima_iint_find(struct inode *inode); +struct ima_iint_cache *ima_inode_get(struct inode *inode); +void ima_inode_free(struct inode *inode); +void __init ima_iintcache_init(void); + extern const int read_idmap[]; #ifdef CONFIG_HAVE_IMA_KEXEC @@ -127,6 +228,12 @@ void ima_load_kexec_buffer(void); static inline void ima_load_kexec_buffer(void) {} #endif /* CONFIG_HAVE_IMA_KEXEC */ +#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS +void ima_post_key_create_or_update(struct key *keyring, struct key *key, + const void *payload, size_t plen, + unsigned long flags, bool create); +#endif + /* * The default binary_runtime_measurements list format is defined as the * platform native format. The canonical format is defined as little-endian. @@ -146,8 +253,8 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, struct ima_template_entry *entry); int ima_calc_boot_aggregate(struct ima_digest_data *hash); void ima_add_violation(struct file *file, const unsigned char *filename, - struct integrity_iint_cache *iint, - const char *op, const char *cause); + struct ima_iint_cache *iint, const char *op, + const char *cause); int ima_init_crypto(void); void ima_putc(struct seq_file *m, void *data, int datalen); void ima_print_digest(struct seq_file *m, u8 *digest, u32 size); @@ -261,10 +368,10 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, struct ima_template_desc **template_desc, const char *func_data, unsigned int *allowed_algos); int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); -int ima_collect_measurement(struct integrity_iint_cache *iint, - struct file *file, void *buf, loff_t size, - enum hash_algo algo, struct modsig *modsig); -void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, +int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file, + void *buf, loff_t size, enum hash_algo algo, + struct modsig *modsig); +void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, @@ -274,7 +381,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap, const char *eventname, enum ima_hooks func, int pcr, const char *func_data, bool buf_hash, u8 *digest, size_t digest_len); -void ima_audit_measurement(struct integrity_iint_cache *iint, +void ima_audit_measurement(struct ima_iint_cache *iint, const unsigned char *filename); int ima_alloc_init_template(struct ima_event_data *event_data, struct ima_template_entry **entry, @@ -312,32 +419,32 @@ int ima_policy_show(struct seq_file *m, void *v); #define IMA_APPRAISE_KEXEC 0x40 #ifdef CONFIG_IMA_APPRAISE -int ima_check_blacklist(struct integrity_iint_cache *iint, +int ima_check_blacklist(struct ima_iint_cache *iint, const struct modsig *modsig, int pcr); -int ima_appraise_measurement(enum ima_hooks func, - struct integrity_iint_cache *iint, +int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig); int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode, int mask, enum ima_hooks func); -void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); -enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, +void ima_update_xattr(struct ima_iint_cache *iint, struct file *file); +enum integrity_status ima_get_cache_status(struct ima_iint_cache *iint, enum ima_hooks func); enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value, int xattr_len); int ima_read_xattr(struct dentry *dentry, struct evm_ima_xattr_data **xattr_value, int xattr_len); +void __init init_ima_appraise_lsm(const struct lsm_id *lsmid); #else -static inline int ima_check_blacklist(struct integrity_iint_cache *iint, +static inline int ima_check_blacklist(struct ima_iint_cache *iint, const struct modsig *modsig, int pcr) { return 0; } static inline int ima_appraise_measurement(enum ima_hooks func, - struct integrity_iint_cache *iint, + struct ima_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, @@ -354,14 +461,13 @@ static inline int ima_must_appraise(struct mnt_idmap *idmap, return 0; } -static inline void ima_update_xattr(struct integrity_iint_cache *iint, +static inline void ima_update_xattr(struct ima_iint_cache *iint, struct file *file) { } -static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache - *iint, - enum ima_hooks func) +static inline enum integrity_status +ima_get_cache_status(struct ima_iint_cache *iint, enum ima_hooks func) { return INTEGRITY_UNKNOWN; } @@ -379,6 +485,10 @@ static inline int ima_read_xattr(struct dentry *dentry, return 0; } +static inline void __init init_ima_appraise_lsm(const struct lsm_id *lsmid) +{ +} + #endif /* CONFIG_IMA_APPRAISE */ #ifdef CONFIG_IMA_APPRAISE_MODSIG @@ -430,7 +540,7 @@ static inline void ima_free_modsig(struct modsig *modsig) #else static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr, - void **lsmrule) + void **lsmrule, gfp_t gfp) { return -EINVAL; } diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 597ea0c4d7..1856981e33 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -131,8 +131,8 @@ int ima_store_template(struct ima_template_entry *entry, * value is invalidated. */ void ima_add_violation(struct file *file, const unsigned char *filename, - struct integrity_iint_cache *iint, - const char *op, const char *cause) + struct ima_iint_cache *iint, const char *op, + const char *cause) { struct ima_template_entry *entry; struct inode *inode = file_inode(file); @@ -201,7 +201,8 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, allowed_algos); } -static bool ima_get_verity_digest(struct integrity_iint_cache *iint, +static bool ima_get_verity_digest(struct ima_iint_cache *iint, + struct inode *inode, struct ima_max_digest_data *hash) { enum hash_algo alg; @@ -211,7 +212,7 @@ static bool ima_get_verity_digest(struct integrity_iint_cache *iint, * On failure, 'measure' policy rules will result in a file data * hash containing 0's. */ - digest_len = fsverity_get_digest(iint->inode, hash->digest, NULL, &alg); + digest_len = fsverity_get_digest(inode, hash->digest, NULL, &alg); if (digest_len == 0) return false; @@ -237,15 +238,15 @@ static bool ima_get_verity_digest(struct integrity_iint_cache *iint, * * Return 0 on success, error code otherwise */ -int ima_collect_measurement(struct integrity_iint_cache *iint, - struct file *file, void *buf, loff_t size, - enum hash_algo algo, struct modsig *modsig) +int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file, + void *buf, loff_t size, enum hash_algo algo, + struct modsig *modsig) { const char *audit_cause = "failed"; struct inode *inode = file_inode(file); struct inode *real_inode = d_real_inode(file_dentry(file)); - const char *filename = file->f_path.dentry->d_name.name; struct ima_max_digest_data hash; + struct name_snapshot filename; struct kstat stat; int result = 0; int length; @@ -280,7 +281,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, memset(&hash.digest, 0, sizeof(hash.digest)); if (iint->flags & IMA_VERITY_REQUIRED) { - if (!ima_get_verity_digest(iint, &hash)) { + if (!ima_get_verity_digest(iint, inode, &hash)) { audit_cause = "no-verity-digest"; result = -ENODATA; } @@ -316,9 +317,13 @@ out: if (file->f_flags & O_DIRECT) audit_cause = "failed(directio)"; + take_dentry_name_snapshot(&filename, file->f_path.dentry); + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, - filename, "collect_data", audit_cause, - result, 0); + filename.name.name, "collect_data", + audit_cause, result, 0); + + release_dentry_name_snapshot(&filename); } return result; } @@ -338,8 +343,8 @@ out: * * Must be called with iint->mutex held. */ -void ima_store_measurement(struct integrity_iint_cache *iint, - struct file *file, const unsigned char *filename, +void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, + const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, struct ima_template_desc *template_desc) @@ -382,7 +387,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, ima_free_template_entry(entry); } -void ima_audit_measurement(struct integrity_iint_cache *iint, +void ima_audit_measurement(struct ima_iint_cache *iint, const unsigned char *filename) { struct audit_buffer *ab; @@ -431,6 +436,7 @@ out: */ const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf) { + struct name_snapshot filename; char *pathname = NULL; *pathbuf = __getname(); @@ -444,7 +450,10 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf) } if (!pathname) { - strscpy(namebuf, path->dentry->d_name.name, NAME_MAX); + take_dentry_name_snapshot(&filename, path->dentry); + strscpy(namebuf, filename.name.name, NAME_MAX); + release_dentry_name_snapshot(&filename); + pathname = namebuf; } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 870dde6770..3497741cae 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -84,8 +84,7 @@ int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode, NULL, NULL, NULL); } -static int ima_fix_xattr(struct dentry *dentry, - struct integrity_iint_cache *iint) +static int ima_fix_xattr(struct dentry *dentry, struct ima_iint_cache *iint) { int rc, offset; u8 algo = iint->ima_hash->algo; @@ -106,7 +105,7 @@ static int ima_fix_xattr(struct dentry *dentry, } /* Return specific func appraised cached result */ -enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, +enum integrity_status ima_get_cache_status(struct ima_iint_cache *iint, enum ima_hooks func) { switch (func) { @@ -126,7 +125,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, } } -static void ima_set_cache_status(struct integrity_iint_cache *iint, +static void ima_set_cache_status(struct ima_iint_cache *iint, enum ima_hooks func, enum integrity_status status) { @@ -152,8 +151,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, } } -static void ima_cache_flags(struct integrity_iint_cache *iint, - enum ima_hooks func) +static void ima_cache_flags(struct ima_iint_cache *iint, enum ima_hooks func) { switch (func) { case MMAP_CHECK: @@ -276,7 +274,7 @@ static int calc_file_id_hash(enum evm_ima_xattr_type type, * * Return 0 on success, error code otherwise. */ -static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, +static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len, enum integrity_status *status, const char **cause) { @@ -443,7 +441,7 @@ static int modsig_verify(enum ima_hooks func, const struct modsig *modsig, * * Returns -EPERM if the hash is blacklisted. */ -int ima_check_blacklist(struct integrity_iint_cache *iint, +int ima_check_blacklist(struct ima_iint_cache *iint, const struct modsig *modsig, int pcr) { enum hash_algo hash_algo; @@ -477,8 +475,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, * * Return 0 on success, error code otherwise */ -int ima_appraise_measurement(enum ima_hooks func, - struct integrity_iint_cache *iint, +int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig) @@ -520,7 +517,7 @@ int ima_appraise_measurement(enum ima_hooks func, } status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, - rc < 0 ? 0 : rc, iint); + rc < 0 ? 0 : rc); switch (status) { case INTEGRITY_PASS: case INTEGRITY_PASS_IMMUTABLE: @@ -603,7 +600,7 @@ out: /* * ima_update_xattr - update 'security.ima' hash value */ -void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) +void ima_update_xattr(struct ima_iint_cache *iint, struct file *file) { struct dentry *dentry = file_dentry(file); int rc = 0; @@ -629,17 +626,18 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) * ima_inode_post_setattr - reflect file metadata changes * @idmap: idmap of the mount the inode was found from * @dentry: pointer to the affected dentry + * @ia_valid: for the UID and GID status * * Changes to a dentry's metadata might result in needing to appraise. * * This function is called from notify_change(), which expects the caller * to lock the inode's i_mutex. */ -void ima_inode_post_setattr(struct mnt_idmap *idmap, - struct dentry *dentry) +static void ima_inode_post_setattr(struct mnt_idmap *idmap, + struct dentry *dentry, int ia_valid) { struct inode *inode = d_backing_inode(dentry); - struct integrity_iint_cache *iint; + struct ima_iint_cache *iint; int action; if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) @@ -647,7 +645,7 @@ void ima_inode_post_setattr(struct mnt_idmap *idmap, return; action = ima_must_appraise(idmap, inode, MAY_ACCESS, POST_SETATTR); - iint = integrity_iint_find(inode); + iint = ima_iint_find(inode); if (iint) { set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); if (!action) @@ -673,12 +671,12 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, static void ima_reset_appraise_flags(struct inode *inode, int digsig) { - struct integrity_iint_cache *iint; + struct ima_iint_cache *iint; if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)) return; - iint = integrity_iint_find(inode); + iint = ima_iint_find(inode); if (!iint) return; iint->measured_pcrs = 0; @@ -749,8 +747,9 @@ static int validate_hash_algo(struct dentry *dentry, return -EACCES; } -int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, - const void *xattr_value, size_t xattr_value_len) +static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, + const char *xattr_name, const void *xattr_value, + size_t xattr_value_len, int flags) { const struct evm_ima_xattr_data *xvalue = xattr_value; int digsig = 0; @@ -779,8 +778,8 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, return result; } -int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, - const char *acl_name, struct posix_acl *kacl) +static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, + const char *acl_name, struct posix_acl *kacl) { if (evm_revalidate_status(acl_name)) ima_reset_appraise_flags(d_backing_inode(dentry), 0); @@ -788,7 +787,8 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, return 0; } -int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) +static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry, + const char *xattr_name) { int result; @@ -800,3 +800,23 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) } return result; } + +static int ima_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry, + const char *acl_name) +{ + return ima_inode_set_acl(idmap, dentry, acl_name, NULL); +} + +static struct security_hook_list ima_appraise_hooks[] __ro_after_init = { + LSM_HOOK_INIT(inode_post_setattr, ima_inode_post_setattr), + LSM_HOOK_INIT(inode_setxattr, ima_inode_setxattr), + LSM_HOOK_INIT(inode_set_acl, ima_inode_set_acl), + LSM_HOOK_INIT(inode_removexattr, ima_inode_removexattr), + LSM_HOOK_INIT(inode_remove_acl, ima_inode_remove_acl), +}; + +void __init init_ima_appraise_lsm(const struct lsm_id *lsmid) +{ + security_add_hooks(ima_appraise_hooks, ARRAY_SIZE(ima_appraise_hooks), + lsmid); +} diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c new file mode 100644 index 0000000000..e7c9c216c1 --- /dev/null +++ b/security/integrity/ima/ima_iint.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2008 IBM Corporation + * + * Authors: + * Mimi Zohar + * + * File: ima_iint.c + * - implements the IMA hook: ima_inode_free + * - cache integrity information in the inode security blob + */ +#include + +#include "ima.h" + +static struct kmem_cache *ima_iint_cache __ro_after_init; + +/** + * ima_iint_find - Return the iint associated with an inode + * @inode: Pointer to the inode + * + * Return the IMA integrity information (iint) associated with an inode, if the + * inode was processed by IMA. + * + * Return: Found iint or NULL. + */ +struct ima_iint_cache *ima_iint_find(struct inode *inode) +{ + if (!IS_IMA(inode)) + return NULL; + + return ima_inode_get_iint(inode); +} + +#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH + 1) + +/* + * It is not clear that IMA should be nested at all, but as long is it measures + * files both on overlayfs and on underlying fs, we need to annotate the iint + * mutex to avoid lockdep false positives related to IMA + overlayfs. + * See ovl_lockdep_annotate_inode_mutex_key() for more details. + */ +static inline void ima_iint_lockdep_annotate(struct ima_iint_cache *iint, + struct inode *inode) +{ +#ifdef CONFIG_LOCKDEP + static struct lock_class_key ima_iint_mutex_key[IMA_MAX_NESTING]; + + int depth = inode->i_sb->s_stack_depth; + + if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING)) + depth = 0; + + lockdep_set_class(&iint->mutex, &ima_iint_mutex_key[depth]); +#endif +} + +static void ima_iint_init_always(struct ima_iint_cache *iint, + struct inode *inode) +{ + iint->ima_hash = NULL; + iint->version = 0; + iint->flags = 0UL; + iint->atomic_flags = 0UL; + iint->ima_file_status = INTEGRITY_UNKNOWN; + iint->ima_mmap_status = INTEGRITY_UNKNOWN; + iint->ima_bprm_status = INTEGRITY_UNKNOWN; + iint->ima_read_status = INTEGRITY_UNKNOWN; + iint->ima_creds_status = INTEGRITY_UNKNOWN; + iint->measured_pcrs = 0; + mutex_init(&iint->mutex); + ima_iint_lockdep_annotate(iint, inode); +} + +static void ima_iint_free(struct ima_iint_cache *iint) +{ + kfree(iint->ima_hash); + mutex_destroy(&iint->mutex); + kmem_cache_free(ima_iint_cache, iint); +} + +/** + * ima_inode_get - Find or allocate an iint associated with an inode + * @inode: Pointer to the inode + * + * Find an iint associated with an inode, and allocate a new one if not found. + * Caller must lock i_mutex. + * + * Return: An iint on success, NULL on error. + */ +struct ima_iint_cache *ima_inode_get(struct inode *inode) +{ + struct ima_iint_cache *iint; + + iint = ima_iint_find(inode); + if (iint) + return iint; + + iint = kmem_cache_alloc(ima_iint_cache, GFP_NOFS); + if (!iint) + return NULL; + + ima_iint_init_always(iint, inode); + + inode->i_flags |= S_IMA; + ima_inode_set_iint(inode, iint); + + return iint; +} + +/** + * ima_inode_free - Called on inode free + * @inode: Pointer to the inode + * + * Free the iint associated with an inode. + */ +void ima_inode_free(struct inode *inode) +{ + struct ima_iint_cache *iint; + + if (!IS_IMA(inode)) + return; + + iint = ima_iint_find(inode); + ima_inode_set_iint(inode, NULL); + + ima_iint_free(iint); +} + +static void ima_iint_init_once(void *foo) +{ + struct ima_iint_cache *iint = (struct ima_iint_cache *)foo; + + memset(iint, 0, sizeof(*iint)); +} + +void __init ima_iintcache_init(void) +{ + ima_iint_cache = + kmem_cache_create("ima_iint_cache", sizeof(struct ima_iint_cache), + 0, SLAB_PANIC, ima_iint_init_once); +} diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 63979aefc9..393f5c7912 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -44,7 +44,7 @@ static int __init ima_add_boot_aggregate(void) static const char op[] = "add_boot_aggregate"; const char *audit_cause = "ENOMEM"; struct ima_template_entry *entry; - struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; + struct ima_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; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index cc1217ac2c..c84e8c5533 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -114,7 +114,7 @@ static int mmap_violation_check(enum ima_hooks func, struct file *file, * */ static void ima_rdwr_violation_check(struct file *file, - struct integrity_iint_cache *iint, + struct ima_iint_cache *iint, int must_measure, char **pathbuf, const char **pathname, @@ -127,7 +127,7 @@ static void ima_rdwr_violation_check(struct file *file, if (mode & FMODE_WRITE) { if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { if (!iint) - iint = integrity_iint_find(inode); + iint = ima_iint_find(inode); /* IMA_MEASURE is set from reader side */ if (iint && test_bit(IMA_MUST_MEASURE, &iint->atomic_flags)) @@ -153,7 +153,7 @@ static void ima_rdwr_violation_check(struct file *file, "invalid_pcr", "open_writers"); } -static void ima_check_last_writer(struct integrity_iint_cache *iint, +static void ima_check_last_writer(struct ima_iint_cache *iint, struct inode *inode, struct file *file) { fmode_t mode = file->f_mode; @@ -189,15 +189,15 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint, * * Flag files that changed, based on i_version */ -void ima_file_free(struct file *file) +static void ima_file_free(struct file *file) { struct inode *inode = file_inode(file); - struct integrity_iint_cache *iint; + struct ima_iint_cache *iint; if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return; - iint = integrity_iint_find(inode); + iint = ima_iint_find(inode); if (!iint) return; @@ -209,7 +209,7 @@ static int process_measurement(struct file *file, const struct cred *cred, enum ima_hooks func) { struct inode *backing_inode, *inode = file_inode(file); - struct integrity_iint_cache *iint = NULL; + struct ima_iint_cache *iint = NULL; struct ima_template_desc *template_desc = NULL; char *pathbuf = NULL; char filename[NAME_MAX]; @@ -248,7 +248,7 @@ static int process_measurement(struct file *file, const struct cred *cred, inode_lock(inode); if (action) { - iint = integrity_inode_get(inode); + iint = ima_inode_get(inode); if (!iint) rc = -ENOMEM; } @@ -427,8 +427,8 @@ out: * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. */ -int ima_file_mmap(struct file *file, unsigned long reqprot, - unsigned long prot, unsigned long flags) +static int ima_file_mmap(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags) { u32 secid; int ret; @@ -455,7 +455,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot, /** * 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. + * @reqprot: protection requested by the application + * @prot: protection that will be applied by the kernel * * Files can be mmap'ed read/write and later changed to execute to circumvent * IMA's mmap appraisal policy rules. Due to locking issues (mmap semaphore @@ -465,7 +466,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot, * * On mprotect change success, return 0. On failure, return -EACESS. */ -int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) +static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, + unsigned long prot) { struct ima_template_desc *template = NULL; struct file *file; @@ -523,7 +525,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. */ -int ima_bprm_check(struct linux_binprm *bprm) +static int ima_bprm_check(struct linux_binprm *bprm) { int ret; u32 secid; @@ -549,7 +551,7 @@ int ima_bprm_check(struct linux_binprm *bprm) * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. */ -int ima_file_check(struct file *file, int mask) +static int ima_file_check(struct file *file, int mask) { u32 secid; @@ -558,16 +560,15 @@ int ima_file_check(struct file *file, int mask) mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK); } -EXPORT_SYMBOL_GPL(ima_file_check); static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf, size_t buf_size) { - struct integrity_iint_cache *iint = NULL, tmp_iint; + struct ima_iint_cache *iint = NULL, tmp_iint; int rc, hash_algo; if (ima_policy_flag) { - iint = integrity_iint_find(inode); + iint = ima_iint_find(inode); if (iint) mutex_lock(&iint->mutex); } @@ -577,7 +578,6 @@ static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf, 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, @@ -683,10 +683,11 @@ EXPORT_SYMBOL_GPL(ima_inode_hash); * Skip calling process_measurement(), but indicate which newly, created * tmpfiles are in policy. */ -void ima_post_create_tmpfile(struct mnt_idmap *idmap, - struct inode *inode) +static void ima_post_create_tmpfile(struct mnt_idmap *idmap, + struct inode *inode) + { - struct integrity_iint_cache *iint; + struct ima_iint_cache *iint; int must_appraise; if (!ima_policy_flag || !S_ISREG(inode->i_mode)) @@ -698,7 +699,7 @@ void ima_post_create_tmpfile(struct mnt_idmap *idmap, return; /* Nothing to do if we can't allocate memory */ - iint = integrity_inode_get(inode); + iint = ima_inode_get(inode); if (!iint) return; @@ -715,10 +716,9 @@ void ima_post_create_tmpfile(struct mnt_idmap *idmap, * Mark files created via the mknodat syscall as new, so that the * file data can be written later. */ -void ima_post_path_mknod(struct mnt_idmap *idmap, - struct dentry *dentry) +static void ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry) { - struct integrity_iint_cache *iint; + struct ima_iint_cache *iint; struct inode *inode = dentry->d_inode; int must_appraise; @@ -731,7 +731,7 @@ void ima_post_path_mknod(struct mnt_idmap *idmap, return; /* Nothing to do if we can't allocate memory */ - iint = integrity_inode_get(inode); + iint = ima_inode_get(inode); if (!iint) return; @@ -751,8 +751,8 @@ void ima_post_path_mknod(struct mnt_idmap *idmap, * * For permission return 0, otherwise return -EACCES. */ -int ima_read_file(struct file *file, enum kernel_read_file_id read_id, - bool contents) +static int ima_read_file(struct file *file, enum kernel_read_file_id read_id, + bool contents) { enum ima_hooks func; u32 secid; @@ -801,8 +801,8 @@ const int read_idmap[READING_MAX_ID] = { * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. */ -int ima_post_read_file(struct file *file, void *buf, loff_t size, - enum kernel_read_file_id read_id) +static int ima_post_read_file(struct file *file, char *buf, loff_t size, + enum kernel_read_file_id read_id) { enum ima_hooks func; u32 secid; @@ -835,7 +835,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, * * For permission return 0, otherwise return -EACCES. */ -int ima_load_data(enum kernel_load_data_id id, bool contents) +static int ima_load_data(enum kernel_load_data_id id, bool contents) { bool ima_enforce, sig_enforce; @@ -889,9 +889,9 @@ int ima_load_data(enum kernel_load_data_id id, bool contents) * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. */ -int ima_post_load_data(char *buf, loff_t size, - enum kernel_load_data_id load_id, - char *description) +static int ima_post_load_data(char *buf, loff_t size, + enum kernel_load_data_id load_id, + char *description) { if (load_id == LOADING_FIRMWARE) { if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && @@ -934,7 +934,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap, int ret = 0; const char *audit_cause = "ENOMEM"; struct ima_template_entry *entry = NULL; - struct integrity_iint_cache iint = {}; + struct ima_iint_cache iint = {}; struct ima_event_data event_data = {.iint = &iint, .filename = eventname, .buf = buf, @@ -1089,6 +1089,39 @@ int ima_measure_critical_data(const char *event_label, } EXPORT_SYMBOL_GPL(ima_measure_critical_data); +#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS + +/** + * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests + * @kmod_name: kernel module name + * + * Avoid a verification loop where verifying the signature of the modprobe + * binary requires executing modprobe itself. Since the modprobe iint->mutex + * is already held when the signature verification is performed, a deadlock + * occurs as soon as modprobe is executed within the critical region, since + * the same lock cannot be taken again. + * + * This happens when public_key_verify_signature(), in case of RSA algorithm, + * use alg_name to store internal information in order to construct an + * algorithm on the fly, but crypto_larval_lookup() will try to use alg_name + * in order to load a kernel module with same name. + * + * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules, + * we are safe to fail such module request from crypto_larval_lookup(), and + * avoid the verification loop. + * + * Return: Zero if it is safe to load the kernel module, -EINVAL otherwise. + */ +static int ima_kernel_module_request(char *kmod_name) +{ + if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0) + return -EINVAL; + + return 0; +} + +#endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */ + static int __init init_ima(void) { int error; @@ -1120,4 +1153,49 @@ static int __init init_ima(void) return error; } +static struct security_hook_list ima_hooks[] __ro_after_init = { + LSM_HOOK_INIT(bprm_check_security, ima_bprm_check), + LSM_HOOK_INIT(file_post_open, ima_file_check), + LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile), + LSM_HOOK_INIT(file_release, ima_file_free), + LSM_HOOK_INIT(mmap_file, ima_file_mmap), + LSM_HOOK_INIT(file_mprotect, ima_file_mprotect), + LSM_HOOK_INIT(kernel_load_data, ima_load_data), + LSM_HOOK_INIT(kernel_post_load_data, ima_post_load_data), + LSM_HOOK_INIT(kernel_read_file, ima_read_file), + LSM_HOOK_INIT(kernel_post_read_file, ima_post_read_file), + LSM_HOOK_INIT(path_post_mknod, ima_post_path_mknod), +#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS + LSM_HOOK_INIT(key_post_create_or_update, ima_post_key_create_or_update), +#endif +#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS + LSM_HOOK_INIT(kernel_module_request, ima_kernel_module_request), +#endif + LSM_HOOK_INIT(inode_free_security, ima_inode_free), +}; + +static const struct lsm_id ima_lsmid = { + .name = "ima", + .id = LSM_ID_IMA, +}; + +static int __init init_ima_lsm(void) +{ + ima_iintcache_init(); + security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid); + init_ima_appraise_lsm(&ima_lsmid); + return 0; +} + +struct lsm_blob_sizes ima_blob_sizes __ro_after_init = { + .lbs_inode = sizeof(struct ima_iint_cache *), +}; + +DEFINE_LSM(ima) = { + .name = "ima", + .init = init_ima_lsm, + .order = LSM_ORDER_LAST, + .blobs = &ima_blob_sizes, +}; + late_initcall(init_ima); /* Start IMA after the TPM is available */ diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index f690626177..09da8e6392 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -49,7 +49,7 @@ #define DONT_HASH 0x0200 #define INVALID_PCR(a) (((a) < 0) || \ - (a) >= (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8)) + (a) >= (sizeof_field(struct ima_iint_cache, measured_pcrs) * 8)) int ima_policy_flag; static int temp_ima_appraise; @@ -401,7 +401,8 @@ static void ima_free_rule(struct ima_rule_entry *entry) kfree(entry); } -static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) +static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry, + gfp_t gfp) { struct ima_rule_entry *nentry; int i; @@ -410,7 +411,7 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) * Immutable elements are copied over as pointers and data; only * lsm rules can change */ - nentry = kmemdup(entry, sizeof(*nentry), GFP_KERNEL); + nentry = kmemdup(entry, sizeof(*nentry), gfp); if (!nentry) return NULL; @@ -425,7 +426,8 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) ima_filter_rule_init(nentry->lsm[i].type, Audit_equal, nentry->lsm[i].args_p, - &nentry->lsm[i].rule); + &nentry->lsm[i].rule, + gfp); if (!nentry->lsm[i].rule) pr_warn("rule for LSM \'%s\' is undefined\n", nentry->lsm[i].args_p); @@ -438,7 +440,7 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry) int i; struct ima_rule_entry *nentry; - nentry = ima_lsm_copy_rule(entry); + nentry = ima_lsm_copy_rule(entry, GFP_KERNEL); if (!nentry) return -ENOMEM; @@ -664,7 +666,7 @@ retry: } if (rc == -ESTALE && !rule_reinitialized) { - lsm_rule = ima_lsm_copy_rule(rule); + lsm_rule = ima_lsm_copy_rule(rule, GFP_ATOMIC); if (lsm_rule) { rule_reinitialized = true; goto retry; @@ -1140,7 +1142,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry, entry->lsm[lsm_rule].type = audit_type; result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal, entry->lsm[lsm_rule].args_p, - &entry->lsm[lsm_rule].rule); + &entry->lsm[lsm_rule].rule, + GFP_KERNEL); if (!entry->lsm[lsm_rule].rule) { pr_warn("rule for LSM \'%s\' is undefined\n", entry->lsm[lsm_rule].args_p); diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 6cd0add524..3b2cb8f100 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -483,7 +483,10 @@ static int ima_eventname_init_common(struct ima_event_data *event_data, bool size_limit) { const char *cur_filename = NULL; + struct name_snapshot filename; u32 cur_filename_len = 0; + bool snapshot = false; + int ret; BUG_ON(event_data->filename == NULL && event_data->file == NULL); @@ -496,7 +499,10 @@ static int ima_eventname_init_common(struct ima_event_data *event_data, } if (event_data->file) { - cur_filename = event_data->file->f_path.dentry->d_name.name; + take_dentry_name_snapshot(&filename, + event_data->file->f_path.dentry); + snapshot = true; + cur_filename = filename.name.name; cur_filename_len = strlen(cur_filename); } else /* @@ -505,8 +511,13 @@ static int ima_eventname_init_common(struct ima_event_data *event_data, */ cur_filename_len = IMA_EVENT_NAME_LEN_MAX; out: - return ima_write_template_field_data(cur_filename, cur_filename_len, - DATA_FMT_STRING, field_data); + ret = ima_write_template_field_data(cur_filename, cur_filename_len, + DATA_FMT_STRING, field_data); + + if (snapshot) + release_dentry_name_snapshot(&filename); + + return ret; } /* diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 9561db7cf6..50d6f798e6 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -18,60 +18,7 @@ #include #include #include - -/* iint action cache flags */ -#define IMA_MEASURE 0x00000001 -#define IMA_MEASURED 0x00000002 -#define IMA_APPRAISE 0x00000004 -#define IMA_APPRAISED 0x00000008 -/*#define IMA_COLLECT 0x00000010 do not use this flag */ -#define IMA_COLLECTED 0x00000020 -#define IMA_AUDIT 0x00000040 -#define IMA_AUDITED 0x00000080 -#define IMA_HASH 0x00000100 -#define IMA_HASHED 0x00000200 - -/* 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 -#define EVM_IMMUTABLE_DIGSIG 0x08000000 -#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000 -#define IMA_MODSIG_ALLOWED 0x20000000 -#define IMA_CHECK_BLACKLIST 0x40000000 -#define IMA_VERITY_REQUIRED 0x80000000 - -#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ - IMA_HASH | IMA_APPRAISE_SUBMASK) -#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \ - IMA_HASHED | IMA_COLLECTED | \ - IMA_APPRAISED_SUBMASK) - -/* iint subaction appraise cache flags */ -#define IMA_FILE_APPRAISE 0x00001000 -#define IMA_FILE_APPRAISED 0x00002000 -#define IMA_MMAP_APPRAISE 0x00004000 -#define IMA_MMAP_APPRAISED 0x00008000 -#define IMA_BPRM_APPRAISE 0x00010000 -#define IMA_BPRM_APPRAISED 0x00020000 -#define IMA_READ_APPRAISE 0x00040000 -#define IMA_READ_APPRAISED 0x00080000 -#define IMA_CREDS_APPRAISE 0x00100000 -#define IMA_CREDS_APPRAISED 0x00200000 -#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ - IMA_BPRM_APPRAISE | IMA_READ_APPRAISE | \ - IMA_CREDS_APPRAISE) -#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ - IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \ - IMA_CREDS_APPRAISED) - -/* iint cache atomic_flags */ -#define IMA_CHANGE_XATTR 0 -#define IMA_UPDATE_XATTR 1 -#define IMA_CHANGE_ATTR 2 -#define IMA_DIGSIG 3 -#define IMA_MUST_MEASURE 4 +#include enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01, @@ -155,31 +102,6 @@ struct ima_file_id { __u8 hash[HASH_MAX_DIGESTSIZE]; } __packed; -/* integrity data associated with an inode */ -struct integrity_iint_cache { - struct rb_node rb_node; /* rooted in integrity_iint_tree */ - struct mutex mutex; /* protects: version, flags, digest */ - struct inode *inode; /* back pointer to inode in question */ - u64 version; /* track inode changes */ - unsigned long flags; - unsigned long measured_pcrs; - unsigned long atomic_flags; - unsigned long real_ino; - dev_t real_dev; - enum integrity_status ima_file_status:4; - enum integrity_status ima_mmap_status:4; - enum integrity_status ima_bprm_status:4; - enum integrity_status ima_read_status:4; - enum integrity_status ima_creds_status:4; - enum integrity_status evm_status:4; - struct ima_digest_data *ima_hash; -}; - -/* rbtree tree calls to lookup, insert, delete - * integrity data associated with an inode. - */ -struct integrity_iint_cache *integrity_iint_find(struct inode *inode); - int integrity_kernel_read(struct file *file, loff_t offset, void *addr, unsigned long count); diff --git a/security/keys/key.c b/security/keys/key.c index 74dfd961af..0aa5f01d16 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "internal.h" @@ -931,8 +930,8 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref, goto error_link_end; } - ima_post_key_create_or_update(keyring, key, payload, plen, - flags, true); + security_key_post_create_or_update(keyring, key, payload, plen, flags, + true); key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); @@ -965,9 +964,8 @@ error: key_ref = __key_update(key_ref, &prep); if (!IS_ERR(key_ref)) - ima_post_key_create_or_update(keyring, key, - payload, plen, - flags, false); + security_key_post_create_or_update(keyring, key, payload, plen, + flags, false); goto error_free_prep; } diff --git a/security/landlock/.kunitconfig b/security/landlock/.kunitconfig new file mode 100644 index 0000000000..03e1194666 --- /dev/null +++ b/security/landlock/.kunitconfig @@ -0,0 +1,4 @@ +CONFIG_KUNIT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_LANDLOCK=y +CONFIG_SECURITY_LANDLOCK_KUNIT_TEST=y diff --git a/security/landlock/Kconfig b/security/landlock/Kconfig index c4bf0d5eff..3f14934020 100644 --- a/security/landlock/Kconfig +++ b/security/landlock/Kconfig @@ -20,3 +20,18 @@ config SECURITY_LANDLOCK If you are unsure how to answer this question, answer N. Otherwise, you should also prepend "landlock," to the content of CONFIG_LSM to enable Landlock at boot time. + +config SECURITY_LANDLOCK_KUNIT_TEST + bool "KUnit tests for Landlock" if !KUNIT_ALL_TESTS + depends on KUNIT=y + depends on SECURITY_LANDLOCK + default KUNIT_ALL_TESTS + help + Build KUnit tests for Landlock. + + See the KUnit documentation in Documentation/dev-tools/kunit + + Run all KUnit tests for Landlock with: + ./tools/testing/kunit/kunit.py run --kunitconfig security/landlock + + If you are unsure how to answer this question, answer N. diff --git a/security/landlock/Makefile b/security/landlock/Makefile index c2e116f2a2..b4538b7cf7 100644 --- a/security/landlock/Makefile +++ b/security/landlock/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o landlock-y := setup.o syscalls.o object.o ruleset.o \ - cred.o ptrace.o fs.o + cred.o task.o fs.o landlock-$(CONFIG_INET) += net.o diff --git a/security/landlock/common.h b/security/landlock/common.h index 5dc0fe1570..0eb1d34c2e 100644 --- a/security/landlock/common.h +++ b/security/landlock/common.h @@ -17,4 +17,6 @@ #define pr_fmt(fmt) LANDLOCK_NAME ": " fmt +#define BIT_INDEX(bit) HWEIGHT(bit - 1) + #endif /* _SECURITY_LANDLOCK_COMMON_H */ diff --git a/security/landlock/fs.c b/security/landlock/fs.c index 0171f7eb6e..3e43e68a63 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -7,6 +7,7 @@ * Copyright © 2021-2022 Microsoft Corporation */ +#include #include #include #include @@ -247,15 +248,18 @@ get_handled_fs_accesses(const struct landlock_ruleset *const domain) LANDLOCK_ACCESS_FS_INITIALLY_DENIED; } -static const struct landlock_ruleset *get_current_fs_domain(void) +static const struct landlock_ruleset * +get_fs_domain(const struct landlock_ruleset *const domain) { - const struct landlock_ruleset *const dom = - landlock_get_current_domain(); - - if (!dom || !get_raw_handled_fs_accesses(dom)) + if (!domain || !get_raw_handled_fs_accesses(domain)) return NULL; - return dom; + return domain; +} + +static const struct landlock_ruleset *get_current_fs_domain(void) +{ + return get_fs_domain(landlock_get_current_domain()); } /* @@ -311,6 +315,119 @@ static bool no_more_access( return true; } +#define NMA_TRUE(...) KUNIT_EXPECT_TRUE(test, no_more_access(__VA_ARGS__)) +#define NMA_FALSE(...) KUNIT_EXPECT_FALSE(test, no_more_access(__VA_ARGS__)) + +#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST + +static void test_no_more_access(struct kunit *const test) +{ + const layer_mask_t rx0[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), + [BIT_INDEX(LANDLOCK_ACCESS_FS_READ_FILE)] = BIT_ULL(0), + }; + const layer_mask_t mx0[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), + [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_REG)] = BIT_ULL(0), + }; + const layer_mask_t x0[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), + }; + const layer_mask_t x1[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(1), + }; + const layer_mask_t x01[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0) | + BIT_ULL(1), + }; + const layer_mask_t allows_all[LANDLOCK_NUM_ACCESS_FS] = {}; + + /* Checks without restriction. */ + NMA_TRUE(&x0, &allows_all, false, &allows_all, NULL, false); + NMA_TRUE(&allows_all, &x0, false, &allows_all, NULL, false); + NMA_FALSE(&x0, &x0, false, &allows_all, NULL, false); + + /* + * Checks that we can only refer a file if no more access could be + * inherited. + */ + NMA_TRUE(&x0, &x0, false, &rx0, NULL, false); + NMA_TRUE(&rx0, &rx0, false, &rx0, NULL, false); + NMA_FALSE(&rx0, &rx0, false, &x0, NULL, false); + NMA_FALSE(&rx0, &rx0, false, &x1, NULL, false); + + /* Checks allowed referring with different nested domains. */ + NMA_TRUE(&x0, &x1, false, &x0, NULL, false); + NMA_TRUE(&x1, &x0, false, &x0, NULL, false); + NMA_TRUE(&x0, &x01, false, &x0, NULL, false); + NMA_TRUE(&x0, &x01, false, &rx0, NULL, false); + NMA_TRUE(&x01, &x0, false, &x0, NULL, false); + NMA_TRUE(&x01, &x0, false, &rx0, NULL, false); + NMA_FALSE(&x01, &x01, false, &x0, NULL, false); + + /* Checks that file access rights are also enforced for a directory. */ + NMA_FALSE(&rx0, &rx0, true, &x0, NULL, false); + + /* Checks that directory access rights don't impact file referring... */ + NMA_TRUE(&mx0, &mx0, false, &x0, NULL, false); + /* ...but only directory referring. */ + NMA_FALSE(&mx0, &mx0, true, &x0, NULL, false); + + /* Checks directory exchange. */ + NMA_TRUE(&mx0, &mx0, true, &mx0, &mx0, true); + NMA_TRUE(&mx0, &mx0, true, &mx0, &x0, true); + NMA_FALSE(&mx0, &mx0, true, &x0, &mx0, true); + NMA_FALSE(&mx0, &mx0, true, &x0, &x0, true); + NMA_FALSE(&mx0, &mx0, true, &x1, &x1, true); + + /* Checks file exchange with directory access rights... */ + NMA_TRUE(&mx0, &mx0, false, &mx0, &mx0, false); + NMA_TRUE(&mx0, &mx0, false, &mx0, &x0, false); + NMA_TRUE(&mx0, &mx0, false, &x0, &mx0, false); + NMA_TRUE(&mx0, &mx0, false, &x0, &x0, false); + /* ...and with file access rights. */ + NMA_TRUE(&rx0, &rx0, false, &rx0, &rx0, false); + NMA_TRUE(&rx0, &rx0, false, &rx0, &x0, false); + NMA_FALSE(&rx0, &rx0, false, &x0, &rx0, false); + NMA_FALSE(&rx0, &rx0, false, &x0, &x0, false); + NMA_FALSE(&rx0, &rx0, false, &x1, &x1, false); + + /* + * Allowing the following requests should not be a security risk + * because domain 0 denies execute access, and domain 1 is always + * nested with domain 0. However, adding an exception for this case + * would mean to check all nested domains to make sure none can get + * more privileges (e.g. processes only sandboxed by domain 0). + * Moreover, this behavior (i.e. composition of N domains) could then + * be inconsistent compared to domain 1's ruleset alone (e.g. it might + * be denied to link/rename with domain 1's ruleset, whereas it would + * be allowed if nested on top of domain 0). Another drawback would be + * to create a cover channel that could enable sandboxed processes to + * infer most of the filesystem restrictions from their domain. To + * make it simple, efficient, safe, and more consistent, this case is + * always denied. + */ + NMA_FALSE(&x1, &x1, false, &x0, NULL, false); + NMA_FALSE(&x1, &x1, false, &rx0, NULL, false); + NMA_FALSE(&x1, &x1, true, &x0, NULL, false); + NMA_FALSE(&x1, &x1, true, &rx0, NULL, false); + + /* Checks the same case of exclusive domains with a file... */ + NMA_TRUE(&x1, &x1, false, &x01, NULL, false); + NMA_FALSE(&x1, &x1, false, &x01, &x0, false); + NMA_FALSE(&x1, &x1, false, &x01, &x01, false); + NMA_FALSE(&x1, &x1, false, &x0, &x0, false); + /* ...and with a directory. */ + NMA_FALSE(&x1, &x1, false, &x0, &x0, true); + NMA_FALSE(&x1, &x1, true, &x0, &x0, false); + NMA_FALSE(&x1, &x1, true, &x0, &x0, true); +} + +#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ + +#undef NMA_TRUE +#undef NMA_FALSE + /* * Removes @layer_masks accesses that are not requested. * @@ -331,6 +448,57 @@ scope_to_request(const access_mask_t access_request, return !memchr_inv(layer_masks, 0, sizeof(*layer_masks)); } +#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST + +static void test_scope_to_request_with_exec_none(struct kunit *const test) +{ + /* Allows everything. */ + layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; + + /* Checks and scopes with execute. */ + KUNIT_EXPECT_TRUE(test, scope_to_request(LANDLOCK_ACCESS_FS_EXECUTE, + &layer_masks)); + KUNIT_EXPECT_EQ(test, 0, + layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)]); + KUNIT_EXPECT_EQ(test, 0, + layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)]); +} + +static void test_scope_to_request_with_exec_some(struct kunit *const test) +{ + /* Denies execute and write. */ + layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), + [BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)] = BIT_ULL(1), + }; + + /* Checks and scopes with execute. */ + KUNIT_EXPECT_FALSE(test, scope_to_request(LANDLOCK_ACCESS_FS_EXECUTE, + &layer_masks)); + KUNIT_EXPECT_EQ(test, BIT_ULL(0), + layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)]); + KUNIT_EXPECT_EQ(test, 0, + layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)]); +} + +static void test_scope_to_request_without_access(struct kunit *const test) +{ + /* Denies execute and write. */ + layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0), + [BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)] = BIT_ULL(1), + }; + + /* Checks and scopes without access request. */ + KUNIT_EXPECT_TRUE(test, scope_to_request(0, &layer_masks)); + KUNIT_EXPECT_EQ(test, 0, + layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)]); + KUNIT_EXPECT_EQ(test, 0, + layer_masks[BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)]); +} + +#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ + /* * Returns true if there is at least one access right different than * LANDLOCK_ACCESS_FS_REFER. @@ -354,6 +522,51 @@ is_eacces(const layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS], return false; } +#define IE_TRUE(...) KUNIT_EXPECT_TRUE(test, is_eacces(__VA_ARGS__)) +#define IE_FALSE(...) KUNIT_EXPECT_FALSE(test, is_eacces(__VA_ARGS__)) + +#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST + +static void test_is_eacces_with_none(struct kunit *const test) +{ + const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; + + IE_FALSE(&layer_masks, 0); + IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_REFER); + IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_EXECUTE); + IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_WRITE_FILE); +} + +static void test_is_eacces_with_refer(struct kunit *const test) +{ + const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = BIT_ULL(0), + }; + + IE_FALSE(&layer_masks, 0); + IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_REFER); + IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_EXECUTE); + IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_WRITE_FILE); +} + +static void test_is_eacces_with_write(struct kunit *const test) +{ + const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = { + [BIT_INDEX(LANDLOCK_ACCESS_FS_WRITE_FILE)] = BIT_ULL(0), + }; + + IE_FALSE(&layer_masks, 0); + IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_REFER); + IE_FALSE(&layer_masks, LANDLOCK_ACCESS_FS_EXECUTE); + + IE_TRUE(&layer_masks, LANDLOCK_ACCESS_FS_WRITE_FILE); +} + +#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ + +#undef IE_TRUE +#undef IE_FALSE + /** * is_access_to_paths_allowed - Check accesses for requests with a common path * @@ -737,6 +950,7 @@ static int current_check_refer_path(struct dentry *const old_dentry, bool allow_parent1, allow_parent2; access_mask_t access_request_parent1, access_request_parent2; struct path mnt_dir; + struct dentry *old_parent; layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS] = {}, layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS] = {}; @@ -784,9 +998,17 @@ static int current_check_refer_path(struct dentry *const old_dentry, mnt_dir.mnt = new_dir->mnt; mnt_dir.dentry = new_dir->mnt->mnt_root; + /* + * old_dentry may be the root of the common mount point and + * !IS_ROOT(old_dentry) at the same time (e.g. with open_tree() and + * OPEN_TREE_CLONE). We do not need to call dget(old_parent) because + * we keep a reference to old_dentry. + */ + old_parent = (old_dentry == mnt_dir.dentry) ? old_dentry : + old_dentry->d_parent; + /* new_dir->dentry is equal to new_dentry->d_parent */ - allow_parent1 = collect_domain_accesses(dom, mnt_dir.dentry, - old_dentry->d_parent, + allow_parent1 = collect_domain_accesses(dom, mnt_dir.dentry, old_parent, &layer_masks_parent1); allow_parent2 = collect_domain_accesses( dom, mnt_dir.dentry, new_dir->dentry, &layer_masks_parent2); @@ -1124,7 +1346,8 @@ static int hook_file_open(struct file *const file) layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; access_mask_t open_access_request, full_access_request, allowed_access; const access_mask_t optional_access = LANDLOCK_ACCESS_FS_TRUNCATE; - const struct landlock_ruleset *const dom = get_current_fs_domain(); + const struct landlock_ruleset *const dom = + get_fs_domain(landlock_cred(file->f_cred)->domain); if (!dom) return 0; @@ -1225,3 +1448,27 @@ __init void landlock_add_fs_hooks(void) security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), &landlock_lsmid); } + +#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST + +/* clang-format off */ +static struct kunit_case test_cases[] = { + KUNIT_CASE(test_no_more_access), + KUNIT_CASE(test_scope_to_request_with_exec_none), + KUNIT_CASE(test_scope_to_request_with_exec_some), + KUNIT_CASE(test_scope_to_request_without_access), + KUNIT_CASE(test_is_eacces_with_none), + KUNIT_CASE(test_is_eacces_with_refer), + KUNIT_CASE(test_is_eacces_with_write), + {} +}; +/* clang-format on */ + +static struct kunit_suite test_suite = { + .name = "landlock_fs", + .test_cases = test_cases, +}; + +kunit_test_suite(test_suite); + +#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ diff --git a/security/landlock/net.c b/security/landlock/net.c index efa1b644a4..c8bcd29bde 100644 --- a/security/landlock/net.c +++ b/security/landlock/net.c @@ -64,12 +64,11 @@ static const struct landlock_ruleset *get_current_net_domain(void) static int current_check_access_socket(struct socket *const sock, struct sockaddr *const address, const int addrlen, - const access_mask_t access_request) + access_mask_t access_request) { __be16 port; layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {}; const struct landlock_rule *rule; - access_mask_t handled_access; struct landlock_id id = { .type = LANDLOCK_KEY_NET_PORT, }; @@ -164,9 +163,9 @@ static int current_check_access_socket(struct socket *const sock, BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data)); rule = landlock_find_rule(dom, id); - handled_access = landlock_init_layer_masks( + access_request = landlock_init_layer_masks( dom, access_request, &layer_masks, LANDLOCK_KEY_NET_PORT); - if (landlock_unmask_layers(rule, handled_access, &layer_masks, + if (landlock_unmask_layers(rule, access_request, &layer_masks, ARRAY_SIZE(layer_masks))) return 0; diff --git a/security/landlock/ptrace.c b/security/landlock/ptrace.c deleted file mode 100644 index 2bfc533d36..0000000000 --- a/security/landlock/ptrace.c +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Landlock LSM - Ptrace hooks - * - * Copyright © 2017-2020 Mickaël Salaün - * Copyright © 2019-2020 ANSSI - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "cred.h" -#include "ptrace.h" -#include "ruleset.h" -#include "setup.h" - -/** - * domain_scope_le - Checks domain ordering for scoped ptrace - * - * @parent: Parent domain. - * @child: Potential child of @parent. - * - * Checks if the @parent domain is less or equal to (i.e. an ancestor, which - * means a subset of) the @child domain. - */ -static bool domain_scope_le(const struct landlock_ruleset *const parent, - const struct landlock_ruleset *const child) -{ - const struct landlock_hierarchy *walker; - - if (!parent) - return true; - if (!child) - return false; - for (walker = child->hierarchy; walker; walker = walker->parent) { - if (walker == parent->hierarchy) - /* @parent is in the scoped hierarchy of @child. */ - return true; - } - /* There is no relationship between @parent and @child. */ - return false; -} - -static bool task_is_scoped(const struct task_struct *const parent, - const struct task_struct *const child) -{ - bool is_scoped; - const struct landlock_ruleset *dom_parent, *dom_child; - - rcu_read_lock(); - dom_parent = landlock_get_task_domain(parent); - dom_child = landlock_get_task_domain(child); - is_scoped = domain_scope_le(dom_parent, dom_child); - rcu_read_unlock(); - return is_scoped; -} - -static int task_ptrace(const struct task_struct *const parent, - const struct task_struct *const child) -{ - /* Quick return for non-landlocked tasks. */ - if (!landlocked(parent)) - return 0; - if (task_is_scoped(parent, child)) - return 0; - return -EPERM; -} - -/** - * hook_ptrace_access_check - Determines whether the current process may access - * another - * - * @child: Process to be accessed. - * @mode: Mode of attachment. - * - * If the current task has Landlock rules, then the child must have at least - * the same rules. Else denied. - * - * Determines whether a process may access another, returning 0 if permission - * granted, -errno if denied. - */ -static int hook_ptrace_access_check(struct task_struct *const child, - const unsigned int mode) -{ - return task_ptrace(current, child); -} - -/** - * hook_ptrace_traceme - Determines whether another process may trace the - * current one - * - * @parent: Task proposed to be the tracer. - * - * If the parent has Landlock rules, then the current task must have the same - * or more rules. Else denied. - * - * Determines whether the nominated task is permitted to trace the current - * process, returning 0 if permission is granted, -errno if denied. - */ -static int hook_ptrace_traceme(struct task_struct *const parent) -{ - return task_ptrace(parent, current); -} - -static struct security_hook_list landlock_hooks[] __ro_after_init = { - LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check), - LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme), -}; - -__init void landlock_add_ptrace_hooks(void) -{ - security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), - &landlock_lsmid); -} diff --git a/security/landlock/ptrace.h b/security/landlock/ptrace.h deleted file mode 100644 index 265b220ae3..0000000000 --- a/security/landlock/ptrace.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Landlock LSM - Ptrace hooks - * - * Copyright © 2017-2019 Mickaël Salaün - * Copyright © 2019 ANSSI - */ - -#ifndef _SECURITY_LANDLOCK_PTRACE_H -#define _SECURITY_LANDLOCK_PTRACE_H - -__init void landlock_add_ptrace_hooks(void); - -#endif /* _SECURITY_LANDLOCK_PTRACE_H */ diff --git a/security/landlock/setup.c b/security/landlock/setup.c index f6dd33143b..28519a45b1 100644 --- a/security/landlock/setup.c +++ b/security/landlock/setup.c @@ -14,8 +14,8 @@ #include "cred.h" #include "fs.h" #include "net.h" -#include "ptrace.h" #include "setup.h" +#include "task.h" bool landlock_initialized __ro_after_init = false; @@ -34,7 +34,7 @@ const struct lsm_id landlock_lsmid = { static int __init landlock_init(void) { landlock_add_cred_hooks(); - landlock_add_ptrace_hooks(); + landlock_add_task_hooks(); landlock_add_fs_hooks(); landlock_add_net_hooks(); landlock_initialized = true; diff --git a/security/landlock/task.c b/security/landlock/task.c new file mode 100644 index 0000000000..849f512361 --- /dev/null +++ b/security/landlock/task.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Landlock LSM - Ptrace hooks + * + * Copyright © 2017-2020 Mickaël Salaün + * Copyright © 2019-2020 ANSSI + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "cred.h" +#include "ruleset.h" +#include "setup.h" +#include "task.h" + +/** + * domain_scope_le - Checks domain ordering for scoped ptrace + * + * @parent: Parent domain. + * @child: Potential child of @parent. + * + * Checks if the @parent domain is less or equal to (i.e. an ancestor, which + * means a subset of) the @child domain. + */ +static bool domain_scope_le(const struct landlock_ruleset *const parent, + const struct landlock_ruleset *const child) +{ + const struct landlock_hierarchy *walker; + + if (!parent) + return true; + if (!child) + return false; + for (walker = child->hierarchy; walker; walker = walker->parent) { + if (walker == parent->hierarchy) + /* @parent is in the scoped hierarchy of @child. */ + return true; + } + /* There is no relationship between @parent and @child. */ + return false; +} + +static bool task_is_scoped(const struct task_struct *const parent, + const struct task_struct *const child) +{ + bool is_scoped; + const struct landlock_ruleset *dom_parent, *dom_child; + + rcu_read_lock(); + dom_parent = landlock_get_task_domain(parent); + dom_child = landlock_get_task_domain(child); + is_scoped = domain_scope_le(dom_parent, dom_child); + rcu_read_unlock(); + return is_scoped; +} + +static int task_ptrace(const struct task_struct *const parent, + const struct task_struct *const child) +{ + /* Quick return for non-landlocked tasks. */ + if (!landlocked(parent)) + return 0; + if (task_is_scoped(parent, child)) + return 0; + return -EPERM; +} + +/** + * hook_ptrace_access_check - Determines whether the current process may access + * another + * + * @child: Process to be accessed. + * @mode: Mode of attachment. + * + * If the current task has Landlock rules, then the child must have at least + * the same rules. Else denied. + * + * Determines whether a process may access another, returning 0 if permission + * granted, -errno if denied. + */ +static int hook_ptrace_access_check(struct task_struct *const child, + const unsigned int mode) +{ + return task_ptrace(current, child); +} + +/** + * hook_ptrace_traceme - Determines whether another process may trace the + * current one + * + * @parent: Task proposed to be the tracer. + * + * If the parent has Landlock rules, then the current task must have the same + * or more rules. Else denied. + * + * Determines whether the nominated task is permitted to trace the current + * process, returning 0 if permission is granted, -errno if denied. + */ +static int hook_ptrace_traceme(struct task_struct *const parent) +{ + return task_ptrace(parent, current); +} + +static struct security_hook_list landlock_hooks[] __ro_after_init = { + LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check), + LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme), +}; + +__init void landlock_add_task_hooks(void) +{ + security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), + &landlock_lsmid); +} diff --git a/security/landlock/task.h b/security/landlock/task.h new file mode 100644 index 0000000000..7c00360219 --- /dev/null +++ b/security/landlock/task.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Landlock LSM - Ptrace hooks + * + * Copyright © 2017-2019 Mickaël Salaün + * Copyright © 2019 ANSSI + */ + +#ifndef _SECURITY_LANDLOCK_TASK_H +#define _SECURITY_LANDLOCK_TASK_H + +__init void landlock_add_task_hooks(void); + +#endif /* _SECURITY_LANDLOCK_TASK_H */ diff --git a/security/security.c b/security/security.c index a344b8fa55..4fd3c83935 100644 --- a/security/security.c +++ b/security/security.c @@ -19,15 +19,13 @@ #include #include #include -#include -#include -#include #include #include #include #include #include #include +#include #include #include #include @@ -51,7 +49,9 @@ (IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \ (IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \ (IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0)) + (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_EVM) ? 1 : 0)) /* * These are descriptions of the reasons that can be passed to the @@ -862,14 +862,14 @@ out: P->hook.FUNC(__VA_ARGS__); \ } while (0) -#define call_int_hook(FUNC, IRC, ...) ({ \ - int RC = IRC; \ +#define call_int_hook(FUNC, ...) ({ \ + int RC = LSM_RET_DEFAULT(FUNC); \ do { \ struct security_hook_list *P; \ \ hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \ RC = P->hook.FUNC(__VA_ARGS__); \ - if (RC != 0) \ + if (RC != LSM_RET_DEFAULT(FUNC)) \ break; \ } \ } while (0); \ @@ -888,7 +888,7 @@ out: */ int security_binder_set_context_mgr(const struct cred *mgr) { - return call_int_hook(binder_set_context_mgr, 0, mgr); + return call_int_hook(binder_set_context_mgr, mgr); } /** @@ -903,7 +903,7 @@ int security_binder_set_context_mgr(const struct cred *mgr) int security_binder_transaction(const struct cred *from, const struct cred *to) { - return call_int_hook(binder_transaction, 0, from, to); + return call_int_hook(binder_transaction, from, to); } /** @@ -918,7 +918,7 @@ int security_binder_transaction(const struct cred *from, int security_binder_transfer_binder(const struct cred *from, const struct cred *to) { - return call_int_hook(binder_transfer_binder, 0, from, to); + return call_int_hook(binder_transfer_binder, from, to); } /** @@ -934,7 +934,7 @@ int security_binder_transfer_binder(const struct cred *from, int security_binder_transfer_file(const struct cred *from, const struct cred *to, const struct file *file) { - return call_int_hook(binder_transfer_file, 0, from, to, file); + return call_int_hook(binder_transfer_file, from, to, file); } /** @@ -953,7 +953,7 @@ int security_binder_transfer_file(const struct cred *from, */ int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { - return call_int_hook(ptrace_access_check, 0, child, mode); + return call_int_hook(ptrace_access_check, child, mode); } /** @@ -968,7 +968,7 @@ int security_ptrace_access_check(struct task_struct *child, unsigned int mode) */ int security_ptrace_traceme(struct task_struct *parent) { - return call_int_hook(ptrace_traceme, 0, parent); + return call_int_hook(ptrace_traceme, parent); } /** @@ -990,8 +990,7 @@ int security_capget(const struct task_struct *target, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - return call_int_hook(capget, 0, target, - effective, inheritable, permitted); + return call_int_hook(capget, target, effective, inheritable, permitted); } /** @@ -1012,8 +1011,8 @@ int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *inheritable, const kernel_cap_t *permitted) { - return call_int_hook(capset, 0, new, old, - effective, inheritable, permitted); + return call_int_hook(capset, new, old, effective, inheritable, + permitted); } /** @@ -1034,7 +1033,7 @@ int security_capable(const struct cred *cred, int cap, unsigned int opts) { - return call_int_hook(capable, 0, cred, ns, cap, opts); + return call_int_hook(capable, cred, ns, cap, opts); } /** @@ -1050,7 +1049,7 @@ int security_capable(const struct cred *cred, */ int security_quotactl(int cmds, int type, int id, const struct super_block *sb) { - return call_int_hook(quotactl, 0, cmds, type, id, sb); + return call_int_hook(quotactl, cmds, type, id, sb); } /** @@ -1063,7 +1062,7 @@ int security_quotactl(int cmds, int type, int id, const struct super_block *sb) */ int security_quota_on(struct dentry *dentry) { - return call_int_hook(quota_on, 0, dentry); + return call_int_hook(quota_on, dentry); } /** @@ -1078,7 +1077,7 @@ int security_quota_on(struct dentry *dentry) */ int security_syslog(int type) { - return call_int_hook(syslog, 0, type); + return call_int_hook(syslog, type); } /** @@ -1093,7 +1092,7 @@ int security_syslog(int type) */ int security_settime64(const struct timespec64 *ts, const struct timezone *tz) { - return call_int_hook(settime, 0, ts, tz); + return call_int_hook(settime, ts, tz); } /** @@ -1148,7 +1147,7 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) */ int security_bprm_creds_for_exec(struct linux_binprm *bprm) { - return call_int_hook(bprm_creds_for_exec, 0, bprm); + return call_int_hook(bprm_creds_for_exec, bprm); } /** @@ -1172,7 +1171,7 @@ int security_bprm_creds_for_exec(struct linux_binprm *bprm) */ int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file) { - return call_int_hook(bprm_creds_from_file, 0, bprm, file); + return call_int_hook(bprm_creds_from_file, bprm, file); } /** @@ -1189,12 +1188,7 @@ int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file * */ int security_bprm_check(struct linux_binprm *bprm) { - int ret; - - ret = call_int_hook(bprm_check_security, 0, bprm); - if (ret) - return ret; - return ima_bprm_check(bprm); + return call_int_hook(bprm_check_security, bprm); } /** @@ -1241,7 +1235,7 @@ void security_bprm_committed_creds(const struct linux_binprm *bprm) */ int security_fs_context_submount(struct fs_context *fc, struct super_block *reference) { - return call_int_hook(fs_context_submount, 0, fc, reference); + return call_int_hook(fs_context_submount, fc, reference); } /** @@ -1257,7 +1251,7 @@ int security_fs_context_submount(struct fs_context *fc, struct super_block *refe */ 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); + return call_int_hook(fs_context_dup, fc, src_fc); } /** @@ -1306,7 +1300,7 @@ int security_sb_alloc(struct super_block *sb) if (unlikely(rc)) return rc; - rc = call_int_hook(sb_alloc_security, 0, sb); + rc = call_int_hook(sb_alloc_security, sb); if (unlikely(rc)) security_sb_free(sb); return rc; @@ -1364,7 +1358,7 @@ EXPORT_SYMBOL(security_free_mnt_opts); */ int security_sb_eat_lsm_opts(char *options, void **mnt_opts) { - return call_int_hook(sb_eat_lsm_opts, 0, options, mnt_opts); + return call_int_hook(sb_eat_lsm_opts, options, mnt_opts); } EXPORT_SYMBOL(security_sb_eat_lsm_opts); @@ -1381,7 +1375,7 @@ EXPORT_SYMBOL(security_sb_eat_lsm_opts); int security_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts) { - return call_int_hook(sb_mnt_opts_compat, 0, sb, mnt_opts); + return call_int_hook(sb_mnt_opts_compat, sb, mnt_opts); } EXPORT_SYMBOL(security_sb_mnt_opts_compat); @@ -1398,7 +1392,7 @@ EXPORT_SYMBOL(security_sb_mnt_opts_compat); int security_sb_remount(struct super_block *sb, void *mnt_opts) { - return call_int_hook(sb_remount, 0, sb, mnt_opts); + return call_int_hook(sb_remount, sb, mnt_opts); } EXPORT_SYMBOL(security_sb_remount); @@ -1412,7 +1406,7 @@ EXPORT_SYMBOL(security_sb_remount); */ int security_sb_kern_mount(const struct super_block *sb) { - return call_int_hook(sb_kern_mount, 0, sb); + return call_int_hook(sb_kern_mount, sb); } /** @@ -1426,7 +1420,7 @@ int security_sb_kern_mount(const struct super_block *sb) */ int security_sb_show_options(struct seq_file *m, struct super_block *sb) { - return call_int_hook(sb_show_options, 0, m, sb); + return call_int_hook(sb_show_options, m, sb); } /** @@ -1440,7 +1434,7 @@ int security_sb_show_options(struct seq_file *m, struct super_block *sb) */ int security_sb_statfs(struct dentry *dentry) { - return call_int_hook(sb_statfs, 0, dentry); + return call_int_hook(sb_statfs, dentry); } /** @@ -1463,7 +1457,7 @@ int security_sb_statfs(struct dentry *dentry) int security_sb_mount(const char *dev_name, const struct path *path, const char *type, unsigned long flags, void *data) { - return call_int_hook(sb_mount, 0, dev_name, path, type, flags, data); + return call_int_hook(sb_mount, dev_name, path, type, flags, data); } /** @@ -1477,7 +1471,7 @@ int security_sb_mount(const char *dev_name, const struct path *path, */ int security_sb_umount(struct vfsmount *mnt, int flags) { - return call_int_hook(sb_umount, 0, mnt, flags); + return call_int_hook(sb_umount, mnt, flags); } /** @@ -1492,7 +1486,7 @@ int security_sb_umount(struct vfsmount *mnt, int flags) int security_sb_pivotroot(const struct path *old_path, const struct path *new_path) { - return call_int_hook(sb_pivotroot, 0, old_path, new_path); + return call_int_hook(sb_pivotroot, old_path, new_path); } /** @@ -1511,9 +1505,17 @@ int security_sb_set_mnt_opts(struct super_block *sb, unsigned long kern_flags, unsigned long *set_kern_flags) { - return call_int_hook(sb_set_mnt_opts, - mnt_opts ? -EOPNOTSUPP : 0, sb, - mnt_opts, kern_flags, set_kern_flags); + struct security_hook_list *hp; + int rc = mnt_opts ? -EOPNOTSUPP : LSM_RET_DEFAULT(sb_set_mnt_opts); + + hlist_for_each_entry(hp, &security_hook_heads.sb_set_mnt_opts, + list) { + rc = hp->hook.sb_set_mnt_opts(sb, mnt_opts, kern_flags, + set_kern_flags); + if (rc != LSM_RET_DEFAULT(sb_set_mnt_opts)) + break; + } + return rc; } EXPORT_SYMBOL(security_sb_set_mnt_opts); @@ -1533,7 +1535,7 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb, unsigned long kern_flags, unsigned long *set_kern_flags) { - return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb, + return call_int_hook(sb_clone_mnt_opts, oldsb, newsb, kern_flags, set_kern_flags); } EXPORT_SYMBOL(security_sb_clone_mnt_opts); @@ -1550,7 +1552,7 @@ EXPORT_SYMBOL(security_sb_clone_mnt_opts); int security_move_mount(const struct path *from_path, const struct path *to_path) { - return call_int_hook(move_mount, 0, from_path, to_path); + return call_int_hook(move_mount, from_path, to_path); } /** @@ -1567,7 +1569,7 @@ int security_move_mount(const struct path *from_path, int security_path_notify(const struct path *path, u64 mask, unsigned int obj_type) { - return call_int_hook(path_notify, 0, path, mask, obj_type); + return call_int_hook(path_notify, path, mask, obj_type); } /** @@ -1586,7 +1588,7 @@ int security_inode_alloc(struct inode *inode) if (unlikely(rc)) return rc; - rc = call_int_hook(inode_alloc_security, 0, inode); + rc = call_int_hook(inode_alloc_security, inode); if (unlikely(rc)) security_inode_free(inode); return rc; @@ -1608,7 +1610,6 @@ static void inode_free_by_rcu(struct rcu_head *head) */ void security_inode_free(struct inode *inode) { - integrity_inode_free(inode); call_void_hook(inode_free_security, inode); /* * The inode may still be referenced in a path walk and @@ -1644,20 +1645,8 @@ int security_dentry_init_security(struct dentry *dentry, int mode, const char **xattr_name, void **ctx, u32 *ctxlen) { - struct security_hook_list *hp; - int rc; - - /* - * Only one module will provide a security context. - */ - hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security, - list) { - rc = hp->hook.dentry_init_security(dentry, mode, name, - xattr_name, ctx, ctxlen); - if (rc != LSM_RET_DEFAULT(dentry_init_security)) - return rc; - } - return LSM_RET_DEFAULT(dentry_init_security); + return call_int_hook(dentry_init_security, dentry, mode, name, + xattr_name, ctx, ctxlen); } EXPORT_SYMBOL(security_dentry_init_security); @@ -1680,7 +1669,7 @@ int security_dentry_create_files_as(struct dentry *dentry, int mode, struct qstr *name, const struct cred *old, struct cred *new) { - return call_int_hook(dentry_create_files_as, 0, dentry, mode, + return call_int_hook(dentry_create_files_as, dentry, mode, name, old, new); } EXPORT_SYMBOL(security_dentry_create_files_as); @@ -1727,8 +1716,8 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, return 0; if (initxattrs) { - /* Allocate +1 for EVM and +1 as terminator. */ - new_xattrs = kcalloc(blob_sizes.lbs_xattr_count + 2, + /* Allocate +1 as terminator. */ + new_xattrs = kcalloc(blob_sizes.lbs_xattr_count + 1, sizeof(*new_xattrs), GFP_NOFS); if (!new_xattrs) return -ENOMEM; @@ -1752,10 +1741,6 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, if (!xattr_count) goto out; - ret = evm_inode_init_security(inode, dir, qstr, new_xattrs, - &xattr_count); - if (ret) - goto out; ret = initxattrs(inode, new_xattrs, fs_data); out: for (; xattr_count > 0; xattr_count--) @@ -1781,7 +1766,7 @@ int security_inode_init_security_anon(struct inode *inode, const struct qstr *name, const struct inode *context_inode) { - return call_int_hook(inode_init_security_anon, 0, inode, name, + return call_int_hook(inode_init_security_anon, inode, name, context_inode); } @@ -1803,10 +1788,24 @@ int security_path_mknod(const struct path *dir, struct dentry *dentry, { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; - return call_int_hook(path_mknod, 0, dir, dentry, mode, dev); + return call_int_hook(path_mknod, dir, dentry, mode, dev); } EXPORT_SYMBOL(security_path_mknod); +/** + * security_path_post_mknod() - Update inode security after reg file creation + * @idmap: idmap of the mount + * @dentry: new file + * + * Update inode security field after a regular file has been created. + */ +void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry) +{ + if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) + return; + call_void_hook(path_post_mknod, idmap, dentry); +} + /** * security_path_mkdir() - Check if creating a new directory is allowed * @dir: parent directory @@ -1822,7 +1821,7 @@ int security_path_mkdir(const struct path *dir, struct dentry *dentry, { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; - return call_int_hook(path_mkdir, 0, dir, dentry, mode); + return call_int_hook(path_mkdir, dir, dentry, mode); } EXPORT_SYMBOL(security_path_mkdir); @@ -1839,7 +1838,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; - return call_int_hook(path_rmdir, 0, dir, dentry); + return call_int_hook(path_rmdir, dir, dentry); } /** @@ -1855,7 +1854,7 @@ int security_path_unlink(const struct path *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; - return call_int_hook(path_unlink, 0, dir, dentry); + return call_int_hook(path_unlink, dir, dentry); } EXPORT_SYMBOL(security_path_unlink); @@ -1874,7 +1873,7 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry, { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; - return call_int_hook(path_symlink, 0, dir, dentry, old_name); + return call_int_hook(path_symlink, dir, dentry, old_name); } /** @@ -1892,7 +1891,7 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, { if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)))) return 0; - return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); + return call_int_hook(path_link, old_dentry, new_dir, new_dentry); } /** @@ -1916,7 +1915,7 @@ int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, IS_PRIVATE(d_backing_inode(new_dentry))))) return 0; - return call_int_hook(path_rename, 0, old_dir, old_dentry, new_dir, + return call_int_hook(path_rename, old_dir, old_dentry, new_dir, new_dentry, flags); } EXPORT_SYMBOL(security_path_rename); @@ -1935,7 +1934,7 @@ int security_path_truncate(const struct path *path) { if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry)))) return 0; - return call_int_hook(path_truncate, 0, path); + return call_int_hook(path_truncate, path); } /** @@ -1953,7 +1952,7 @@ int security_path_chmod(const struct path *path, umode_t mode) { if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry)))) return 0; - return call_int_hook(path_chmod, 0, path, mode); + return call_int_hook(path_chmod, path, mode); } /** @@ -1970,7 +1969,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) { if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry)))) return 0; - return call_int_hook(path_chown, 0, path, uid, gid); + return call_int_hook(path_chown, path, uid, gid); } /** @@ -1983,7 +1982,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) */ int security_path_chroot(const struct path *path) { - return call_int_hook(path_chroot, 0, path); + return call_int_hook(path_chroot, path); } #endif /* CONFIG_SECURITY_PATH */ @@ -2002,10 +2001,25 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, { if (unlikely(IS_PRIVATE(dir))) return 0; - return call_int_hook(inode_create, 0, dir, dentry, mode); + return call_int_hook(inode_create, dir, dentry, mode); } EXPORT_SYMBOL_GPL(security_inode_create); +/** + * security_inode_post_create_tmpfile() - Update inode security of new tmpfile + * @idmap: idmap of the mount + * @inode: inode of the new tmpfile + * + * Update inode security data after a tmpfile has been created. + */ +void security_inode_post_create_tmpfile(struct mnt_idmap *idmap, + struct inode *inode) +{ + if (unlikely(IS_PRIVATE(inode))) + return; + call_void_hook(inode_post_create_tmpfile, idmap, inode); +} + /** * security_inode_link() - Check if creating a hard link is allowed * @old_dentry: existing file @@ -2021,7 +2035,7 @@ int security_inode_link(struct dentry *old_dentry, struct inode *dir, { if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)))) return 0; - return call_int_hook(inode_link, 0, old_dentry, dir, new_dentry); + return call_int_hook(inode_link, old_dentry, dir, new_dentry); } /** @@ -2037,7 +2051,7 @@ int security_inode_unlink(struct inode *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - return call_int_hook(inode_unlink, 0, dir, dentry); + return call_int_hook(inode_unlink, dir, dentry); } /** @@ -2055,7 +2069,7 @@ int security_inode_symlink(struct inode *dir, struct dentry *dentry, { if (unlikely(IS_PRIVATE(dir))) return 0; - return call_int_hook(inode_symlink, 0, dir, dentry, old_name); + return call_int_hook(inode_symlink, dir, dentry, old_name); } /** @@ -2073,7 +2087,7 @@ int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { if (unlikely(IS_PRIVATE(dir))) return 0; - return call_int_hook(inode_mkdir, 0, dir, dentry, mode); + return call_int_hook(inode_mkdir, dir, dentry, mode); } EXPORT_SYMBOL_GPL(security_inode_mkdir); @@ -2090,7 +2104,7 @@ int security_inode_rmdir(struct inode *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - return call_int_hook(inode_rmdir, 0, dir, dentry); + return call_int_hook(inode_rmdir, dir, dentry); } /** @@ -2112,7 +2126,7 @@ int security_inode_mknod(struct inode *dir, struct dentry *dentry, { if (unlikely(IS_PRIVATE(dir))) return 0; - return call_int_hook(inode_mknod, 0, dir, dentry, mode, dev); + return call_int_hook(inode_mknod, dir, dentry, mode, dev); } /** @@ -2137,13 +2151,13 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, return 0; if (flags & RENAME_EXCHANGE) { - int err = call_int_hook(inode_rename, 0, new_dir, new_dentry, + int err = call_int_hook(inode_rename, new_dir, new_dentry, old_dir, old_dentry); if (err) return err; } - return call_int_hook(inode_rename, 0, old_dir, old_dentry, + return call_int_hook(inode_rename, old_dir, old_dentry, new_dir, new_dentry); } @@ -2159,7 +2173,7 @@ int security_inode_readlink(struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - return call_int_hook(inode_readlink, 0, dentry); + return call_int_hook(inode_readlink, dentry); } /** @@ -2178,7 +2192,7 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode, { if (unlikely(IS_PRIVATE(inode))) return 0; - return call_int_hook(inode_follow_link, 0, dentry, inode, rcu); + return call_int_hook(inode_follow_link, dentry, inode, rcu); } /** @@ -2199,7 +2213,7 @@ int security_inode_permission(struct inode *inode, int mask) { if (unlikely(IS_PRIVATE(inode))) return 0; - return call_int_hook(inode_permission, 0, inode, mask); + return call_int_hook(inode_permission, inode, mask); } /** @@ -2218,17 +2232,28 @@ int security_inode_permission(struct inode *inode, int mask) int security_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr) { - int ret; - if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - ret = call_int_hook(inode_setattr, 0, dentry, attr); - if (ret) - return ret; - return evm_inode_setattr(idmap, dentry, attr); + return call_int_hook(inode_setattr, idmap, dentry, attr); } EXPORT_SYMBOL_GPL(security_inode_setattr); +/** + * security_inode_post_setattr() - Update the inode after a setattr operation + * @idmap: idmap of the mount + * @dentry: file + * @ia_valid: file attributes set + * + * Update inode security field after successful setting file attributes. + */ +void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + int ia_valid) +{ + if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) + return; + call_void_hook(inode_post_setattr, idmap, dentry, ia_valid); +} + /** * security_inode_getattr() - Check if getting file attributes is allowed * @path: file @@ -2241,7 +2266,7 @@ int security_inode_getattr(const struct path *path) { if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry)))) return 0; - return call_int_hook(inode_getattr, 0, path); + return call_int_hook(inode_getattr, path); } /** @@ -2269,17 +2294,12 @@ int security_inode_setxattr(struct mnt_idmap *idmap, * SELinux and Smack integrate the cap call, * so assume that all LSMs supplying this call do so. */ - ret = call_int_hook(inode_setxattr, 1, idmap, dentry, name, value, - size, flags); + ret = call_int_hook(inode_setxattr, idmap, dentry, name, value, size, + flags); if (ret == 1) ret = cap_inode_setxattr(dentry, name, value, size, flags); - if (ret) - return ret; - ret = ima_inode_setxattr(dentry, name, value, size); - if (ret) - return ret; - return evm_inode_setxattr(idmap, dentry, name, value, size); + return ret; } /** @@ -2298,18 +2318,26 @@ int security_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name, struct posix_acl *kacl) { - int ret; - if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - ret = call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name, - kacl); - if (ret) - return ret; - ret = ima_inode_set_acl(idmap, dentry, acl_name, kacl); - if (ret) - return ret; - return evm_inode_set_acl(idmap, dentry, acl_name, kacl); + return call_int_hook(inode_set_acl, idmap, dentry, acl_name, kacl); +} + +/** + * security_inode_post_set_acl() - Update inode security from posix acls set + * @dentry: file + * @acl_name: acl name + * @kacl: acl struct + * + * Update inode security data after successfully setting posix acls on @dentry. + * The posix acls in @kacl are identified by @acl_name. + */ +void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name, + struct posix_acl *kacl) +{ + if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) + return; + call_void_hook(inode_post_set_acl, dentry, acl_name, kacl); } /** @@ -2328,7 +2356,7 @@ int security_inode_get_acl(struct mnt_idmap *idmap, { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - return call_int_hook(inode_get_acl, 0, idmap, dentry, acl_name); + return call_int_hook(inode_get_acl, idmap, dentry, acl_name); } /** @@ -2345,17 +2373,26 @@ int security_inode_get_acl(struct mnt_idmap *idmap, int security_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name) { - int ret; - if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - ret = call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name); - if (ret) - return ret; - ret = ima_inode_remove_acl(idmap, dentry, acl_name); - if (ret) - return ret; - return evm_inode_remove_acl(idmap, dentry, acl_name); + return call_int_hook(inode_remove_acl, idmap, dentry, acl_name); +} + +/** + * security_inode_post_remove_acl() - Update inode security after rm posix acls + * @idmap: idmap of the mount + * @dentry: file + * @acl_name: acl name + * + * Update inode security data after successfully removing posix acls on + * @dentry in @idmap. The posix acls are identified by @acl_name. + */ +void security_inode_post_remove_acl(struct mnt_idmap *idmap, + struct dentry *dentry, const char *acl_name) +{ + if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) + return; + call_void_hook(inode_post_remove_acl, idmap, dentry, acl_name); } /** @@ -2374,7 +2411,6 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name, if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return; call_void_hook(inode_post_setxattr, dentry, name, value, size, flags); - evm_inode_post_setxattr(dentry, name, value, size); } /** @@ -2391,7 +2427,7 @@ int security_inode_getxattr(struct dentry *dentry, const char *name) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - return call_int_hook(inode_getxattr, 0, dentry, name); + return call_int_hook(inode_getxattr, dentry, name); } /** @@ -2407,7 +2443,7 @@ int security_inode_listxattr(struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return 0; - return call_int_hook(inode_listxattr, 0, dentry); + return call_int_hook(inode_listxattr, dentry); } /** @@ -2432,15 +2468,24 @@ int security_inode_removexattr(struct mnt_idmap *idmap, * SELinux and Smack integrate the cap call, * so assume that all LSMs supplying this call do so. */ - ret = call_int_hook(inode_removexattr, 1, idmap, dentry, name); + ret = call_int_hook(inode_removexattr, idmap, dentry, name); if (ret == 1) ret = cap_inode_removexattr(idmap, dentry, name); - if (ret) - return ret; - ret = ima_inode_removexattr(dentry, name); - if (ret) - return ret; - return evm_inode_removexattr(idmap, dentry, name); + return ret; +} + +/** + * security_inode_post_removexattr() - Update the inode after a removexattr op + * @dentry: file + * @name: xattr name + * + * Update the inode after a successful removexattr operation. + */ +void security_inode_post_removexattr(struct dentry *dentry, const char *name) +{ + if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) + return; + call_void_hook(inode_post_removexattr, dentry, name); } /** @@ -2456,7 +2501,7 @@ int security_inode_removexattr(struct mnt_idmap *idmap, */ int security_inode_need_killpriv(struct dentry *dentry) { - return call_int_hook(inode_need_killpriv, 0, dentry); + return call_int_hook(inode_need_killpriv, dentry); } /** @@ -2473,7 +2518,7 @@ int security_inode_need_killpriv(struct dentry *dentry) int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry) { - return call_int_hook(inode_killpriv, 0, idmap, dentry); + return call_int_hook(inode_killpriv, idmap, dentry); } /** @@ -2496,21 +2541,11 @@ int security_inode_getsecurity(struct mnt_idmap *idmap, struct inode *inode, const char *name, void **buffer, bool alloc) { - struct security_hook_list *hp; - int rc; - if (unlikely(IS_PRIVATE(inode))) return LSM_RET_DEFAULT(inode_getsecurity); - /* - * Only one module will provide an attribute with a given name. - */ - hlist_for_each_entry(hp, &security_hook_heads.inode_getsecurity, list) { - rc = hp->hook.inode_getsecurity(idmap, inode, name, buffer, - alloc); - if (rc != LSM_RET_DEFAULT(inode_getsecurity)) - return rc; - } - return LSM_RET_DEFAULT(inode_getsecurity); + + return call_int_hook(inode_getsecurity, idmap, inode, name, buffer, + alloc); } /** @@ -2531,21 +2566,11 @@ int security_inode_getsecurity(struct mnt_idmap *idmap, int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) { - struct security_hook_list *hp; - int rc; - if (unlikely(IS_PRIVATE(inode))) return LSM_RET_DEFAULT(inode_setsecurity); - /* - * Only one module will provide an attribute with a given name. - */ - hlist_for_each_entry(hp, &security_hook_heads.inode_setsecurity, list) { - rc = hp->hook.inode_setsecurity(inode, name, value, size, - flags); - if (rc != LSM_RET_DEFAULT(inode_setsecurity)) - return rc; - } - return LSM_RET_DEFAULT(inode_setsecurity); + + return call_int_hook(inode_setsecurity, inode, name, value, size, + flags); } /** @@ -2566,7 +2591,7 @@ int security_inode_listsecurity(struct inode *inode, { if (unlikely(IS_PRIVATE(inode))) return 0; - return call_int_hook(inode_listsecurity, 0, inode, buffer, buffer_size); + return call_int_hook(inode_listsecurity, inode, buffer, buffer_size); } EXPORT_SYMBOL(security_inode_listsecurity); @@ -2597,7 +2622,7 @@ void security_inode_getsecid(struct inode *inode, u32 *secid) */ int security_inode_copy_up(struct dentry *src, struct cred **new) { - return call_int_hook(inode_copy_up, 0, src, new); + return call_int_hook(inode_copy_up, src, new); } EXPORT_SYMBOL(security_inode_copy_up); @@ -2615,7 +2640,6 @@ EXPORT_SYMBOL(security_inode_copy_up); */ int security_inode_copy_up_xattr(const char *name) { - struct security_hook_list *hp; int rc; /* @@ -2623,14 +2647,11 @@ int security_inode_copy_up_xattr(const char *name) * xattr), -EOPNOTSUPP if it does not know anything about the xattr or * any other error code in case of an error. */ - hlist_for_each_entry(hp, - &security_hook_heads.inode_copy_up_xattr, list) { - rc = hp->hook.inode_copy_up_xattr(name); - if (rc != LSM_RET_DEFAULT(inode_copy_up_xattr)) - return rc; - } + rc = call_int_hook(inode_copy_up_xattr, name); + if (rc != LSM_RET_DEFAULT(inode_copy_up_xattr)) + return rc; - return evm_inode_copy_up_xattr(name); + return LSM_RET_DEFAULT(inode_copy_up_xattr); } EXPORT_SYMBOL(security_inode_copy_up_xattr); @@ -2647,7 +2668,7 @@ EXPORT_SYMBOL(security_inode_copy_up_xattr); int security_kernfs_init_security(struct kernfs_node *kn_dir, struct kernfs_node *kn) { - return call_int_hook(kernfs_init_security, 0, kn_dir, kn); + return call_int_hook(kernfs_init_security, kn_dir, kn); } /** @@ -2671,7 +2692,7 @@ int security_kernfs_init_security(struct kernfs_node *kn_dir, */ int security_file_permission(struct file *file, int mask) { - return call_int_hook(file_permission, 0, file, mask); + return call_int_hook(file_permission, file, mask); } /** @@ -2689,12 +2710,23 @@ int security_file_alloc(struct file *file) if (rc) return rc; - rc = call_int_hook(file_alloc_security, 0, file); + rc = call_int_hook(file_alloc_security, file); if (unlikely(rc)) security_file_free(file); return rc; } +/** + * security_file_release() - Perform actions before releasing the file ref + * @file: the file + * + * Perform actions before releasing the last reference to a file. + */ +void security_file_release(struct file *file) +{ + call_void_hook(file_release, file); +} + /** * security_file_free() - Free a file's LSM blob * @file: the file @@ -2729,7 +2761,7 @@ void security_file_free(struct file *file) */ int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return call_int_hook(file_ioctl, 0, file, cmd, arg); + return call_int_hook(file_ioctl, file, cmd, arg); } EXPORT_SYMBOL_GPL(security_file_ioctl); @@ -2747,7 +2779,7 @@ EXPORT_SYMBOL_GPL(security_file_ioctl); int security_file_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) { - return call_int_hook(file_ioctl_compat, 0, file, cmd, arg); + return call_int_hook(file_ioctl_compat, file, cmd, arg); } EXPORT_SYMBOL_GPL(security_file_ioctl_compat); @@ -2798,13 +2830,8 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot) int security_mmap_file(struct file *file, unsigned long prot, unsigned long flags) { - unsigned long prot_adj = mmap_prot(file, prot); - int ret; - - ret = call_int_hook(mmap_file, 0, file, prot, prot_adj, flags); - if (ret) - return ret; - return ima_file_mmap(file, prot, prot_adj, flags); + return call_int_hook(mmap_file, file, prot, mmap_prot(file, prot), + flags); } /** @@ -2817,7 +2844,7 @@ int security_mmap_file(struct file *file, unsigned long prot, */ int security_mmap_addr(unsigned long addr) { - return call_int_hook(mmap_addr, 0, addr); + return call_int_hook(mmap_addr, addr); } /** @@ -2833,12 +2860,7 @@ int security_mmap_addr(unsigned long addr) int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot) { - int ret; - - ret = call_int_hook(file_mprotect, 0, vma, reqprot, prot); - if (ret) - return ret; - return ima_file_mprotect(vma, prot); + return call_int_hook(file_mprotect, vma, reqprot, prot); } /** @@ -2853,7 +2875,7 @@ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, */ int security_file_lock(struct file *file, unsigned int cmd) { - return call_int_hook(file_lock, 0, file, cmd); + return call_int_hook(file_lock, file, cmd); } /** @@ -2872,7 +2894,7 @@ int security_file_lock(struct file *file, unsigned int cmd) */ int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg) { - return call_int_hook(file_fcntl, 0, file, cmd, arg); + return call_int_hook(file_fcntl, file, cmd, arg); } /** @@ -2906,11 +2928,11 @@ void security_file_set_fowner(struct file *file) int security_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int sig) { - return call_int_hook(file_send_sigiotask, 0, tsk, fown, sig); + return call_int_hook(file_send_sigiotask, tsk, fown, sig); } /** - * security_file_receive() - Check is receiving a file via IPC is allowed + * security_file_receive() - Check if receiving a file via IPC is allowed * @file: file being received * * This hook allows security modules to control the ability of a process to @@ -2920,7 +2942,7 @@ int security_file_send_sigiotask(struct task_struct *tsk, */ int security_file_receive(struct file *file) { - return call_int_hook(file_receive, 0, file); + return call_int_hook(file_receive, file); } /** @@ -2936,13 +2958,30 @@ int security_file_open(struct file *file) { int ret; - ret = call_int_hook(file_open, 0, file); + ret = call_int_hook(file_open, file); if (ret) return ret; return fsnotify_open_perm(file); } +/** + * security_file_post_open() - Evaluate a file after it has been opened + * @file: the file + * @mask: access mask + * + * Evaluate an opened file and the access mask requested with open(). The hook + * is useful for LSMs that require the file content to be available in order to + * make decisions. + * + * Return: Returns 0 if permission is granted. + */ +int security_file_post_open(struct file *file, int mask) +{ + return call_int_hook(file_post_open, file, mask); +} +EXPORT_SYMBOL_GPL(security_file_post_open); + /** * security_file_truncate() - Check if truncating a file is allowed * @file: file @@ -2955,7 +2994,7 @@ int security_file_open(struct file *file) */ int security_file_truncate(struct file *file) { - return call_int_hook(file_truncate, 0, file); + return call_int_hook(file_truncate, file); } /** @@ -2973,7 +3012,7 @@ int security_task_alloc(struct task_struct *task, unsigned long clone_flags) if (rc) return rc; - rc = call_int_hook(task_alloc, 0, task, clone_flags); + rc = call_int_hook(task_alloc, task, clone_flags); if (unlikely(rc)) security_task_free(task); return rc; @@ -3011,7 +3050,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) if (rc) return rc; - rc = call_int_hook(cred_alloc_blank, 0, cred, gfp); + rc = call_int_hook(cred_alloc_blank, cred, gfp); if (unlikely(rc)) security_cred_free(cred); return rc; @@ -3055,7 +3094,7 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) if (rc) return rc; - rc = call_int_hook(cred_prepare, 0, new, old, gfp); + rc = call_int_hook(cred_prepare, new, old, gfp); if (unlikely(rc)) security_cred_free(new); return rc; @@ -3100,7 +3139,7 @@ EXPORT_SYMBOL(security_cred_getsecid); */ int security_kernel_act_as(struct cred *new, u32 secid) { - return call_int_hook(kernel_act_as, 0, new, secid); + return call_int_hook(kernel_act_as, new, secid); } /** @@ -3116,11 +3155,11 @@ int security_kernel_act_as(struct cred *new, u32 secid) */ int security_kernel_create_files_as(struct cred *new, struct inode *inode) { - return call_int_hook(kernel_create_files_as, 0, new, inode); + return call_int_hook(kernel_create_files_as, new, inode); } /** - * security_kernel_module_request() - Check is loading a module is allowed + * security_kernel_module_request() - Check if loading a module is allowed * @kmod_name: module name * * Ability to trigger the kernel to automatically upcall to userspace for @@ -3130,12 +3169,7 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) */ int security_kernel_module_request(char *kmod_name) { - int ret; - - ret = call_int_hook(kernel_module_request, 0, kmod_name); - if (ret) - return ret; - return integrity_kernel_module_request(kmod_name); + return call_int_hook(kernel_module_request, kmod_name); } /** @@ -3151,12 +3185,7 @@ int security_kernel_module_request(char *kmod_name) int security_kernel_read_file(struct file *file, enum kernel_read_file_id id, bool contents) { - int ret; - - ret = call_int_hook(kernel_read_file, 0, file, id, contents); - if (ret) - return ret; - return ima_read_file(file, id, contents); + return call_int_hook(kernel_read_file, file, id, contents); } EXPORT_SYMBOL_GPL(security_kernel_read_file); @@ -3176,12 +3205,7 @@ EXPORT_SYMBOL_GPL(security_kernel_read_file); int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id) { - int ret; - - ret = call_int_hook(kernel_post_read_file, 0, file, buf, size, id); - if (ret) - return ret; - return ima_post_read_file(file, buf, size, id); + return call_int_hook(kernel_post_read_file, file, buf, size, id); } EXPORT_SYMBOL_GPL(security_kernel_post_read_file); @@ -3196,12 +3220,7 @@ EXPORT_SYMBOL_GPL(security_kernel_post_read_file); */ int security_kernel_load_data(enum kernel_load_data_id id, bool contents) { - int ret; - - ret = call_int_hook(kernel_load_data, 0, id, contents); - if (ret) - return ret; - return ima_load_data(id, contents); + return call_int_hook(kernel_load_data, id, contents); } EXPORT_SYMBOL_GPL(security_kernel_load_data); @@ -3223,13 +3242,7 @@ int security_kernel_post_load_data(char *buf, loff_t size, enum kernel_load_data_id id, char *description) { - int ret; - - ret = call_int_hook(kernel_post_load_data, 0, buf, size, id, - description); - if (ret) - return ret; - return ima_post_load_data(buf, size, id, description); + return call_int_hook(kernel_post_load_data, buf, size, id, description); } EXPORT_SYMBOL_GPL(security_kernel_post_load_data); @@ -3250,7 +3263,7 @@ EXPORT_SYMBOL_GPL(security_kernel_post_load_data); int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) { - return call_int_hook(task_fix_setuid, 0, new, old, flags); + return call_int_hook(task_fix_setuid, new, old, flags); } /** @@ -3270,7 +3283,7 @@ int security_task_fix_setuid(struct cred *new, const struct cred *old, int security_task_fix_setgid(struct cred *new, const struct cred *old, int flags) { - return call_int_hook(task_fix_setgid, 0, new, old, flags); + return call_int_hook(task_fix_setgid, new, old, flags); } /** @@ -3287,7 +3300,7 @@ int security_task_fix_setgid(struct cred *new, const struct cred *old, */ int security_task_fix_setgroups(struct cred *new, const struct cred *old) { - return call_int_hook(task_fix_setgroups, 0, new, old); + return call_int_hook(task_fix_setgroups, new, old); } /** @@ -3302,7 +3315,7 @@ int security_task_fix_setgroups(struct cred *new, const struct cred *old) */ int security_task_setpgid(struct task_struct *p, pid_t pgid) { - return call_int_hook(task_setpgid, 0, p, pgid); + return call_int_hook(task_setpgid, p, pgid); } /** @@ -3316,7 +3329,7 @@ int security_task_setpgid(struct task_struct *p, pid_t pgid) */ int security_task_getpgid(struct task_struct *p) { - return call_int_hook(task_getpgid, 0, p); + return call_int_hook(task_getpgid, p); } /** @@ -3329,7 +3342,7 @@ int security_task_getpgid(struct task_struct *p) */ int security_task_getsid(struct task_struct *p) { - return call_int_hook(task_getsid, 0, p); + return call_int_hook(task_getsid, p); } /** @@ -3372,7 +3385,7 @@ EXPORT_SYMBOL(security_task_getsecid_obj); */ int security_task_setnice(struct task_struct *p, int nice) { - return call_int_hook(task_setnice, 0, p, nice); + return call_int_hook(task_setnice, p, nice); } /** @@ -3386,7 +3399,7 @@ int security_task_setnice(struct task_struct *p, int nice) */ int security_task_setioprio(struct task_struct *p, int ioprio) { - return call_int_hook(task_setioprio, 0, p, ioprio); + return call_int_hook(task_setioprio, p, ioprio); } /** @@ -3399,7 +3412,7 @@ int security_task_setioprio(struct task_struct *p, int ioprio) */ int security_task_getioprio(struct task_struct *p) { - return call_int_hook(task_getioprio, 0, p); + return call_int_hook(task_getioprio, p); } /** @@ -3416,7 +3429,7 @@ int security_task_getioprio(struct task_struct *p) int security_task_prlimit(const struct cred *cred, const struct cred *tcred, unsigned int flags) { - return call_int_hook(task_prlimit, 0, cred, tcred, flags); + return call_int_hook(task_prlimit, cred, tcred, flags); } /** @@ -3434,7 +3447,7 @@ int security_task_prlimit(const struct cred *cred, const struct cred *tcred, int security_task_setrlimit(struct task_struct *p, unsigned int resource, struct rlimit *new_rlim) { - return call_int_hook(task_setrlimit, 0, p, resource, new_rlim); + return call_int_hook(task_setrlimit, p, resource, new_rlim); } /** @@ -3448,7 +3461,7 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource, */ int security_task_setscheduler(struct task_struct *p) { - return call_int_hook(task_setscheduler, 0, p); + return call_int_hook(task_setscheduler, p); } /** @@ -3461,7 +3474,7 @@ int security_task_setscheduler(struct task_struct *p) */ int security_task_getscheduler(struct task_struct *p) { - return call_int_hook(task_getscheduler, 0, p); + return call_int_hook(task_getscheduler, p); } /** @@ -3474,7 +3487,7 @@ int security_task_getscheduler(struct task_struct *p) */ int security_task_movememory(struct task_struct *p) { - return call_int_hook(task_movememory, 0, p); + return call_int_hook(task_movememory, p); } /** @@ -3495,7 +3508,7 @@ int security_task_movememory(struct task_struct *p) int security_task_kill(struct task_struct *p, struct kernel_siginfo *info, int sig, const struct cred *cred) { - return call_int_hook(task_kill, 0, p, info, sig, cred); + return call_int_hook(task_kill, p, info, sig, cred); } /** @@ -3553,7 +3566,7 @@ void security_task_to_inode(struct task_struct *p, struct inode *inode) */ int security_create_user_ns(const struct cred *cred) { - return call_int_hook(userns_create, 0, cred); + return call_int_hook(userns_create, cred); } /** @@ -3567,7 +3580,7 @@ int security_create_user_ns(const struct cred *cred) */ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag) { - return call_int_hook(ipc_permission, 0, ipcp, flag); + return call_int_hook(ipc_permission, ipcp, flag); } /** @@ -3599,7 +3612,7 @@ int security_msg_msg_alloc(struct msg_msg *msg) if (unlikely(rc)) return rc; - rc = call_int_hook(msg_msg_alloc_security, 0, msg); + rc = call_int_hook(msg_msg_alloc_security, msg); if (unlikely(rc)) security_msg_msg_free(msg); return rc; @@ -3633,7 +3646,7 @@ int security_msg_queue_alloc(struct kern_ipc_perm *msq) if (unlikely(rc)) return rc; - rc = call_int_hook(msg_queue_alloc_security, 0, msq); + rc = call_int_hook(msg_queue_alloc_security, msq); if (unlikely(rc)) security_msg_queue_free(msq); return rc; @@ -3665,7 +3678,7 @@ void security_msg_queue_free(struct kern_ipc_perm *msq) */ int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) { - return call_int_hook(msg_queue_associate, 0, msq, msqflg); + return call_int_hook(msg_queue_associate, msq, msqflg); } /** @@ -3680,7 +3693,7 @@ int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) */ int security_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd) { - return call_int_hook(msg_queue_msgctl, 0, msq, cmd); + return call_int_hook(msg_queue_msgctl, msq, cmd); } /** @@ -3697,7 +3710,7 @@ int security_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd) int security_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg) { - return call_int_hook(msg_queue_msgsnd, 0, msq, msg, msqflg); + return call_int_hook(msg_queue_msgsnd, msq, msg, msqflg); } /** @@ -3718,7 +3731,7 @@ int security_msg_queue_msgsnd(struct kern_ipc_perm *msq, int security_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg, struct task_struct *target, long type, int mode) { - return call_int_hook(msg_queue_msgrcv, 0, msq, msg, target, type, mode); + return call_int_hook(msg_queue_msgrcv, msq, msg, target, type, mode); } /** @@ -3736,7 +3749,7 @@ int security_shm_alloc(struct kern_ipc_perm *shp) if (unlikely(rc)) return rc; - rc = call_int_hook(shm_alloc_security, 0, shp); + rc = call_int_hook(shm_alloc_security, shp); if (unlikely(rc)) security_shm_free(shp); return rc; @@ -3769,7 +3782,7 @@ void security_shm_free(struct kern_ipc_perm *shp) */ int security_shm_associate(struct kern_ipc_perm *shp, int shmflg) { - return call_int_hook(shm_associate, 0, shp, shmflg); + return call_int_hook(shm_associate, shp, shmflg); } /** @@ -3784,7 +3797,7 @@ int security_shm_associate(struct kern_ipc_perm *shp, int shmflg) */ int security_shm_shmctl(struct kern_ipc_perm *shp, int cmd) { - return call_int_hook(shm_shmctl, 0, shp, cmd); + return call_int_hook(shm_shmctl, shp, cmd); } /** @@ -3802,7 +3815,7 @@ int security_shm_shmctl(struct kern_ipc_perm *shp, int cmd) int security_shm_shmat(struct kern_ipc_perm *shp, char __user *shmaddr, int shmflg) { - return call_int_hook(shm_shmat, 0, shp, shmaddr, shmflg); + return call_int_hook(shm_shmat, shp, shmaddr, shmflg); } /** @@ -3820,7 +3833,7 @@ int security_sem_alloc(struct kern_ipc_perm *sma) if (unlikely(rc)) return rc; - rc = call_int_hook(sem_alloc_security, 0, sma); + rc = call_int_hook(sem_alloc_security, sma); if (unlikely(rc)) security_sem_free(sma); return rc; @@ -3852,7 +3865,7 @@ void security_sem_free(struct kern_ipc_perm *sma) */ int security_sem_associate(struct kern_ipc_perm *sma, int semflg) { - return call_int_hook(sem_associate, 0, sma, semflg); + return call_int_hook(sem_associate, sma, semflg); } /** @@ -3867,7 +3880,7 @@ int security_sem_associate(struct kern_ipc_perm *sma, int semflg) */ int security_sem_semctl(struct kern_ipc_perm *sma, int cmd) { - return call_int_hook(sem_semctl, 0, sma, cmd); + return call_int_hook(sem_semctl, sma, cmd); } /** @@ -3885,7 +3898,7 @@ int security_sem_semctl(struct kern_ipc_perm *sma, int cmd) int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops, unsigned nsops, int alter) { - return call_int_hook(sem_semop, 0, sma, sops, nsops, alter); + return call_int_hook(sem_semop, sma, sops, nsops, alter); } /** @@ -4116,11 +4129,11 @@ int security_setprocattr(int lsmid, const char *name, void *value, size_t size) */ int security_netlink_send(struct sock *sk, struct sk_buff *skb) { - return call_int_hook(netlink_send, 0, sk, skb); + return call_int_hook(netlink_send, sk, skb); } /** - * security_ismaclabel() - Check is the named attribute is a MAC label + * security_ismaclabel() - Check if the named attribute is a MAC label * @name: full extended attribute name * * Check if the extended attribute specified by @name represents a MAC label. @@ -4129,7 +4142,7 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb) */ int security_ismaclabel(const char *name) { - return call_int_hook(ismaclabel, 0, name); + return call_int_hook(ismaclabel, name); } EXPORT_SYMBOL(security_ismaclabel); @@ -4148,20 +4161,7 @@ EXPORT_SYMBOL(security_ismaclabel); */ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { - struct security_hook_list *hp; - int rc; - - /* - * Currently, only one LSM can implement secid_to_secctx (i.e this - * LSM hook is not "stackable"). - */ - hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) { - rc = hp->hook.secid_to_secctx(secid, secdata, seclen); - if (rc != LSM_RET_DEFAULT(secid_to_secctx)) - return rc; - } - - return LSM_RET_DEFAULT(secid_to_secctx); + return call_int_hook(secid_to_secctx, secid, secdata, seclen); } EXPORT_SYMBOL(security_secid_to_secctx); @@ -4178,7 +4178,7 @@ EXPORT_SYMBOL(security_secid_to_secctx); int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) { *secid = 0; - return call_int_hook(secctx_to_secid, 0, secdata, seclen, secid); + return call_int_hook(secctx_to_secid, secdata, seclen, secid); } EXPORT_SYMBOL(security_secctx_to_secid); @@ -4225,7 +4225,7 @@ EXPORT_SYMBOL(security_inode_invalidate_secctx); */ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) { - return call_int_hook(inode_notifysecctx, 0, inode, ctx, ctxlen); + return call_int_hook(inode_notifysecctx, inode, ctx, ctxlen); } EXPORT_SYMBOL(security_inode_notifysecctx); @@ -4247,7 +4247,7 @@ EXPORT_SYMBOL(security_inode_notifysecctx); */ int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) { - return call_int_hook(inode_setsecctx, 0, dentry, ctx, ctxlen); + return call_int_hook(inode_setsecctx, dentry, ctx, ctxlen); } EXPORT_SYMBOL(security_inode_setsecctx); @@ -4264,19 +4264,7 @@ EXPORT_SYMBOL(security_inode_setsecctx); */ int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) { - struct security_hook_list *hp; - int rc; - - /* - * Only one module will provide a security context. - */ - hlist_for_each_entry(hp, &security_hook_heads.inode_getsecctx, list) { - rc = hp->hook.inode_getsecctx(inode, ctx, ctxlen); - if (rc != LSM_RET_DEFAULT(inode_getsecctx)) - return rc; - } - - return LSM_RET_DEFAULT(inode_getsecctx); + return call_int_hook(inode_getsecctx, inode, ctx, ctxlen); } EXPORT_SYMBOL(security_inode_getsecctx); @@ -4295,7 +4283,7 @@ int security_post_notification(const struct cred *w_cred, const struct cred *cred, struct watch_notification *n) { - return call_int_hook(post_notification, 0, w_cred, cred, n); + return call_int_hook(post_notification, w_cred, cred, n); } #endif /* CONFIG_WATCH_QUEUE */ @@ -4311,7 +4299,7 @@ int security_post_notification(const struct cred *w_cred, */ int security_watch_key(struct key *key) { - return call_int_hook(watch_key, 0, key); + return call_int_hook(watch_key, key); } #endif /* CONFIG_KEY_NOTIFICATIONS */ @@ -4340,7 +4328,7 @@ int security_watch_key(struct key *key) int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk) { - return call_int_hook(unix_stream_connect, 0, sock, other, newsk); + return call_int_hook(unix_stream_connect, sock, other, newsk); } EXPORT_SYMBOL(security_unix_stream_connect); @@ -4366,7 +4354,7 @@ EXPORT_SYMBOL(security_unix_stream_connect); */ int security_unix_may_send(struct socket *sock, struct socket *other) { - return call_int_hook(unix_may_send, 0, sock, other); + return call_int_hook(unix_may_send, sock, other); } EXPORT_SYMBOL(security_unix_may_send); @@ -4383,7 +4371,7 @@ EXPORT_SYMBOL(security_unix_may_send); */ int security_socket_create(int family, int type, int protocol, int kern) { - return call_int_hook(socket_create, 0, family, type, protocol, kern); + return call_int_hook(socket_create, family, type, protocol, kern); } /** @@ -4407,7 +4395,7 @@ int security_socket_create(int family, int type, int protocol, int kern) int security_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { - return call_int_hook(socket_post_create, 0, sock, family, type, + return call_int_hook(socket_post_create, sock, family, type, protocol, kern); } @@ -4423,7 +4411,7 @@ int security_socket_post_create(struct socket *sock, int family, */ int security_socket_socketpair(struct socket *socka, struct socket *sockb) { - return call_int_hook(socket_socketpair, 0, socka, sockb); + return call_int_hook(socket_socketpair, socka, sockb); } EXPORT_SYMBOL(security_socket_socketpair); @@ -4442,7 +4430,7 @@ EXPORT_SYMBOL(security_socket_socketpair); int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { - return call_int_hook(socket_bind, 0, sock, address, addrlen); + return call_int_hook(socket_bind, sock, address, addrlen); } /** @@ -4459,7 +4447,7 @@ int security_socket_bind(struct socket *sock, int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) { - return call_int_hook(socket_connect, 0, sock, address, addrlen); + return call_int_hook(socket_connect, sock, address, addrlen); } /** @@ -4473,7 +4461,7 @@ int security_socket_connect(struct socket *sock, */ int security_socket_listen(struct socket *sock, int backlog) { - return call_int_hook(socket_listen, 0, sock, backlog); + return call_int_hook(socket_listen, sock, backlog); } /** @@ -4489,11 +4477,11 @@ int security_socket_listen(struct socket *sock, int backlog) */ int security_socket_accept(struct socket *sock, struct socket *newsock) { - return call_int_hook(socket_accept, 0, sock, newsock); + return call_int_hook(socket_accept, sock, newsock); } /** - * security_socket_sendmsg() - Check is sending a message is allowed + * security_socket_sendmsg() - Check if sending a message is allowed * @sock: sending socket * @msg: message to send * @size: size of message @@ -4504,7 +4492,7 @@ int security_socket_accept(struct socket *sock, struct socket *newsock) */ int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { - return call_int_hook(socket_sendmsg, 0, sock, msg, size); + return call_int_hook(socket_sendmsg, sock, msg, size); } /** @@ -4521,7 +4509,7 @@ int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) int security_socket_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags) { - return call_int_hook(socket_recvmsg, 0, sock, msg, size, flags); + return call_int_hook(socket_recvmsg, sock, msg, size, flags); } /** @@ -4535,7 +4523,7 @@ int security_socket_recvmsg(struct socket *sock, struct msghdr *msg, */ int security_socket_getsockname(struct socket *sock) { - return call_int_hook(socket_getsockname, 0, sock); + return call_int_hook(socket_getsockname, sock); } /** @@ -4548,7 +4536,7 @@ int security_socket_getsockname(struct socket *sock) */ int security_socket_getpeername(struct socket *sock) { - return call_int_hook(socket_getpeername, 0, sock); + return call_int_hook(socket_getpeername, sock); } /** @@ -4564,7 +4552,7 @@ int security_socket_getpeername(struct socket *sock) */ int security_socket_getsockopt(struct socket *sock, int level, int optname) { - return call_int_hook(socket_getsockopt, 0, sock, level, optname); + return call_int_hook(socket_getsockopt, sock, level, optname); } /** @@ -4579,7 +4567,7 @@ int security_socket_getsockopt(struct socket *sock, int level, int optname) */ int security_socket_setsockopt(struct socket *sock, int level, int optname) { - return call_int_hook(socket_setsockopt, 0, sock, level, optname); + return call_int_hook(socket_setsockopt, sock, level, optname); } /** @@ -4594,7 +4582,7 @@ int security_socket_setsockopt(struct socket *sock, int level, int optname) */ int security_socket_shutdown(struct socket *sock, int how) { - return call_int_hook(socket_shutdown, 0, sock, how); + return call_int_hook(socket_shutdown, sock, how); } /** @@ -4611,7 +4599,7 @@ int security_socket_shutdown(struct socket *sock, int how) */ int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) { - return call_int_hook(socket_sock_rcv_skb, 0, sk, skb); + return call_int_hook(socket_sock_rcv_skb, sk, skb); } EXPORT_SYMBOL(security_sock_rcv_skb); @@ -4633,20 +4621,8 @@ EXPORT_SYMBOL(security_sock_rcv_skb); int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, sockptr_t optlen, unsigned int len) { - struct security_hook_list *hp; - int rc; - - /* - * Only one module will provide a security context. - */ - hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream, - list) { - rc = hp->hook.socket_getpeersec_stream(sock, optval, optlen, - len); - if (rc != LSM_RET_DEFAULT(socket_getpeersec_stream)) - return rc; - } - return LSM_RET_DEFAULT(socket_getpeersec_stream); + return call_int_hook(socket_getpeersec_stream, sock, optval, optlen, + len); } /** @@ -4666,19 +4642,7 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { - struct security_hook_list *hp; - int rc; - - /* - * Only one module will provide a security context. - */ - hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram, - list) { - rc = hp->hook.socket_getpeersec_dgram(sock, skb, secid); - if (rc != LSM_RET_DEFAULT(socket_getpeersec_dgram)) - return rc; - } - return LSM_RET_DEFAULT(socket_getpeersec_dgram); + return call_int_hook(socket_getpeersec_dgram, sock, skb, secid); } EXPORT_SYMBOL(security_socket_getpeersec_dgram); @@ -4695,7 +4659,7 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram); */ int security_sk_alloc(struct sock *sk, int family, gfp_t priority) { - return call_int_hook(sk_alloc_security, 0, sk, family, priority); + return call_int_hook(sk_alloc_security, sk, family, priority); } /** @@ -4776,7 +4740,7 @@ EXPORT_SYMBOL(security_sock_graft); int security_inet_conn_request(const struct sock *sk, struct sk_buff *skb, struct request_sock *req) { - return call_int_hook(inet_conn_request, 0, sk, skb, req); + return call_int_hook(inet_conn_request, sk, skb, req); } EXPORT_SYMBOL(security_inet_conn_request); @@ -4817,7 +4781,7 @@ EXPORT_SYMBOL(security_inet_conn_established); */ int security_secmark_relabel_packet(u32 secid) { - return call_int_hook(secmark_relabel_packet, 0, secid); + return call_int_hook(secmark_relabel_packet, secid); } EXPORT_SYMBOL(security_secmark_relabel_packet); @@ -4854,7 +4818,7 @@ EXPORT_SYMBOL(security_secmark_refcount_dec); */ int security_tun_dev_alloc_security(void **security) { - return call_int_hook(tun_dev_alloc_security, 0, security); + return call_int_hook(tun_dev_alloc_security, security); } EXPORT_SYMBOL(security_tun_dev_alloc_security); @@ -4879,7 +4843,7 @@ EXPORT_SYMBOL(security_tun_dev_free_security); */ int security_tun_dev_create(void) { - return call_int_hook(tun_dev_create, 0); + return call_int_hook(tun_dev_create); } EXPORT_SYMBOL(security_tun_dev_create); @@ -4893,7 +4857,7 @@ EXPORT_SYMBOL(security_tun_dev_create); */ int security_tun_dev_attach_queue(void *security) { - return call_int_hook(tun_dev_attach_queue, 0, security); + return call_int_hook(tun_dev_attach_queue, security); } EXPORT_SYMBOL(security_tun_dev_attach_queue); @@ -4909,7 +4873,7 @@ EXPORT_SYMBOL(security_tun_dev_attach_queue); */ int security_tun_dev_attach(struct sock *sk, void *security) { - return call_int_hook(tun_dev_attach, 0, sk, security); + return call_int_hook(tun_dev_attach, sk, security); } EXPORT_SYMBOL(security_tun_dev_attach); @@ -4924,7 +4888,7 @@ EXPORT_SYMBOL(security_tun_dev_attach); */ int security_tun_dev_open(void *security) { - return call_int_hook(tun_dev_open, 0, security); + return call_int_hook(tun_dev_open, security); } EXPORT_SYMBOL(security_tun_dev_open); @@ -4940,7 +4904,7 @@ EXPORT_SYMBOL(security_tun_dev_open); int security_sctp_assoc_request(struct sctp_association *asoc, struct sk_buff *skb) { - return call_int_hook(sctp_assoc_request, 0, asoc, skb); + return call_int_hook(sctp_assoc_request, asoc, skb); } EXPORT_SYMBOL(security_sctp_assoc_request); @@ -4961,8 +4925,7 @@ EXPORT_SYMBOL(security_sctp_assoc_request); int security_sctp_bind_connect(struct sock *sk, int optname, struct sockaddr *address, int addrlen) { - return call_int_hook(sctp_bind_connect, 0, sk, optname, - address, addrlen); + return call_int_hook(sctp_bind_connect, sk, optname, address, addrlen); } EXPORT_SYMBOL(security_sctp_bind_connect); @@ -4996,7 +4959,7 @@ 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); + return call_int_hook(sctp_assoc_established, asoc, skb); } EXPORT_SYMBOL(security_sctp_assoc_established); @@ -5014,7 +4977,7 @@ EXPORT_SYMBOL(security_sctp_assoc_established); */ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk) { - return call_int_hook(mptcp_add_subflow, 0, sk, ssk); + return call_int_hook(mptcp_add_subflow, sk, ssk); } #endif /* CONFIG_SECURITY_NETWORK */ @@ -5032,7 +4995,7 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk) */ int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey) { - return call_int_hook(ib_pkey_access, 0, sec, subnet_prefix, pkey); + return call_int_hook(ib_pkey_access, sec, subnet_prefix, pkey); } EXPORT_SYMBOL(security_ib_pkey_access); @@ -5049,8 +5012,7 @@ EXPORT_SYMBOL(security_ib_pkey_access); int security_ib_endport_manage_subnet(void *sec, const char *dev_name, u8 port_num) { - return call_int_hook(ib_endport_manage_subnet, 0, sec, - dev_name, port_num); + return call_int_hook(ib_endport_manage_subnet, sec, dev_name, port_num); } EXPORT_SYMBOL(security_ib_endport_manage_subnet); @@ -5064,7 +5026,7 @@ EXPORT_SYMBOL(security_ib_endport_manage_subnet); */ int security_ib_alloc_security(void **sec) { - return call_int_hook(ib_alloc_security, 0, sec); + return call_int_hook(ib_alloc_security, sec); } EXPORT_SYMBOL(security_ib_alloc_security); @@ -5097,7 +5059,7 @@ int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp) { - return call_int_hook(xfrm_policy_alloc_security, 0, ctxp, sec_ctx, gfp); + return call_int_hook(xfrm_policy_alloc_security, ctxp, sec_ctx, gfp); } EXPORT_SYMBOL(security_xfrm_policy_alloc); @@ -5114,7 +5076,7 @@ EXPORT_SYMBOL(security_xfrm_policy_alloc); int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp) { - return call_int_hook(xfrm_policy_clone_security, 0, old_ctx, new_ctxp); + return call_int_hook(xfrm_policy_clone_security, old_ctx, new_ctxp); } /** @@ -5139,7 +5101,7 @@ EXPORT_SYMBOL(security_xfrm_policy_free); */ int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { - return call_int_hook(xfrm_policy_delete_security, 0, ctx); + return call_int_hook(xfrm_policy_delete_security, ctx); } /** @@ -5156,7 +5118,7 @@ int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) { - return call_int_hook(xfrm_state_alloc, 0, x, sec_ctx); + return call_int_hook(xfrm_state_alloc, x, sec_ctx); } EXPORT_SYMBOL(security_xfrm_state_alloc); @@ -5175,7 +5137,7 @@ EXPORT_SYMBOL(security_xfrm_state_alloc); int security_xfrm_state_alloc_acquire(struct xfrm_state *x, struct xfrm_sec_ctx *polsec, u32 secid) { - return call_int_hook(xfrm_state_alloc_acquire, 0, x, polsec, secid); + return call_int_hook(xfrm_state_alloc_acquire, x, polsec, secid); } /** @@ -5188,7 +5150,7 @@ int security_xfrm_state_alloc_acquire(struct xfrm_state *x, */ int security_xfrm_state_delete(struct xfrm_state *x) { - return call_int_hook(xfrm_state_delete_security, 0, x); + return call_int_hook(xfrm_state_delete_security, x); } EXPORT_SYMBOL(security_xfrm_state_delete); @@ -5217,7 +5179,7 @@ void security_xfrm_state_free(struct xfrm_state *x) */ int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid) { - return call_int_hook(xfrm_policy_lookup, 0, ctx, fl_secid); + return call_int_hook(xfrm_policy_lookup, ctx, fl_secid); } /** @@ -5265,12 +5227,12 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x, */ int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) { - return call_int_hook(xfrm_decode_session, 0, skb, secid, 1); + return call_int_hook(xfrm_decode_session, skb, secid, 1); } void security_skb_classify_flow(struct sk_buff *skb, struct flowi_common *flic) { - int rc = call_int_hook(xfrm_decode_session, 0, skb, &flic->flowic_secid, + int rc = call_int_hook(xfrm_decode_session, skb, &flic->flowic_secid, 0); BUG_ON(rc); @@ -5293,7 +5255,7 @@ EXPORT_SYMBOL(security_skb_classify_flow); int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags) { - return call_int_hook(key_alloc, 0, key, cred, flags); + return call_int_hook(key_alloc, key, cred, flags); } /** @@ -5320,7 +5282,7 @@ void security_key_free(struct key *key) int security_key_permission(key_ref_t key_ref, const struct cred *cred, enum key_need_perm need_perm) { - return call_int_hook(key_permission, 0, key_ref, cred, need_perm); + return call_int_hook(key_permission, key_ref, cred, need_perm); } /** @@ -5339,7 +5301,26 @@ int security_key_permission(key_ref_t key_ref, const struct cred *cred, int security_key_getsecurity(struct key *key, char **buffer) { *buffer = NULL; - return call_int_hook(key_getsecurity, 0, key, buffer); + return call_int_hook(key_getsecurity, key, buffer); +} + +/** + * security_key_post_create_or_update() - Notification of key create or update + * @keyring: keyring to which the key is linked to + * @key: created or updated key + * @payload: data used to instantiate or update the key + * @payload_len: length of payload + * @flags: key flags + * @create: flag indicating whether the key was created or updated + * + * Notify the caller of a key creation or update. + */ +void security_key_post_create_or_update(struct key *keyring, struct key *key, + const void *payload, size_t payload_len, + unsigned long flags, bool create) +{ + call_void_hook(key_post_create_or_update, keyring, key, payload, + payload_len, flags, create); } #endif /* CONFIG_KEYS */ @@ -5350,15 +5331,17 @@ int security_key_getsecurity(struct key *key, char **buffer) * @op: rule operator * @rulestr: rule context * @lsmrule: receive buffer for audit rule struct + * @gfp: GFP flag used for kmalloc * * Allocate and initialize an LSM audit rule structure. * * Return: Return 0 if @lsmrule has been successfully set, -EINVAL in case of * an invalid rule. */ -int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule) +int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule, + gfp_t gfp) { - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule); + return call_int_hook(audit_rule_init, field, op, rulestr, lsmrule, gfp); } /** @@ -5372,7 +5355,7 @@ int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule) */ int security_audit_rule_known(struct audit_krule *krule) { - return call_int_hook(audit_rule_known, 0, krule); + return call_int_hook(audit_rule_known, krule); } /** @@ -5402,7 +5385,7 @@ void security_audit_rule_free(void *lsmrule) */ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule) { - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule); + return call_int_hook(audit_rule_match, secid, field, op, lsmrule); } #endif /* CONFIG_AUDIT */ @@ -5421,7 +5404,7 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule) */ int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) { - return call_int_hook(bpf, 0, cmd, attr, size); + return call_int_hook(bpf, cmd, attr, size); } /** @@ -5436,7 +5419,7 @@ int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) */ int security_bpf_map(struct bpf_map *map, fmode_t fmode) { - return call_int_hook(bpf_map, 0, map, fmode); + return call_int_hook(bpf_map, map, fmode); } /** @@ -5450,33 +5433,91 @@ int security_bpf_map(struct bpf_map *map, fmode_t fmode) */ int security_bpf_prog(struct bpf_prog *prog) { - return call_int_hook(bpf_prog, 0, prog); + return call_int_hook(bpf_prog, prog); } /** - * security_bpf_map_alloc() - Allocate a bpf map LSM blob - * @map: bpf map + * security_bpf_map_create() - Check if BPF map creation is allowed + * @map: BPF map object + * @attr: BPF syscall attributes used to create BPF map + * @token: BPF token used to grant user access * - * Initialize the security field inside bpf map. + * Do a check when the kernel creates a new BPF map. This is also the + * point where LSM blob is allocated for LSMs that need them. * * Return: Returns 0 on success, error on failure. */ -int security_bpf_map_alloc(struct bpf_map *map) +int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) { - return call_int_hook(bpf_map_alloc_security, 0, map); + return call_int_hook(bpf_map_create, map, attr, token); } /** - * security_bpf_prog_alloc() - Allocate a bpf program LSM blob - * @aux: bpf program aux info struct + * security_bpf_prog_load() - Check if loading of BPF program is allowed + * @prog: BPF program object + * @attr: BPF syscall attributes used to create BPF program + * @token: BPF token used to grant user access to BPF subsystem * - * Initialize the security field inside bpf program. + * Perform an access control check when the kernel loads a BPF program and + * allocates associated BPF program object. This hook is also responsible for + * allocating any required LSM state for the BPF program. * * Return: Returns 0 on success, error on failure. */ -int security_bpf_prog_alloc(struct bpf_prog_aux *aux) +int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) { - return call_int_hook(bpf_prog_alloc_security, 0, aux); + return call_int_hook(bpf_prog_load, prog, attr, token); +} + +/** + * security_bpf_token_create() - Check if creating of BPF token is allowed + * @token: BPF token object + * @attr: BPF syscall attributes used to create BPF token + * @path: path pointing to BPF FS mount point from which BPF token is created + * + * Do a check when the kernel instantiates a new BPF token object from BPF FS + * instance. This is also the point where LSM blob can be allocated for LSMs. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path) +{ + return call_int_hook(bpf_token_create, token, attr, path); +} + +/** + * security_bpf_token_cmd() - Check if BPF token is allowed to delegate + * requested BPF syscall command + * @token: BPF token object + * @cmd: BPF syscall command requested to be delegated by BPF token + * + * Do a check when the kernel decides whether provided BPF token should allow + * delegation of requested BPF syscall command. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd) +{ + return call_int_hook(bpf_token_cmd, token, cmd); +} + +/** + * security_bpf_token_capable() - Check if BPF token is allowed to delegate + * requested BPF-related capability + * @token: BPF token object + * @cap: capabilities requested to be delegated by BPF token + * + * Do a check when the kernel decides whether provided BPF token should allow + * delegation of requested BPF-related capabilities. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_capable(const struct bpf_token *token, int cap) +{ + return call_int_hook(bpf_token_capable, token, cap); } /** @@ -5487,18 +5528,29 @@ int security_bpf_prog_alloc(struct bpf_prog_aux *aux) */ void security_bpf_map_free(struct bpf_map *map) { - call_void_hook(bpf_map_free_security, map); + call_void_hook(bpf_map_free, map); +} + +/** + * security_bpf_prog_free() - Free a BPF program's LSM blob + * @prog: BPF program struct + * + * Clean up the security information stored inside BPF program. + */ +void security_bpf_prog_free(struct bpf_prog *prog) +{ + call_void_hook(bpf_prog_free, prog); } /** - * security_bpf_prog_free() - Free a bpf program's LSM blob - * @aux: bpf program aux info struct + * security_bpf_token_free() - Free a BPF token's LSM blob + * @token: BPF token struct * - * Clean up the security information stored inside bpf prog. + * Clean up the security information stored inside BPF token. */ -void security_bpf_prog_free(struct bpf_prog_aux *aux) +void security_bpf_token_free(struct bpf_token *token) { - call_void_hook(bpf_prog_free_security, aux); + call_void_hook(bpf_token_free, token); } #endif /* CONFIG_BPF_SYSCALL */ @@ -5513,7 +5565,7 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux) */ int security_locked_down(enum lockdown_reason what) { - return call_int_hook(locked_down, 0, what); + return call_int_hook(locked_down, what); } EXPORT_SYMBOL(security_locked_down); @@ -5529,7 +5581,7 @@ EXPORT_SYMBOL(security_locked_down); */ int security_perf_event_open(struct perf_event_attr *attr, int type) { - return call_int_hook(perf_event_open, 0, attr, type); + return call_int_hook(perf_event_open, attr, type); } /** @@ -5542,7 +5594,7 @@ int security_perf_event_open(struct perf_event_attr *attr, int type) */ int security_perf_event_alloc(struct perf_event *event) { - return call_int_hook(perf_event_alloc, 0, event); + return call_int_hook(perf_event_alloc, event); } /** @@ -5566,7 +5618,7 @@ void security_perf_event_free(struct perf_event *event) */ int security_perf_event_read(struct perf_event *event) { - return call_int_hook(perf_event_read, 0, event); + return call_int_hook(perf_event_read, event); } /** @@ -5579,7 +5631,7 @@ int security_perf_event_read(struct perf_event *event) */ int security_perf_event_write(struct perf_event *event) { - return call_int_hook(perf_event_write, 0, event); + return call_int_hook(perf_event_write, event); } #endif /* CONFIG_PERF_EVENTS */ @@ -5595,7 +5647,7 @@ int security_perf_event_write(struct perf_event *event) */ int security_uring_override_creds(const struct cred *new) { - return call_int_hook(uring_override_creds, 0, new); + return call_int_hook(uring_override_creds, new); } /** @@ -5608,7 +5660,7 @@ int security_uring_override_creds(const struct cred *new) */ int security_uring_sqpoll(void) { - return call_int_hook(uring_sqpoll, 0); + return call_int_hook(uring_sqpoll); } /** @@ -5621,6 +5673,6 @@ int security_uring_sqpoll(void) */ int security_uring_cmd(struct io_uring_cmd *ioucmd) { - return call_int_hook(uring_cmd, 0, ioucmd); + return call_int_hook(uring_cmd, ioucmd); } #endif /* CONFIG_IO_URING */ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 71e6e7079d..3448454c82 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2920,23 +2920,22 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, struct superblock_security_struct *sbsec; struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count); u32 newsid, clen; + u16 newsclass; int rc; char *context; sbsec = selinux_superblock(dir->i_sb); newsid = tsec->create_sid; - - rc = selinux_determine_inode_label(tsec, dir, qstr, - inode_mode_to_security_class(inode->i_mode), - &newsid); + newsclass = inode_mode_to_security_class(inode->i_mode); + rc = selinux_determine_inode_label(tsec, dir, qstr, newsclass, &newsid); if (rc) return rc; /* Possibly defer initialization to selinux_complete_init. */ if (sbsec->flags & SE_SBINITIALIZED) { struct inode_security_struct *isec = selinux_inode(inode); - isec->sclass = inode_mode_to_security_class(inode->i_mode); + isec->sclass = newsclass; isec->sid = newsid; isec->initialized = LABEL_INITIALIZED; } @@ -3136,7 +3135,8 @@ static int selinux_inode_permission(struct inode *inode, int mask) return rc; } -static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) +static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + struct iattr *iattr) { const struct cred *cred = current_cred(); struct inode *inode = d_backing_inode(dentry); @@ -3534,9 +3534,10 @@ static int selinux_inode_copy_up_xattr(const char *name) { /* The copy_up hook above sets the initial context on an inode, but we * don't then want to overwrite it by blindly copying all the lower - * xattrs up. Instead, we have to filter out SELinux-related xattrs. + * xattrs up. Instead, filter out SELinux-related xattrs following + * policy load. */ - if (strcmp(name, XATTR_NAME_SELINUX) == 0) + if (selinux_initialized() && strcmp(name, XATTR_NAME_SELINUX) == 0) return 1; /* Discard */ /* * Any other attribute apart from SELINUX is not claimed, supported @@ -5194,11 +5195,11 @@ out_len: return err; } -static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) +static int selinux_socket_getpeersec_dgram(struct socket *sock, + struct sk_buff *skb, u32 *secid) { u32 peer_secid = SECSID_NULL; u16 family; - struct inode_security_struct *isec; if (skb && skb->protocol == htons(ETH_P_IP)) family = PF_INET; @@ -5206,19 +5207,21 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * family = PF_INET6; else if (sock) family = sock->sk->sk_family; - else - goto out; + else { + *secid = SECSID_NULL; + return -EINVAL; + } if (sock && family == PF_UNIX) { + struct inode_security_struct *isec; isec = inode_security_novalidate(SOCK_INODE(sock)); peer_secid = isec->sid; } else if (skb) selinux_skb_peerlbl_sid(skb, family, &peer_secid); -out: *secid = peer_secid; if (peer_secid == SECSID_NULL) - return -EINVAL; + return -ENOPROTOOPT; return 0; } @@ -6920,7 +6923,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog) BPF__PROG_RUN, NULL); } -static int selinux_bpf_map_alloc(struct bpf_map *map) +static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) { struct bpf_security_struct *bpfsec; @@ -6942,7 +6946,31 @@ static void selinux_bpf_map_free(struct bpf_map *map) kfree(bpfsec); } -static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) +static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) +{ + struct bpf_security_struct *bpfsec; + + bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); + if (!bpfsec) + return -ENOMEM; + + bpfsec->sid = current_sid(); + prog->aux->security = bpfsec; + + return 0; +} + +static void selinux_bpf_prog_free(struct bpf_prog *prog) +{ + struct bpf_security_struct *bpfsec = prog->aux->security; + + prog->aux->security = NULL; + kfree(bpfsec); +} + +static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path) { struct bpf_security_struct *bpfsec; @@ -6951,16 +6979,16 @@ static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) return -ENOMEM; bpfsec->sid = current_sid(); - aux->security = bpfsec; + token->security = bpfsec; return 0; } -static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) +static void selinux_bpf_token_free(struct bpf_token *token) { - struct bpf_security_struct *bpfsec = aux->security; + struct bpf_security_struct *bpfsec = token->security; - aux->security = NULL; + token->security = NULL; kfree(bpfsec); } #endif @@ -7324,8 +7352,9 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(bpf, selinux_bpf), LSM_HOOK_INIT(bpf_map, selinux_bpf_map), LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), - LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), - LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), + LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free), + LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), + LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free), #endif #ifdef CONFIG_PERF_EVENTS @@ -7382,8 +7411,9 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init), #endif #ifdef CONFIG_BPF_SYSCALL - LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), - LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc), + LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create), + LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load), + LSM_HOOK_INIT(bpf_token_create, selinux_bpf_token_create), #endif #ifdef CONFIG_PERF_EVENTS LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h index 52aca71210..29c7d4c86f 100644 --- a/security/selinux/include/audit.h +++ b/security/selinux/include/audit.h @@ -21,12 +21,14 @@ * @op: the operator the rule uses * @rulestr: the text "target" of the rule * @rule: pointer to the new rule structure returned via this + * @gfp: GFP flag used for kmalloc * * Returns 0 if successful, -errno if not. On success, the rule structure * will be allocated internally. The caller must free this structure with * selinux_audit_rule_free() after use. */ -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule); +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule, + gfp_t gfp); /** * selinux_audit_rule_free - free an selinux audit rule structure. diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 697eb43524..2ad98732d0 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -1,20 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Implementation of the access vector table type. * * Author : Stephen Smalley, */ -/* Updated: Frank Mayer and Karl MacMillan - * - * Added conditional policy language extensions - * - * Copyright (C) 2003 Tresys Technology, LLC - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. +/* Updated: Frank Mayer and + * Karl MacMillan + * Added conditional policy language extensions + * Copyright (C) 2003 Tresys Technology, LLC * * Updated: Yuichi Nakamura - * Tuned number of hash slots for avtab to reduce memory usage + * Tuned number of hash slots for avtab to reduce memory usage */ #include @@ -36,19 +33,20 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask) static const u32 c2 = 0x1b873593; static const u32 r1 = 15; static const u32 r2 = 13; - static const u32 m = 5; - static const u32 n = 0xe6546b64; + static const u32 m = 5; + static const u32 n = 0xe6546b64; u32 hash = 0; -#define mix(input) do { \ - u32 v = input; \ - v *= c1; \ - v = (v << r1) | (v >> (32 - r1)); \ - v *= c2; \ - hash ^= v; \ +#define mix(input) \ + do { \ + u32 v = input; \ + v *= c1; \ + v = (v << r1) | (v >> (32 - r1)); \ + v *= c2; \ + hash ^= v; \ hash = (hash << r2) | (hash >> (32 - r2)); \ - hash = hash * m + n; \ + hash = hash * m + n; \ } while (0) mix(keyp->target_class); @@ -66,9 +64,10 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask) return hash & mask; } -static struct avtab_node* -avtab_insert_node(struct avtab *h, struct avtab_node **dst, - const struct avtab_key *key, const struct avtab_datum *datum) +static struct avtab_node *avtab_insert_node(struct avtab *h, + struct avtab_node **dst, + const struct avtab_key *key, + const struct avtab_datum *datum) { struct avtab_node *newnode; struct avtab_extended_perms *xperms; @@ -99,7 +98,7 @@ avtab_insert_node(struct avtab *h, struct avtab_node **dst, static int avtab_node_cmp(const struct avtab_key *key1, const struct avtab_key *key2) { - u16 specified = key1->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); + u16 specified = key1->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); if (key1->source_type == key2->source_type && key1->target_type == key2->target_type && @@ -129,8 +128,7 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key, return -EINVAL; hvalue = avtab_hash(key, h->mask); - for (prev = NULL, cur = h->htable[hvalue]; - cur; + for (prev = NULL, cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) { cmp = avtab_node_cmp(key, &cur->key); /* extended perms may not be unique */ @@ -163,8 +161,7 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h, if (!h || !h->nslot || h->nel == U32_MAX) return NULL; hvalue = avtab_hash(key, h->mask); - for (prev = NULL, cur = h->htable[hvalue]; - cur; + for (prev = NULL, cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) { cmp = avtab_node_cmp(key, &cur->key); if (cmp <= 0) @@ -188,8 +185,7 @@ struct avtab_node *avtab_search_node(struct avtab *h, return NULL; hvalue = avtab_hash(key, h->mask); - for (cur = h->htable[hvalue]; cur; - cur = cur->next) { + for (cur = h->htable[hvalue]; cur; cur = cur->next) { cmp = avtab_node_cmp(key, &cur->key); if (cmp == 0) return cur; @@ -199,8 +195,8 @@ struct avtab_node *avtab_search_node(struct avtab *h, return NULL; } -struct avtab_node* -avtab_search_node_next(struct avtab_node *node, u16 specified) +struct avtab_node *avtab_search_node_next(struct avtab_node *node, + u16 specified) { struct avtab_key tmp_key; struct avtab_node *cur; @@ -314,17 +310,19 @@ void avtab_hash_eval(struct avtab *h, const char *tag) if (chain_len > max_chain_len) max_chain_len = chain_len; - chain2_len_sum += (unsigned long long)chain_len * chain_len; + chain2_len_sum += + (unsigned long long)chain_len * chain_len; } } pr_debug("SELinux: %s: %d entries and %d/%d buckets used, " - "longest chain length %d, sum of chain length^2 %llu\n", - tag, h->nel, slots_used, h->nslot, max_chain_len, - chain2_len_sum); + "longest chain length %d, sum of chain length^2 %llu\n", + tag, h->nel, slots_used, h->nslot, max_chain_len, + chain2_len_sum); } #endif /* CONFIG_SECURITY_SELINUX_DEBUG */ +/* clang-format off */ static const uint16_t spec_order[] = { AVTAB_ALLOWED, AVTAB_AUDITDENY, @@ -336,6 +334,7 @@ static const uint16_t spec_order[] = { AVTAB_XPERMS_AUDITALLOW, AVTAB_XPERMS_DONTAUDIT }; +/* clang-format on */ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, int (*insertf)(struct avtab *a, const struct avtab_key *k, @@ -365,9 +364,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, if (items2 > ARRAY_SIZE(buf32)) { pr_err("SELinux: avtab: entry overflow\n"); return -EINVAL; - } - rc = next_entry(buf32, fp, sizeof(u32)*items2); + rc = next_entry(buf32, fp, sizeof(u32) * items2); if (rc) { pr_err("SELinux: avtab: truncated entry\n"); return rc; @@ -400,8 +398,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, pr_err("SELinux: avtab: null entry\n"); return -EINVAL; } - if ((val & AVTAB_AV) && - (val & AVTAB_TYPE)) { + if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) { pr_err("SELinux: avtab: entry has both access vectors and types\n"); return -EINVAL; } @@ -428,7 +425,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return 0; } - rc = next_entry(buf16, fp, sizeof(u16)*4); + rc = next_entry(buf16, fp, sizeof(u16) * 4); if (rc) { pr_err("SELinux: avtab: truncated entry\n"); return rc; @@ -454,10 +451,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, } if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && - (key.specified & AVTAB_XPERMS)) { + (key.specified & AVTAB_XPERMS)) { pr_err("SELinux: avtab: policy version %u does not " - "support extended permissions rules and one " - "was specified\n", vers); + "support extended permissions rules and one " + "was specified\n", + vers); return -EINVAL; } else if (key.specified & AVTAB_XPERMS) { memset(&xperms, 0, sizeof(struct avtab_extended_perms)); @@ -471,7 +469,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, pr_err("SELinux: avtab: truncated entry\n"); return rc; } - rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p)); + rc = next_entry(buf32, fp, + sizeof(u32) * ARRAY_SIZE(xperms.perms.p)); if (rc) { pr_err("SELinux: avtab: truncated entry\n"); return rc; @@ -507,7 +506,6 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol) __le32 buf[1]; u32 nel, i; - rc = next_entry(buf, fp, sizeof(u32)); if (rc < 0) { pr_err("SELinux: avtab: truncated table\n"); @@ -561,7 +559,8 @@ int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp) return rc; if (cur->key.specified & AVTAB_XPERMS) { - rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp); + rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, + fp); if (rc) return rc; rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp); @@ -570,7 +569,7 @@ int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp) for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++) buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]); rc = put_entry(buf32, sizeof(u32), - ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp); + ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp); } else { buf32[0] = cpu_to_le32(cur->datum.u.data); rc = put_entry(buf32, sizeof(u32), 1, fp); @@ -593,8 +592,7 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp) return rc; for (i = 0; i < a->nslot; i++) { - for (cur = a->htable[i]; cur; - cur = cur->next) { + for (cur = a->htable[i]; cur; cur = cur->next) { rc = avtab_write_item(p, cur, fp); if (rc) return rc; @@ -606,10 +604,9 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp) void __init avtab_cache_init(void) { - avtab_node_cachep = kmem_cache_create("avtab_node", - sizeof(struct avtab_node), - 0, SLAB_PANIC, NULL); - avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms", - sizeof(struct avtab_extended_perms), - 0, SLAB_PANIC, NULL); + avtab_node_cachep = kmem_cache_create( + "avtab_node", sizeof(struct avtab_node), 0, SLAB_PANIC, NULL); + avtab_xperms_cachep = kmem_cache_create( + "avtab_extended_perms", sizeof(struct avtab_extended_perms), 0, + SLAB_PANIC, NULL); } diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index 3c3904bf02..8e8820484c 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -9,42 +9,42 @@ * Author : Stephen Smalley, */ -/* Updated: Frank Mayer and Karl MacMillan - * - * Added conditional policy language extensions - * - * Copyright (C) 2003 Tresys Technology, LLC +/* Updated: Frank Mayer and + * Karl MacMillan + * Added conditional policy language extensions + * Copyright (C) 2003 Tresys Technology, LLC * * Updated: Yuichi Nakamura - * Tuned number of hash slots for avtab to reduce memory usage + * Tuned number of hash slots for avtab to reduce memory usage */ + #ifndef _SS_AVTAB_H_ #define _SS_AVTAB_H_ #include "security.h" struct avtab_key { - u16 source_type; /* source type */ - u16 target_type; /* target type */ - u16 target_class; /* target object class */ -#define AVTAB_ALLOWED 0x0001 -#define AVTAB_AUDITALLOW 0x0002 -#define AVTAB_AUDITDENY 0x0004 -#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) -#define AVTAB_TRANSITION 0x0010 -#define AVTAB_MEMBER 0x0020 -#define AVTAB_CHANGE 0x0040 -#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) + u16 source_type; /* source type */ + u16 target_type; /* target type */ + u16 target_class; /* target object class */ +#define AVTAB_ALLOWED 0x0001 +#define AVTAB_AUDITALLOW 0x0002 +#define AVTAB_AUDITDENY 0x0004 +#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) +#define AVTAB_TRANSITION 0x0010 +#define AVTAB_MEMBER 0x0020 +#define AVTAB_CHANGE 0x0040 +#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) /* extended permissions */ #define AVTAB_XPERMS_ALLOWED 0x0100 -#define AVTAB_XPERMS_AUDITALLOW 0x0200 +#define AVTAB_XPERMS_AUDITALLOW 0x0200 #define AVTAB_XPERMS_DONTAUDIT 0x0400 -#define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \ - AVTAB_XPERMS_AUDITALLOW | \ - AVTAB_XPERMS_DONTAUDIT) -#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ -#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ - u16 specified; /* what field is specified */ +#define AVTAB_XPERMS \ + (AVTAB_XPERMS_ALLOWED | AVTAB_XPERMS_AUDITALLOW | \ + AVTAB_XPERMS_DONTAUDIT) +#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ +#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ + u16 specified; /* what field is specified */ }; /* @@ -53,8 +53,8 @@ struct avtab_key { */ struct avtab_extended_perms { /* These are not flags. All 256 values may be used */ -#define AVTAB_XPERMS_IOCTLFUNCTION 0x01 -#define AVTAB_XPERMS_IOCTLDRIVER 0x02 +#define AVTAB_XPERMS_IOCTLFUNCTION 0x01 +#define AVTAB_XPERMS_IOCTLDRIVER 0x02 /* extension of the avtab_key specified */ u8 specified; /* ioctl, netfilter, ... */ /* @@ -82,9 +82,9 @@ struct avtab_node { struct avtab { struct avtab_node **htable; - u32 nel; /* number of elements */ - u32 nslot; /* number of hash slots */ - u32 mask; /* mask to compute hash func */ + u32 nel; /* number of elements */ + u32 nslot; /* number of hash slots */ + u32 mask; /* mask to compute hash func */ }; void avtab_init(struct avtab *h); @@ -92,6 +92,9 @@ int avtab_alloc(struct avtab *, u32); int avtab_alloc_dup(struct avtab *new, const struct avtab *orig); void avtab_destroy(struct avtab *h); +#define MAX_AVTAB_HASH_BITS 16 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) + #ifdef CONFIG_SECURITY_SELINUX_DEBUG void avtab_hash_eval(struct avtab *h, const char *tag); #else @@ -107,7 +110,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, void *p); int avtab_read(struct avtab *a, void *fp, struct policydb *pol); -int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp); +int avtab_write_item(struct policydb *p, const struct avtab_node *cur, + void *fp); int avtab_write(struct policydb *p, struct avtab *a, void *fp); struct avtab_node *avtab_insert_nonunique(struct avtab *h, @@ -116,11 +120,7 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_node *avtab_search_node(struct avtab *h, const struct avtab_key *key); +struct avtab_node *avtab_search_node_next(struct avtab_node *node, + u16 specified); -struct avtab_node *avtab_search_node_next(struct avtab_node *node, u16 specified); - -#define MAX_AVTAB_HASH_BITS 16 -#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) - -#endif /* _SS_AVTAB_H_ */ - +#endif /* _SS_AVTAB_H_ */ diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 81ff676f20..f12476855b 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0-only +/* SPDX-License-Identifier: GPL-2.0-only */ /* Authors: Karl MacMillan * Frank Mayer - * - * Copyright (C) 2003 - 2004 Tresys Technology, LLC + * Copyright (C) 2003 - 2004 Tresys Technology, LLC */ #include @@ -166,9 +165,8 @@ void cond_policydb_destroy(struct policydb *p) int cond_init_bool_indexes(struct policydb *p) { kfree(p->bool_val_to_struct); - p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim, - sizeof(*p->bool_val_to_struct), - GFP_KERNEL); + p->bool_val_to_struct = kmalloc_array( + p->p_bools.nprim, sizeof(*p->bool_val_to_struct), GFP_KERNEL); if (!p->bool_val_to_struct) return -ENOMEM; return 0; @@ -287,7 +285,8 @@ static int cond_insertf(struct avtab *a, const struct avtab_key *k, if (other) { node_ptr = avtab_search_node(&p->te_cond_avtab, k); if (node_ptr) { - if (avtab_search_node_next(node_ptr, k->specified)) { + if (avtab_search_node_next(node_ptr, + k->specified)) { pr_err("SELinux: too many conflicting type rules.\n"); return -EINVAL; } @@ -478,8 +477,8 @@ int cond_write_bool(void *vkey, void *datum, void *ptr) * the conditional. This means that the avtab with the conditional * rules will not be saved but will be rebuilt on policy load. */ -static int cond_write_av_list(struct policydb *p, - struct cond_av_list *list, struct policy_file *fp) +static int cond_write_av_list(struct policydb *p, struct cond_av_list *list, + struct policy_file *fp) { __le32 buf[1]; u32 i; @@ -500,7 +499,7 @@ static int cond_write_av_list(struct policydb *p, } static int cond_write_node(struct policydb *p, struct cond_node *node, - struct policy_file *fp) + struct policy_file *fp) { __le32 buf[2]; int rc; @@ -555,7 +554,7 @@ int cond_write_list(struct policydb *p, void *fp) } void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, - struct extended_perms_decision *xpermd) + struct extended_perms_decision *xpermd) { struct avtab_node *node; @@ -563,7 +562,7 @@ void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, return; for (node = avtab_search_node(ctab, key); node; - node = avtab_search_node_next(node, key->specified)) { + node = avtab_search_node_next(node, key->specified)) { if (node->key.specified & AVTAB_ENABLED) services_compute_xperms_decision(xpermd, node); } @@ -572,7 +571,7 @@ void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, * av table, and if so, add them to the result */ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, - struct av_decision *avd, struct extended_perms *xperms) + struct av_decision *avd, struct extended_perms *xperms) { struct avtab_node *node; @@ -580,30 +579,29 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, return; for (node = avtab_search_node(ctab, key); node; - node = avtab_search_node_next(node, key->specified)) { - if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == - (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) + node = avtab_search_node_next(node, key->specified)) { + if ((u16)(AVTAB_ALLOWED | AVTAB_ENABLED) == + (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED))) avd->allowed |= node->datum.u.data; - if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == - (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) + if ((u16)(AVTAB_AUDITDENY | AVTAB_ENABLED) == + (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED))) /* Since a '0' in an auditdeny mask represents a * permission we do NOT want to audit (dontaudit), we use * the '&' operand to ensure that all '0's in the mask * are retained (much unlike the allow and auditallow cases). */ avd->auditdeny &= node->datum.u.data; - if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == - (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) + if ((u16)(AVTAB_AUDITALLOW | AVTAB_ENABLED) == + (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED))) avd->auditallow |= node->datum.u.data; if (xperms && (node->key.specified & AVTAB_ENABLED) && - (node->key.specified & AVTAB_XPERMS)) + (node->key.specified & AVTAB_XPERMS)) services_compute_xperms_drivers(xperms, node); } } -static int cond_dup_av_list(struct cond_av_list *new, - struct cond_av_list *orig, - struct avtab *avtab) +static int cond_dup_av_list(struct cond_av_list *new, struct cond_av_list *orig, + struct avtab *avtab) { u32 i; @@ -614,9 +612,8 @@ static int cond_dup_av_list(struct cond_av_list *new, return -ENOMEM; for (i = 0; i < orig->len; i++) { - new->nodes[i] = avtab_insert_nonunique(avtab, - &orig->nodes[i]->key, - &orig->nodes[i]->datum); + new->nodes[i] = avtab_insert_nonunique( + avtab, &orig->nodes[i]->key, &orig->nodes[i]->datum); if (!new->nodes[i]) return -ENOMEM; new->len++; @@ -637,8 +634,7 @@ static int duplicate_policydb_cond_list(struct policydb *newp, newp->cond_list_len = 0; newp->cond_list = kcalloc(origp->cond_list_len, - sizeof(*newp->cond_list), - GFP_KERNEL); + sizeof(*newp->cond_list), GFP_KERNEL); if (!newp->cond_list) goto error; @@ -649,7 +645,8 @@ static int duplicate_policydb_cond_list(struct policydb *newp, newp->cond_list_len++; newn->cur_state = orign->cur_state; - newn->expr.nodes = kmemdup(orign->expr.nodes, + newn->expr.nodes = + kmemdup(orign->expr.nodes, orign->expr.len * sizeof(*orign->expr.nodes), GFP_KERNEL); if (!newn->expr.nodes) @@ -658,12 +655,12 @@ static int duplicate_policydb_cond_list(struct policydb *newp, newn->expr.len = orign->expr.len; rc = cond_dup_av_list(&newn->true_list, &orign->true_list, - &newp->te_cond_avtab); + &newp->te_cond_avtab); if (rc) goto error; rc = cond_dup_av_list(&newn->false_list, &orign->false_list, - &newp->te_cond_avtab); + &newp->te_cond_avtab); if (rc) goto error; } @@ -683,7 +680,8 @@ static int cond_bools_destroy(void *key, void *datum, void *args) return 0; } -static int cond_bools_copy(struct hashtab_node *new, struct hashtab_node *orig, void *args) +static int cond_bools_copy(struct hashtab_node *new, struct hashtab_node *orig, + void *args) { struct cond_bool_datum *datum; @@ -709,7 +707,7 @@ static int cond_bools_index(void *key, void *datum, void *args) } static int duplicate_policydb_bools(struct policydb *newdb, - struct policydb *orig) + struct policydb *orig) { struct cond_bool_datum **cond_bool_array; int rc; @@ -721,7 +719,7 @@ static int duplicate_policydb_bools(struct policydb *newdb, return -ENOMEM; rc = hashtab_duplicate(&newdb->p_bools.table, &orig->p_bools.table, - cond_bools_copy, cond_bools_destroy, NULL); + cond_bools_copy, cond_bools_destroy, NULL); if (rc) { kfree(cond_bool_array); return -ENOMEM; diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 5a7b51278d..b972ce40db 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* Authors: Karl MacMillan * Frank Mayer - * - * Copyright (C) 2003 - 2004 Tresys Technology, LLC + * Copyright (C) 2003 - 2004 Tresys Technology, LLC */ #ifndef _CONDITIONAL_H_ @@ -20,14 +19,14 @@ * in reverse polish notation. */ struct cond_expr_node { -#define COND_BOOL 1 /* plain bool */ -#define COND_NOT 2 /* !bool */ -#define COND_OR 3 /* bool || bool */ -#define COND_AND 4 /* bool && bool */ -#define COND_XOR 5 /* bool ^ bool */ -#define COND_EQ 6 /* bool == bool */ -#define COND_NEQ 7 /* bool != bool */ -#define COND_LAST COND_NEQ +#define COND_BOOL 1 /* plain bool */ +#define COND_NOT 2 /* !bool */ +#define COND_OR 3 /* bool || bool */ +#define COND_AND 4 /* bool && bool */ +#define COND_XOR 5 /* bool ^ bool */ +#define COND_EQ 6 /* bool == bool */ +#define COND_NEQ 7 /* bool != bool */ +#define COND_LAST COND_NEQ u32 expr_type; u32 boolean; }; @@ -75,9 +74,9 @@ int cond_write_bool(void *key, void *datum, void *ptr); int cond_write_list(struct policydb *p, void *fp); void cond_compute_av(struct avtab *ctab, struct avtab_key *key, - struct av_decision *avd, struct extended_perms *xperms); + struct av_decision *avd, struct extended_perms *xperms); void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, - struct extended_perms_decision *xpermd); + struct extended_perms_decision *xpermd); void evaluate_cond_nodes(struct policydb *p); void cond_policydb_destroy_dup(struct policydb *p); int cond_policydb_dup(struct policydb *new, struct policydb *orig); diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h index f76eb3128a..203033cfad 100644 --- a/security/selinux/ss/constraint.h +++ b/security/selinux/ss/constraint.h @@ -13,6 +13,7 @@ * * Author : Stephen Smalley, */ + #ifndef _SS_CONSTRAINT_H_ #define _SS_CONSTRAINT_H_ @@ -21,43 +22,43 @@ #define CEXPR_MAXDEPTH 5 struct constraint_expr { -#define CEXPR_NOT 1 /* not expr */ -#define CEXPR_AND 2 /* expr and expr */ -#define CEXPR_OR 3 /* expr or expr */ -#define CEXPR_ATTR 4 /* attr op attr */ -#define CEXPR_NAMES 5 /* attr op names */ - u32 expr_type; /* expression type */ - -#define CEXPR_USER 1 /* user */ -#define CEXPR_ROLE 2 /* role */ -#define CEXPR_TYPE 4 /* type */ -#define CEXPR_TARGET 8 /* target if set, source otherwise */ -#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */ -#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */ -#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */ -#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */ -#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */ -#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */ -#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */ - u32 attr; /* attribute */ - -#define CEXPR_EQ 1 /* == or eq */ -#define CEXPR_NEQ 2 /* != */ -#define CEXPR_DOM 3 /* dom */ -#define CEXPR_DOMBY 4 /* domby */ -#define CEXPR_INCOMP 5 /* incomp */ - u32 op; /* operator */ - - struct ebitmap names; /* names */ +#define CEXPR_NOT 1 /* not expr */ +#define CEXPR_AND 2 /* expr and expr */ +#define CEXPR_OR 3 /* expr or expr */ +#define CEXPR_ATTR 4 /* attr op attr */ +#define CEXPR_NAMES 5 /* attr op names */ + u32 expr_type; /* expression type */ + +#define CEXPR_USER 1 /* user */ +#define CEXPR_ROLE 2 /* role */ +#define CEXPR_TYPE 4 /* type */ +#define CEXPR_TARGET 8 /* target if set, source otherwise */ +#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */ +#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */ +#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */ +#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */ +#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */ +#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */ +#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */ + u32 attr; /* attribute */ + +#define CEXPR_EQ 1 /* == or eq */ +#define CEXPR_NEQ 2 /* != */ +#define CEXPR_DOM 3 /* dom */ +#define CEXPR_DOMBY 4 /* domby */ +#define CEXPR_INCOMP 5 /* incomp */ + u32 op; /* operator */ + + struct ebitmap names; /* names */ struct type_set *type_names; - struct constraint_expr *next; /* next expression */ + struct constraint_expr *next; /* next expression */ }; struct constraint_node { - u32 permissions; /* constrained permissions */ - struct constraint_expr *expr; /* constraint on permissions */ - struct constraint_node *next; /* next constraint */ + u32 permissions; /* constrained permissions */ + struct constraint_expr *expr; /* constraint on permissions */ + struct constraint_node *next; /* next constraint */ }; -#endif /* _SS_CONSTRAINT_H_ */ +#endif /* _SS_CONSTRAINT_H_ */ diff --git a/security/selinux/ss/context.c b/security/selinux/ss/context.c index 38bc0aa524..e39990f494 100644 --- a/security/selinux/ss/context.c +++ b/security/selinux/ss/context.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Implementations of the security context functions. * diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 1f59468c07..7ccab2e696 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h @@ -13,6 +13,7 @@ * * Author : Stephen Smalley, */ + #ifndef _SS_CONTEXT_H_ #define _SS_CONTEXT_H_ @@ -28,9 +29,9 @@ struct context { u32 user; u32 role; u32 type; - u32 len; /* length of string in bytes */ + u32 len; /* length of string in bytes */ struct mls_range range; - char *str; /* string representation if context cannot be mapped. */ + char *str; /* string representation if context cannot be mapped. */ }; static inline void mls_context_init(struct context *c) @@ -38,7 +39,8 @@ static inline void mls_context_init(struct context *c) memset(&c->range, 0, sizeof(c->range)); } -static inline int mls_context_cpy(struct context *dst, const struct context *src) +static inline int mls_context_cpy(struct context *dst, + const struct context *src) { int rc; @@ -58,7 +60,8 @@ out: /* * Sets both levels in the MLS range of 'dst' to the low level of 'src'. */ -static inline int mls_context_cpy_low(struct context *dst, const struct context *src) +static inline int mls_context_cpy_low(struct context *dst, + const struct context *src) { int rc; @@ -78,7 +81,8 @@ out: /* * Sets both levels in the MLS range of 'dst' to the high level of 'src'. */ -static inline int mls_context_cpy_high(struct context *dst, const struct context *src) +static inline int mls_context_cpy_high(struct context *dst, + const struct context *src) { int rc; @@ -95,9 +99,9 @@ out: return rc; } - static inline int mls_context_glblub(struct context *dst, - const struct context *c1, const struct context *c2) + const struct context *c1, + const struct context *c2) { struct mls_range *dr = &dst->range; const struct mls_range *r1 = &c1->range, *r2 = &c2->range; @@ -114,13 +118,13 @@ static inline int mls_context_glblub(struct context *dst, /* Take the least of the high */ dr->level[1].sens = min(r1->level[1].sens, r2->level[1].sens); - rc = ebitmap_and(&dr->level[0].cat, - &r1->level[0].cat, &r2->level[0].cat); + rc = ebitmap_and(&dr->level[0].cat, &r1->level[0].cat, + &r2->level[0].cat); if (rc) goto out; - rc = ebitmap_and(&dr->level[1].cat, - &r1->level[1].cat, &r2->level[1].cat); + rc = ebitmap_and(&dr->level[1].cat, &r1->level[1].cat, + &r2->level[1].cat); if (rc) goto out; @@ -128,7 +132,8 @@ out: return rc; } -static inline int mls_context_cmp(const struct context *c1, const struct context *c2) +static inline int mls_context_cmp(const struct context *c1, + const struct context *c2) { return ((c1->range.level[0].sens == c2->range.level[0].sens) && ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && @@ -183,19 +188,17 @@ static inline void context_destroy(struct context *c) mls_context_destroy(c); } -static inline int context_cmp(const struct context *c1, const struct context *c2) +static inline int context_cmp(const struct context *c1, + const struct context *c2) { if (c1->len && c2->len) return (c1->len == c2->len && !strcmp(c1->str, c2->str)); if (c1->len || c2->len) return 0; - return ((c1->user == c2->user) && - (c1->role == c2->role) && - (c1->type == c2->type) && - mls_context_cmp(c1, c2)); + return ((c1->user == c2->user) && (c1->role == c2->role) && + (c1->type == c2->type) && mls_context_cmp(c1, c2)); } u32 context_compute_hash(const struct context *c); -#endif /* _SS_CONTEXT_H_ */ - +#endif /* _SS_CONTEXT_H_ */ diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 77875ad355..67c1a73cd5 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Implementation of the extensible bitmap type. * @@ -6,14 +6,11 @@ */ /* * Updated: Hewlett-Packard + * Added support to import/export the NetLabel category bitmap + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * - * Added support to import/export the NetLabel category bitmap - * - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - */ -/* * Updated: KaiGai Kohei - * Applied standard bit operations to improve bitmap scanning. + * Applied standard bit operations to improve bitmap scanning. */ #include @@ -24,7 +21,7 @@ #include "ebitmap.h" #include "policydb.h" -#define BITS_PER_U64 (sizeof(u64) * 8) +#define BITS_PER_U64 (sizeof(u64) * 8) static struct kmem_cache *ebitmap_node_cachep __ro_after_init; @@ -37,8 +34,7 @@ int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2) n1 = e1->node; n2 = e2->node; - while (n1 && n2 && - (n1->startbit == n2->startbit) && + while (n1 && n2 && (n1->startbit == n2->startbit) && !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) { n1 = n1->next; n2 = n2->next; @@ -79,14 +75,16 @@ int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src) return 0; } -int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebitmap *e2) +int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, + const struct ebitmap *e2) { struct ebitmap_node *n; int bit, rc; ebitmap_init(dst); - ebitmap_for_each_positive_bit(e1, n, bit) { + ebitmap_for_each_positive_bit(e1, n, bit) + { if (ebitmap_get_bit(e2, bit)) { rc = ebitmap_set_bit(dst, bit, 1); if (rc < 0) @@ -96,7 +94,6 @@ int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebit return 0; } - #ifdef CONFIG_NETLABEL /** * ebitmap_netlbl_export - Export an ebitmap into a NetLabel category bitmap @@ -131,10 +128,8 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) { e_map = e_iter->maps[iter]; if (e_map != 0) { - rc = netlbl_catmap_setlong(catmap, - offset, - e_map, - GFP_ATOMIC); + rc = netlbl_catmap_setlong(catmap, offset, + e_map, GFP_ATOMIC); if (rc != 0) goto netlbl_export_failure; } @@ -185,7 +180,8 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, if (e_iter == NULL || offset >= e_iter->startbit + EBITMAP_SIZE) { e_prev = e_iter; - e_iter = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC); + e_iter = kmem_cache_zalloc(ebitmap_node_cachep, + GFP_ATOMIC); if (e_iter == NULL) goto netlbl_import_failure; e_iter->startbit = offset - (offset % EBITMAP_SIZE); @@ -218,7 +214,8 @@ netlbl_import_failure: * if last_e2bit is non-zero, the highest set bit in e2 cannot exceed * last_e2bit. */ -int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 last_e2bit) +int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, + u32 last_e2bit) { const struct ebitmap_node *n1, *n2; int i; @@ -234,8 +231,8 @@ int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 las n1 = n1->next; continue; } - for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; ) - i--; /* Skip trailing NULL map entries */ + for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i];) + i--; /* Skip trailing NULL map entries */ if (last_e2bit && (i >= 0)) { u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE + __fls(n2->maps[i]); @@ -302,8 +299,8 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) * within the bitmap */ if (prev) - e->highbit = prev->startbit - + EBITMAP_SIZE; + e->highbit = prev->startbit + + EBITMAP_SIZE; else e->highbit = 0; } @@ -424,7 +421,8 @@ int ebitmap_read(struct ebitmap *e, void *fp) if (!n || startbit >= n->startbit + EBITMAP_SIZE) { struct ebitmap_node *tmp; - tmp = kmem_cache_zalloc(ebitmap_node_cachep, GFP_KERNEL); + tmp = kmem_cache_zalloc(ebitmap_node_cachep, + GFP_KERNEL); if (!tmp) { pr_err("SELinux: ebitmap: out of memory\n"); rc = -ENOMEM; @@ -481,7 +479,8 @@ int ebitmap_write(const struct ebitmap *e, void *fp) count = 0; last_bit = 0; last_startbit = -1; - ebitmap_for_each_positive_bit(e, n, bit) { + ebitmap_for_each_positive_bit(e, n, bit) + { if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { count++; last_startbit = rounddown(bit, BITS_PER_U64); @@ -497,7 +496,8 @@ int ebitmap_write(const struct ebitmap *e, void *fp) map = 0; last_startbit = INT_MIN; - ebitmap_for_each_positive_bit(e, n, bit) { + ebitmap_for_each_positive_bit(e, n, bit) + { if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { __le64 buf64[1]; @@ -559,6 +559,6 @@ u32 ebitmap_hash(const struct ebitmap *e, u32 hash) void __init ebitmap_cache_init(void) { ebitmap_node_cachep = kmem_cache_create("ebitmap_node", - sizeof(struct ebitmap_node), - 0, SLAB_PANIC, NULL); + sizeof(struct ebitmap_node), 0, + SLAB_PANIC, NULL); } diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index e3c807cfad..02798b35ee 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h @@ -12,23 +12,25 @@ * * Author : Stephen Smalley, */ + #ifndef _SS_EBITMAP_H_ #define _SS_EBITMAP_H_ #include #ifdef CONFIG_64BIT -#define EBITMAP_NODE_SIZE 64 +#define EBITMAP_NODE_SIZE 64 #else -#define EBITMAP_NODE_SIZE 32 +#define EBITMAP_NODE_SIZE 32 #endif -#define EBITMAP_UNIT_NUMS ((EBITMAP_NODE_SIZE-sizeof(void *)-sizeof(u32))\ - / sizeof(unsigned long)) -#define EBITMAP_UNIT_SIZE BITS_PER_LONG -#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) -#define EBITMAP_BIT 1ULL -#define EBITMAP_SHIFT_UNIT_SIZE(x) \ +#define EBITMAP_UNIT_NUMS \ + ((EBITMAP_NODE_SIZE - sizeof(void *) - sizeof(u32)) / \ + sizeof(unsigned long)) +#define EBITMAP_UNIT_SIZE BITS_PER_LONG +#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) +#define EBITMAP_BIT 1ULL +#define EBITMAP_SHIFT_UNIT_SIZE(x) \ (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2) struct ebitmap_node { @@ -38,8 +40,8 @@ struct ebitmap_node { }; struct ebitmap { - struct ebitmap_node *node; /* first node in the bitmap */ - u32 highbit; /* highest position in the total bitmap */ + struct ebitmap_node *node; /* first node in the bitmap */ + u32 highbit; /* highest position in the total bitmap */ }; #define ebitmap_length(e) ((e)->highbit) @@ -80,9 +82,9 @@ static inline unsigned int ebitmap_next_positive(const struct ebitmap *e, return ebitmap_length(e); } -#define EBITMAP_NODE_INDEX(node, bit) \ +#define EBITMAP_NODE_INDEX(node, bit) \ (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE) -#define EBITMAP_NODE_OFFSET(node, bit) \ +#define EBITMAP_NODE_OFFSET(node, bit) \ (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE) static inline int ebitmap_node_get_bit(const struct ebitmap_node *n, @@ -117,15 +119,17 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, n->maps[index] &= ~(EBITMAP_BIT << ofs); } -#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)) \ +#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)) int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2); int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src); -int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebitmap *e2); -int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 last_e2bit); +int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, + const struct ebitmap *e2); +int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, + u32 last_e2bit); int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit); int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); void ebitmap_destroy(struct ebitmap *e); @@ -151,4 +155,4 @@ static inline int ebitmap_netlbl_import(struct ebitmap *ebmap, } #endif -#endif /* _SS_EBITMAP_H_ */ +#endif /* _SS_EBITMAP_H_ */ diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index c05d8346a9..754bedbde1 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -4,6 +4,7 @@ * * Author : Stephen Smalley, */ + #include #include #include @@ -47,8 +48,8 @@ int hashtab_init(struct hashtab *h, u32 nel_hint) return 0; } -int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst, - void *key, void *datum) +int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst, void *key, + void *datum) { struct hashtab_node *newnode; @@ -83,8 +84,7 @@ void hashtab_destroy(struct hashtab *h) h->htable = NULL; } -int hashtab_map(struct hashtab *h, - int (*apply)(void *k, void *d, void *args), +int hashtab_map(struct hashtab *h, int (*apply)(void *k, void *d, void *args), void *args) { u32 i; @@ -137,10 +137,9 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info) #endif /* CONFIG_SECURITY_SELINUX_DEBUG */ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig, - int (*copy)(struct hashtab_node *new, - struct hashtab_node *orig, void *args), - int (*destroy)(void *k, void *d, void *args), - void *args) + int (*copy)(struct hashtab_node *new, + struct hashtab_node *orig, void *args), + int (*destroy)(void *k, void *d, void *args), void *args) { struct hashtab_node *cur, *tmp, *tail; u32 i; @@ -178,7 +177,7 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig, return 0; - error: +error: for (i = 0; i < new->size; i++) { for (cur = new->htable[i]; cur; cur = tmp) { tmp = cur->next; @@ -193,7 +192,7 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig, void __init hashtab_cache_init(void) { - hashtab_node_cachep = kmem_cache_create("hashtab_node", - sizeof(struct hashtab_node), - 0, SLAB_PANIC, NULL); + hashtab_node_cachep = kmem_cache_create("hashtab_node", + sizeof(struct hashtab_node), 0, + SLAB_PANIC, NULL); } diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h index 09b0a37449..5f74dcc136 100644 --- a/security/selinux/ss/hashtab.h +++ b/security/selinux/ss/hashtab.h @@ -8,6 +8,7 @@ * * Author : Stephen Smalley, */ + #ifndef _SS_HASHTAB_H_ #define _SS_HASHTAB_H_ @@ -15,12 +16,11 @@ #include #include -#define HASHTAB_MAX_NODES U32_MAX +#define HASHTAB_MAX_NODES U32_MAX struct hashtab_key_params { - u32 (*hash)(const void *key); /* hash function */ - int (*cmp)(const void *key1, const void *key2); - /* key comparison function */ + u32 (*hash)(const void *key); /* hash func */ + int (*cmp)(const void *key1, const void *key2); /* comparison func */ }; struct hashtab_node { @@ -30,9 +30,9 @@ struct hashtab_node { }; struct hashtab { - struct hashtab_node **htable; /* hash table */ - u32 size; /* number of slots in hash table */ - u32 nel; /* number of elements in hash table */ + struct hashtab_node **htable; /* hash table */ + u32 size; /* number of slots in hash table */ + u32 nel; /* number of elements in hash table */ }; struct hashtab_info { @@ -48,8 +48,8 @@ struct hashtab_info { */ int hashtab_init(struct hashtab *h, u32 nel_hint); -int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst, - void *key, void *datum); +int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst, void *key, + void *datum); /* * Inserts the specified (key, datum) pair into the specified hash table. @@ -84,8 +84,8 @@ static inline int hashtab_insert(struct hashtab *h, void *key, void *datum, cur = cur->next; } - return __hashtab_insert(h, prev ? &prev->next : &h->htable[hvalue], - key, datum); + return __hashtab_insert(h, prev ? &prev->next : &h->htable[hvalue], key, + datum); } /* @@ -133,15 +133,13 @@ void hashtab_destroy(struct hashtab *h); * iterating through the hash table and will propagate the error * return to its caller. */ -int hashtab_map(struct hashtab *h, - int (*apply)(void *k, void *d, void *args), +int hashtab_map(struct hashtab *h, int (*apply)(void *k, void *d, void *args), void *args); int hashtab_duplicate(struct hashtab *new, struct hashtab *orig, - int (*copy)(struct hashtab_node *new, - struct hashtab_node *orig, void *args), - int (*destroy)(void *k, void *d, void *args), - void *args); + int (*copy)(struct hashtab_node *new, + struct hashtab_node *orig, void *args), + int (*destroy)(void *k, void *d, void *args), void *args); #ifdef CONFIG_SECURITY_SELINUX_DEBUG /* Fill info with some hash table statistics */ @@ -149,7 +147,8 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info); #else static inline void hashtab_stat(struct hashtab *h, struct hashtab_info *info) { + return; } #endif -#endif /* _SS_HASHTAB_H */ +#endif /* _SS_HASHTAB_H */ diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index cd38f5913b..989c809d31 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -4,19 +4,15 @@ * * Author : Stephen Smalley, */ + /* * Updated: Trusted Computer Solutions, Inc. + * Support for enhanced MLS infrastructure. + * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. * - * Support for enhanced MLS infrastructure. - * - * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. - */ -/* * Updated: Hewlett-Packard - * - * Added support to import/export the MLS label from NetLabel - * - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 + * Added support to import/export the MLS label from NetLabel + * Copyright (C) Hewlett-Packard Development Company, L.P., 2006 */ #include @@ -52,7 +48,8 @@ int mls_compute_context_len(struct policydb *p, struct context *context) head = -2; prev = -2; e = &context->range.level[l].cat; - ebitmap_for_each_positive_bit(e, node, i) { + ebitmap_for_each_positive_bit(e, node, i) + { if (i - prev > 1) { /* one or more negative bits are skipped */ if (head != prev) { @@ -86,8 +83,7 @@ int mls_compute_context_len(struct policydb *p, struct context *context) * the MLS fields of `context' into the string `*scontext'. * Update `*scontext' to point to the end of the MLS fields. */ -void mls_sid_to_context(struct policydb *p, - struct context *context, +void mls_sid_to_context(struct policydb *p, struct context *context, char **scontext) { char *scontextp, *nm; @@ -112,7 +108,8 @@ void mls_sid_to_context(struct policydb *p, head = -2; prev = -2; e = &context->range.level[l].cat; - ebitmap_for_each_positive_bit(e, node, i) { + ebitmap_for_each_positive_bit(e, node, i) + { if (i - prev > 1) { /* one or more negative bits are skipped */ if (prev != head) { @@ -230,12 +227,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c) * Policy read-lock must be held for sidtab lookup. * */ -int mls_context_to_sid(struct policydb *pol, - char oldc, - char *scontext, - struct context *context, - struct sidtab *s, - u32 def_sid) +int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext, + struct context *context, struct sidtab *s, u32 def_sid) { char *sensitivity, *cur_cat, *next_cat, *rngptr; struct level_datum *levdatum; @@ -333,7 +326,8 @@ int mls_context_to_sid(struct policydb *pol, return -EINVAL; for (i = catdatum->value; i < rngdatum->value; i++) { - rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); + rc = ebitmap_set_bit( + &context->range.level[l].cat, i, 1); if (rc) return rc; } @@ -371,8 +365,8 @@ int mls_from_string(struct policydb *p, char *str, struct context *context, if (!tmpstr) { rc = -ENOMEM; } else { - rc = mls_context_to_sid(p, ':', tmpstr, context, - NULL, SECSID_NULL); + rc = mls_context_to_sid(p, ':', tmpstr, context, NULL, + SECSID_NULL); kfree(tmpstr); } @@ -382,8 +376,7 @@ int mls_from_string(struct policydb *p, char *str, struct context *context, /* * Copies the MLS range `range' into `context'. */ -int mls_range_set(struct context *context, - struct mls_range *range) +int mls_range_set(struct context *context, struct mls_range *range) { int l, rc = 0; @@ -399,9 +392,8 @@ int mls_range_set(struct context *context, return rc; } -int mls_setup_user_range(struct policydb *p, - struct context *fromcon, struct user_datum *user, - struct context *usercon) +int mls_setup_user_range(struct policydb *p, struct context *fromcon, + struct user_datum *user, struct context *usercon) { if (p->mls_enabled) { struct mls_level *fromcon_sen = &(fromcon->range.level[0]); @@ -444,10 +436,8 @@ int mls_setup_user_range(struct policydb *p, * policy `oldp' to the values specified in the policy `newp', * storing the resulting context in `newc'. */ -int mls_convert_context(struct policydb *oldp, - struct policydb *newp, - struct context *oldc, - struct context *newc) +int mls_convert_context(struct policydb *oldp, struct policydb *newp, + struct context *oldc, struct context *newc) { struct level_datum *levdatum; struct cat_datum *catdatum; @@ -468,8 +458,9 @@ int mls_convert_context(struct policydb *oldp, return -EINVAL; newc->range.level[l].sens = levdatum->level->sens; - ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, - node, i) { + ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node, + i) + { int rc; catdatum = symtab_search(&newp->p_cats, @@ -486,13 +477,9 @@ int mls_convert_context(struct policydb *oldp, return 0; } -int mls_compute_sid(struct policydb *p, - struct context *scontext, - struct context *tcontext, - u16 tclass, - u32 specified, - struct context *newcontext, - bool sock) +int mls_compute_sid(struct policydb *p, struct context *scontext, + struct context *tcontext, u16 tclass, u32 specified, + struct context *newcontext, bool sock) { struct range_trans rtr; struct mls_range *r; @@ -532,8 +519,8 @@ int mls_compute_sid(struct policydb *p, case DEFAULT_TARGET_LOW_HIGH: return mls_context_cpy(newcontext, tcontext); case DEFAULT_GLBLUB: - return mls_context_glblub(newcontext, - scontext, tcontext); + return mls_context_glblub(newcontext, scontext, + tcontext); } fallthrough; @@ -563,8 +550,7 @@ int mls_compute_sid(struct policydb *p, * NetLabel MLS sensitivity level field. * */ -void mls_export_netlbl_lvl(struct policydb *p, - struct context *context, +void mls_export_netlbl_lvl(struct policydb *p, struct context *context, struct netlbl_lsm_secattr *secattr) { if (!p->mls_enabled) @@ -585,8 +571,7 @@ void mls_export_netlbl_lvl(struct policydb *p, * NetLabel MLS sensitivity level into the context. * */ -void mls_import_netlbl_lvl(struct policydb *p, - struct context *context, +void mls_import_netlbl_lvl(struct policydb *p, struct context *context, struct netlbl_lsm_secattr *secattr) { if (!p->mls_enabled) @@ -607,8 +592,7 @@ void mls_import_netlbl_lvl(struct policydb *p, * MLS category field. Returns zero on success, negative values on failure. * */ -int mls_export_netlbl_cat(struct policydb *p, - struct context *context, +int mls_export_netlbl_cat(struct policydb *p, struct context *context, struct netlbl_lsm_secattr *secattr) { int rc; @@ -637,8 +621,7 @@ int mls_export_netlbl_cat(struct policydb *p, * negative values on failure. * */ -int mls_import_netlbl_cat(struct policydb *p, - struct context *context, +int mls_import_netlbl_cat(struct policydb *p, struct context *context, struct netlbl_lsm_secattr *secattr) { int rc; diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 107681dd18..0798063675 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h @@ -4,19 +4,15 @@ * * Author : Stephen Smalley, */ + /* * Updated: Trusted Computer Solutions, Inc. + * Support for enhanced MLS infrastructure. + * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. * - * Support for enhanced MLS infrastructure. - * - * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. - */ -/* * Updated: Hewlett-Packard - * - * Added support to import/export the MLS label from NetLabel - * - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 + * Added support to import/export the MLS label from NetLabel + * Copyright (X) Hewlett-Packard Development Company, L.P., 2006 */ #ifndef _SS_MLS_H_ @@ -35,47 +31,32 @@ int mls_context_isvalid(struct policydb *p, struct context *c); int mls_range_isvalid(struct policydb *p, struct mls_range *r); int mls_level_isvalid(struct policydb *p, struct mls_level *l); -int mls_context_to_sid(struct policydb *p, - char oldc, - char *scontext, - struct context *context, - struct sidtab *s, - u32 def_sid); +int mls_context_to_sid(struct policydb *p, char oldc, char *scontext, + struct context *context, struct sidtab *s, u32 def_sid); int mls_from_string(struct policydb *p, char *str, struct context *context, gfp_t gfp_mask); int mls_range_set(struct context *context, struct mls_range *range); -int mls_convert_context(struct policydb *oldp, - struct policydb *newp, - struct context *oldc, - struct context *newc); +int mls_convert_context(struct policydb *oldp, struct policydb *newp, + struct context *oldc, struct context *newc); -int mls_compute_sid(struct policydb *p, - struct context *scontext, - struct context *tcontext, - u16 tclass, - u32 specified, - struct context *newcontext, - bool sock); +int mls_compute_sid(struct policydb *p, struct context *scontext, + struct context *tcontext, u16 tclass, u32 specified, + struct context *newcontext, bool sock); -int mls_setup_user_range(struct policydb *p, - struct context *fromcon, struct user_datum *user, - struct context *usercon); +int mls_setup_user_range(struct policydb *p, struct context *fromcon, + struct user_datum *user, struct context *usercon); #ifdef CONFIG_NETLABEL -void mls_export_netlbl_lvl(struct policydb *p, - struct context *context, +void mls_export_netlbl_lvl(struct policydb *p, struct context *context, struct netlbl_lsm_secattr *secattr); -void mls_import_netlbl_lvl(struct policydb *p, - struct context *context, +void mls_import_netlbl_lvl(struct policydb *p, struct context *context, struct netlbl_lsm_secattr *secattr); -int mls_export_netlbl_cat(struct policydb *p, - struct context *context, +int mls_export_netlbl_cat(struct policydb *p, struct context *context, struct netlbl_lsm_secattr *secattr); -int mls_import_netlbl_cat(struct policydb *p, - struct context *context, +int mls_import_netlbl_cat(struct policydb *p, struct context *context, struct netlbl_lsm_secattr *secattr); #else static inline void mls_export_netlbl_lvl(struct policydb *p, @@ -112,5 +93,4 @@ static inline u32 mls_range_hash(const struct mls_range *r, u32 hash) return hash; } -#endif /* _SS_MLS_H */ - +#endif /* _SS_MLS_H */ diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index f492cf1488..7ef6e8cb0c 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h @@ -4,12 +4,11 @@ * * Author : Stephen Smalley, */ + /* * Updated: Trusted Computer Solutions, Inc. - * - * Support for enhanced MLS infrastructure. - * - * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + * Support for enhanced MLS infrastructure. + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. */ #ifndef _SS_MLS_TYPES_H_ @@ -19,34 +18,35 @@ #include "ebitmap.h" struct mls_level { - u32 sens; /* sensitivity */ - struct ebitmap cat; /* category set */ + u32 sens; /* sensitivity */ + struct ebitmap cat; /* category set */ }; struct mls_range { struct mls_level level[2]; /* low == level[0], high == level[1] */ }; -static inline int mls_level_eq(const struct mls_level *l1, const struct mls_level *l2) +static inline int mls_level_eq(const struct mls_level *l1, + const struct mls_level *l2) { - return ((l1->sens == l2->sens) && - ebitmap_cmp(&l1->cat, &l2->cat)); + return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat)); } -static inline int mls_level_dom(const struct mls_level *l1, const struct mls_level *l2) +static inline int mls_level_dom(const struct mls_level *l1, + const struct mls_level *l2) { return ((l1->sens >= l2->sens) && ebitmap_contains(&l1->cat, &l2->cat, 0)); } #define mls_level_incomp(l1, l2) \ -(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1))) + (!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1))) #define mls_level_between(l1, l2, l3) \ -(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1))) + (mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1))) -#define mls_range_contains(r1, r2) \ -(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \ - mls_level_dom(&(r1).level[1], &(r2).level[1])) +#define mls_range_contains(r1, r2) \ + (mls_level_dom(&(r2).level[0], &(r1).level[0]) && \ + mls_level_dom(&(r1).level[1], &(r2).level[1])) -#endif /* _SS_MLS_TYPES_H_ */ +#endif /* _SS_MLS_TYPES_H_ */ diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 3b19ad28c9..3d22d5baa8 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -7,25 +7,21 @@ /* * Updated: Trusted Computer Solutions, Inc. + * Support for enhanced MLS infrastructure. + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * - * Support for enhanced MLS infrastructure. - * - * Updated: Frank Mayer and Karl MacMillan - * - * Added conditional policy language extensions + * Updated: Frank Mayer and + * Karl MacMillan + * Added conditional policy language extensions + * Copyright (C) 2003-2004 Tresys Technology, LLC * * Updated: Hewlett-Packard - * - * Added support for the policy capability bitmap + * Added support for the policy capability bitmap + * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. * * Update: Mellanox Techonologies - * - * Added Infiniband support - * - * Copyright (C) 2016 Mellanox Techonologies - * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. - * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. - * Copyright (C) 2003 - 2004 Tresys Technology, LLC + * Added Infiniband support + * Copyright (C) 2016 Mellanox Techonologies */ #include @@ -42,6 +38,7 @@ #include "services.h" #ifdef CONFIG_SECURITY_SELINUX_DEBUG +/* clang-format off */ static const char *const symtab_name[SYM_NUM] = { "common prefixes", "classes", @@ -52,6 +49,7 @@ static const char *const symtab_name[SYM_NUM] = { "levels", "categories", }; +/* clang-format off */ #endif struct policydb_compat_info { @@ -63,103 +61,104 @@ struct policydb_compat_info { /* These need to be updated if SYM_NUM or OCON_NUM changes */ static const struct policydb_compat_info policydb_compat[] = { { - .version = POLICYDB_VERSION_BASE, - .sym_num = SYM_NUM - 3, - .ocon_num = OCON_NUM - 3, + .version = POLICYDB_VERSION_BASE, + .sym_num = SYM_NUM - 3, + .ocon_num = OCON_NUM - 3, }, { - .version = POLICYDB_VERSION_BOOL, - .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM - 3, + .version = POLICYDB_VERSION_BOOL, + .sym_num = SYM_NUM - 2, + .ocon_num = OCON_NUM - 3, }, { - .version = POLICYDB_VERSION_IPV6, - .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_IPV6, + .sym_num = SYM_NUM - 2, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_NLCLASS, - .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_NLCLASS, + .sym_num = SYM_NUM - 2, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_MLS, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_MLS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_AVTAB, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_AVTAB, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_RANGETRANS, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_RANGETRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_POLCAP, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_POLCAP, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_PERMISSIVE, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_PERMISSIVE, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_BOUNDARY, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_BOUNDARY, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_FILENAME_TRANS, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_FILENAME_TRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_ROLETRANS, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_ROLETRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_DEFAULT_TYPE, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_DEFAULT_TYPE, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_CONSTRAINT_NAMES, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_CONSTRAINT_NAMES, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_XPERMS_IOCTL, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM - 2, + .version = POLICYDB_VERSION_XPERMS_IOCTL, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM - 2, }, { - .version = POLICYDB_VERSION_INFINIBAND, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .version = POLICYDB_VERSION_INFINIBAND, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, }, { - .version = POLICYDB_VERSION_GLBLUB, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .version = POLICYDB_VERSION_GLBLUB, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, }, { - .version = POLICYDB_VERSION_COMP_FTRANS, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .version = POLICYDB_VERSION_COMP_FTRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, }, }; -static const struct policydb_compat_info *policydb_lookup_compat(unsigned int version) +static const struct policydb_compat_info * +policydb_lookup_compat(unsigned int version) { unsigned int i; @@ -312,7 +311,8 @@ static int cat_destroy(void *key, void *datum, void *p) return 0; } -static int (*const destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = { +/* clang-format off */ +static int (*const destroy_f[SYM_NUM])(void *key, void *datum, void *datap) = { common_destroy, cls_destroy, role_destroy, @@ -322,6 +322,7 @@ static int (*const destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = { sens_destroy, cat_destroy, }; +/* clang-format on */ static int filenametr_destroy(void *key, void *datum, void *p) { @@ -366,8 +367,8 @@ static void ocontext_destroy(struct ocontext *c, unsigned int i) context_destroy(&c->context[0]); context_destroy(&c->context[1]); - if (i == OCON_ISID || i == OCON_FS || - i == OCON_NETIF || i == OCON_FSUSE) + if (i == OCON_ISID || i == OCON_FS || i == OCON_NETIF || + i == OCON_FSUSE) kfree(c->u.name); kfree(c); } @@ -429,7 +430,6 @@ static int filenametr_cmp(const void *k1, const void *k2) return v; return strcmp(ft1->name, ft2->name); - } static const struct hashtab_key_params filenametr_key_params = { @@ -437,8 +437,8 @@ static const struct hashtab_key_params filenametr_key_params = { .cmp = filenametr_cmp, }; -struct filename_trans_datum *policydb_filenametr_search( - struct policydb *p, struct filename_trans_key *key) +struct filename_trans_datum * +policydb_filenametr_search(struct policydb *p, struct filename_trans_key *key) { return hashtab_search(&p->filename_trans, key, filenametr_key_params); } @@ -448,7 +448,7 @@ static u32 rangetr_hash(const void *k) const struct range_trans *key = k; return key->source_type + (key->target_type << 3) + - (key->target_class << 5); + (key->target_class << 5); } static int rangetr_cmp(const void *k1, const void *k2) @@ -484,7 +484,8 @@ static u32 role_trans_hash(const void *k) { const struct role_trans_key *key = k; - return jhash_3words(key->role, key->type, (u32)key->tclass << 16 | key->tclass, 0); + return jhash_3words(key->role, key->type, + (u32)key->tclass << 16 | key->tclass, 0); } static int role_trans_cmp(const void *k1, const void *k2) @@ -576,9 +577,8 @@ static int role_index(void *key, void *datum, void *datap) role = datum; p = datap; - if (!role->value - || role->value > p->p_roles.nprim - || role->bounds > p->p_roles.nprim) + if (!role->value || role->value > p->p_roles.nprim || + role->bounds > p->p_roles.nprim) return -EINVAL; p->sym_val_to_name[SYM_ROLES][role->value - 1] = key; @@ -595,9 +595,8 @@ static int type_index(void *key, void *datum, void *datap) p = datap; if (typdatum->primary) { - if (!typdatum->value - || typdatum->value > p->p_types.nprim - || typdatum->bounds > p->p_types.nprim) + if (!typdatum->value || typdatum->value > p->p_types.nprim || + typdatum->bounds > p->p_types.nprim) return -EINVAL; p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key; p->type_val_to_struct[typdatum->value - 1] = typdatum; @@ -613,9 +612,8 @@ static int user_index(void *key, void *datum, void *datap) usrdatum = datum; p = datap; - if (!usrdatum->value - || usrdatum->value > p->p_users.nprim - || usrdatum->bounds > p->p_users.nprim) + if (!usrdatum->value || usrdatum->value > p->p_users.nprim || + usrdatum->bounds > p->p_users.nprim) return -EINVAL; p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key; @@ -660,7 +658,8 @@ static int cat_index(void *key, void *datum, void *datap) return 0; } -static int (*const index_f[SYM_NUM]) (void *key, void *datum, void *datap) = { +/* clang-format off */ +static int (*const index_f[SYM_NUM])(void *key, void *datum, void *datap) = { common_index, class_index, role_index, @@ -670,6 +669,7 @@ static int (*const index_f[SYM_NUM]) (void *key, void *datum, void *datap) = { sens_index, cat_index, }; +/* clang-format on */ #ifdef CONFIG_SECURITY_SELINUX_DEBUG static void hash_eval(struct hashtab *h, const char *hash_name) @@ -677,9 +677,10 @@ static void hash_eval(struct hashtab *h, const char *hash_name) struct hashtab_info info; hashtab_stat(h, &info); - pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n", - hash_name, h->nel, info.slots_used, h->size, - info.max_chain_len, info.chain2_len_sum); + pr_debug( + "SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n", + hash_name, h->nel, info.slots_used, h->size, info.max_chain_len, + info.chain2_len_sum); } static void symtab_hash_eval(struct symtab *s) @@ -710,16 +711,17 @@ static int policydb_index(struct policydb *p) int i, rc; if (p->mls_enabled) - pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n", - p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, - p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim); + pr_debug( + "SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n", + p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, + p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim); else pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); - pr_debug("SELinux: %d classes, %d rules\n", - p->p_classes.nprim, p->te_avtab.nel); + pr_debug("SELinux: %d classes, %d rules\n", p->p_classes.nprim, + p->te_avtab.nel); avtab_hash_eval(&p->te_avtab, "rules"); symtab_hash_eval(p->symtab); @@ -730,21 +732,18 @@ static int policydb_index(struct policydb *p) if (!p->class_val_to_struct) return -ENOMEM; - p->role_val_to_struct = kcalloc(p->p_roles.nprim, - sizeof(*p->role_val_to_struct), - GFP_KERNEL); + p->role_val_to_struct = kcalloc( + p->p_roles.nprim, sizeof(*p->role_val_to_struct), GFP_KERNEL); if (!p->role_val_to_struct) return -ENOMEM; - p->user_val_to_struct = kcalloc(p->p_users.nprim, - sizeof(*p->user_val_to_struct), - GFP_KERNEL); + p->user_val_to_struct = kcalloc( + p->p_users.nprim, sizeof(*p->user_val_to_struct), GFP_KERNEL); if (!p->user_val_to_struct) return -ENOMEM; - p->type_val_to_struct = kvcalloc(p->p_types.nprim, - sizeof(*p->type_val_to_struct), - GFP_KERNEL); + p->type_val_to_struct = kvcalloc( + p->p_types.nprim, sizeof(*p->type_val_to_struct), GFP_KERNEL); if (!p->type_val_to_struct) return -ENOMEM; @@ -754,8 +753,7 @@ static int policydb_index(struct policydb *p) for (i = 0; i < SYM_NUM; i++) { p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim, - sizeof(char *), - GFP_KERNEL); + sizeof(char *), GFP_KERNEL); if (!p->sym_val_to_name[i]) return -ENOMEM; @@ -857,8 +855,7 @@ void policydb_destroy(struct policydb *p) int policydb_load_isids(struct policydb *p, struct sidtab *s) { struct ocontext *head, *c; - bool isid_init_supported = ebitmap_get_bit(&p->policycaps, - POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT); + bool isid_init; int rc; rc = sidtab_init(s); @@ -867,6 +864,9 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s) return rc; } + isid_init = ebitmap_get_bit(&p->policycaps, + POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT); + head = p->ocontexts[OCON_ISID]; for (c = head; c; c = c->next) { u32 sid = c->sid[0]; @@ -886,7 +886,7 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s) * Also ignore SECINITSID_INIT if the policy doesn't declare * support for it */ - if (sid == SECINITSID_INIT && !isid_init_supported) + if (sid == SECINITSID_INIT && !isid_init) continue; rc = sidtab_set_initial(s, sid, &c->context[0]); @@ -905,8 +905,9 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s) * started before policy load would initially get the context * corresponding to SECINITSID_KERNEL. */ - if (sid == SECINITSID_KERNEL && !isid_init_supported) { - rc = sidtab_set_initial(s, SECINITSID_INIT, &c->context[0]); + if (sid == SECINITSID_KERNEL && !isid_init) { + rc = sidtab_set_initial(s, SECINITSID_INIT, + &c->context[0]); if (rc) { pr_err("SELinux: unable to load initial SID %s.\n", name); @@ -1047,8 +1048,7 @@ out: * Read and validate a security context structure * from a policydb binary representation file. */ -static int context_read_and_validate(struct context *c, - struct policydb *p, +static int context_read_and_validate(struct context *c, struct policydb *p, void *fp) { __le32 buf[3]; @@ -1211,10 +1211,8 @@ static int type_set_read(struct type_set *t, void *fp) return 0; } - -static int read_cons_helper(struct policydb *p, - struct constraint_node **nodep, - u32 ncons, int allowxtarget, void *fp) +static int read_cons_helper(struct policydb *p, struct constraint_node **nodep, + u32 ncons, int allowxtarget, void *fp) { struct constraint_node *c, *lc; struct constraint_expr *e, *le; @@ -1284,8 +1282,9 @@ static int read_cons_helper(struct policydb *p, return rc; if (p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) { - e->type_names = kzalloc(sizeof - (*e->type_names), GFP_KERNEL); + e->type_names = + kzalloc(sizeof(*e->type_names), + GFP_KERNEL); if (!e->type_names) return -ENOMEM; type_set_init(e->type_names); @@ -1319,7 +1318,7 @@ static int class_read(struct policydb *p, struct symtab *s, void *fp) if (!cladatum) return -ENOMEM; - rc = next_entry(buf, fp, sizeof(u32)*6); + rc = next_entry(buf, fp, sizeof(u32) * 6); if (rc) goto bad; @@ -1345,8 +1344,8 @@ static int class_read(struct policydb *p, struct symtab *s, void *fp) goto bad; rc = -EINVAL; - cladatum->comdatum = symtab_search(&p->p_commons, - cladatum->comkey); + cladatum->comdatum = + symtab_search(&p->p_commons, cladatum->comkey); if (!cladatum->comdatum) { pr_err("SELinux: unknown common %s\n", cladatum->comkey); @@ -1369,8 +1368,8 @@ static int class_read(struct policydb *p, struct symtab *s, void *fp) if (rc) goto bad; ncons = le32_to_cpu(buf[0]); - rc = read_cons_helper(p, &cladatum->validatetrans, - ncons, 1, fp); + rc = read_cons_helper(p, &cladatum->validatetrans, ncons, 1, + fp); if (rc) goto bad; } @@ -1507,7 +1506,6 @@ bad: return rc; } - /* * Read a MLS level structure from a policydb binary * representation file. @@ -1659,8 +1657,9 @@ bad: return rc; } -static int (*const read_f[SYM_NUM]) (struct policydb *p, - struct symtab *s, void *fp) = { +/* clang-format off */ +static int (*const read_f[SYM_NUM])(struct policydb *p, struct symtab *s, + void *fp) = { common_read, class_read, role_read, @@ -1670,6 +1669,7 @@ static int (*const read_f[SYM_NUM]) (struct policydb *p, sens_read, cat_read, }; +/* clang-format on */ static int user_bounds_sanity_check(void *key, void *datum, void *datap) { @@ -1685,12 +1685,13 @@ static int user_bounds_sanity_check(void *key, void *datum, void *datap) if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { pr_err("SELinux: user %s: " "too deep or looped boundary\n", - (char *) key); + (char *)key); return -EINVAL; } upper = p->user_val_to_struct[upper->bounds - 1]; - ebitmap_for_each_positive_bit(&user->roles, node, bit) { + ebitmap_for_each_positive_bit(&user->roles, node, bit) + { if (ebitmap_get_bit(&upper->roles, bit)) continue; @@ -1721,12 +1722,13 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap) if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { pr_err("SELinux: role %s: " "too deep or looped bounds\n", - (char *) key); + (char *)key); return -EINVAL; } upper = p->role_val_to_struct[upper->bounds - 1]; - ebitmap_for_each_positive_bit(&role->types, node, bit) { + ebitmap_for_each_positive_bit(&role->types, node, bit) + { if (ebitmap_get_bit(&upper->types, bit)) continue; @@ -1754,7 +1756,7 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap) if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { pr_err("SELinux: type %s: " "too deep or looped boundary\n", - (char *) key); + (char *)key); return -EINVAL; } @@ -1764,7 +1766,7 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap) if (upper->attribute) { pr_err("SELinux: type %s: " "bounded by attribute %s\n", - (char *) key, + (char *)key, sym_name(p, SYM_TYPES, upper->value - 1)); return -EINVAL; } @@ -1815,7 +1817,7 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name) if (!tclass || tclass > p->p_classes.nprim) return 0; - cladatum = p->class_val_to_struct[tclass-1]; + cladatum = p->class_val_to_struct[tclass - 1]; comdatum = cladatum->comdatum; if (comdatum) perdatum = symtab_search(&comdatum->permissions, name); @@ -1824,7 +1826,7 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name) if (!perdatum) return 0; - return 1U << (perdatum->value-1); + return 1U << (perdatum->value - 1); } static int range_read(struct policydb *p, void *fp) @@ -2192,12 +2194,12 @@ static int genfs_read(struct policydb *p, void *fp) goto out; newc->v.sclass = le32_to_cpu(buf[0]); - rc = context_read_and_validate(&newc->context[0], p, fp); + rc = context_read_and_validate(&newc->context[0], p, + fp); if (rc) goto out; - for (l = NULL, c = genfs->head; c; - l = c, c = c->next) { + for (l = NULL, c = genfs->head; c; l = c, c = c->next) { rc = -EINVAL; if (!strcmp(newc->u.name, c->u.name) && (!c->v.sclass || !newc->v.sclass || @@ -2231,8 +2233,8 @@ out: return rc; } -static int ocontext_read(struct policydb *p, const struct policydb_compat_info *info, - void *fp) +static int ocontext_read(struct policydb *p, + const struct policydb_compat_info *info, void *fp) { int rc; unsigned int i; @@ -2267,7 +2269,8 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * goto out; c->sid[0] = le32_to_cpu(buf[0]); - rc = context_read_and_validate(&c->context[0], p, fp); + rc = context_read_and_validate(&c->context[0], + p, fp); if (rc) goto out; break; @@ -2286,21 +2289,24 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * pr_warn("SELinux: void and deprecated fs ocon %s\n", c->u.name); - rc = context_read_and_validate(&c->context[0], p, fp); + rc = context_read_and_validate(&c->context[0], + p, fp); if (rc) goto out; - rc = context_read_and_validate(&c->context[1], p, fp); + rc = context_read_and_validate(&c->context[1], + p, fp); if (rc) goto out; break; case OCON_PORT: - rc = next_entry(buf, fp, sizeof(u32)*3); + rc = next_entry(buf, fp, sizeof(u32) * 3); if (rc) goto out; c->u.port.protocol = le32_to_cpu(buf[0]); c->u.port.low_port = le32_to_cpu(buf[1]); c->u.port.high_port = le32_to_cpu(buf[2]); - rc = context_read_and_validate(&c->context[0], p, fp); + rc = context_read_and_validate(&c->context[0], + p, fp); if (rc) goto out; break; @@ -2310,12 +2316,13 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * goto out; c->u.node.addr = nodebuf[0]; /* network order */ c->u.node.mask = nodebuf[1]; /* network order */ - rc = context_read_and_validate(&c->context[0], p, fp); + rc = context_read_and_validate(&c->context[0], + p, fp); if (rc) goto out; break; case OCON_FSUSE: - rc = next_entry(buf, fp, sizeof(u32)*2); + rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc) goto out; @@ -2332,7 +2339,8 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * if (rc) goto out; - rc = context_read_and_validate(&c->context[0], p, fp); + rc = context_read_and_validate(&c->context[0], + p, fp); if (rc) goto out; break; @@ -2345,8 +2353,9 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * for (k = 0; k < 4; k++) c->u.node6.addr[k] = nodebuf[k]; for (k = 0; k < 4; k++) - c->u.node6.mask[k] = nodebuf[k+4]; - rc = context_read_and_validate(&c->context[0], p, fp); + c->u.node6.mask[k] = nodebuf[k + 4]; + rc = context_read_and_validate(&c->context[0], + p, fp); if (rc) goto out; break; @@ -2359,7 +2368,8 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * goto out; /* we need to have subnet_prefix in CPU order */ - c->u.ibpkey.subnet_prefix = be64_to_cpu(prefixbuf[0]); + c->u.ibpkey.subnet_prefix = + be64_to_cpu(prefixbuf[0]); rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc) @@ -2373,12 +2383,11 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * goto out; } - c->u.ibpkey.low_pkey = pkey_lo; + c->u.ibpkey.low_pkey = pkey_lo; c->u.ibpkey.high_pkey = pkey_hi; rc = context_read_and_validate(&c->context[0], - p, - fp); + p, fp); if (rc) goto out; break; @@ -2391,7 +2400,8 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * goto out; len = le32_to_cpu(buf[0]); - rc = str_read(&c->u.ibendport.dev_name, GFP_KERNEL, fp, len); + rc = str_read(&c->u.ibendport.dev_name, + GFP_KERNEL, fp, len); if (rc) goto out; @@ -2404,8 +2414,7 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info * c->u.ibendport.port = port; rc = context_read_and_validate(&c->context[0], - p, - fp); + p, fp); if (rc) goto out; break; @@ -2462,7 +2471,8 @@ int policydb_read(struct policydb *p, void *fp) policydb_str = kmalloc(len + 1, GFP_KERNEL); if (!policydb_str) { pr_err("SELinux: unable to allocate memory for policydb " - "string of length %d\n", len); + "string of length %d\n", + len); goto bad; } @@ -2477,7 +2487,8 @@ int policydb_read(struct policydb *p, void *fp) policydb_str[len] = '\0'; if (strcmp(policydb_str, POLICYDB_STRING)) { pr_err("SELinux: policydb string %s does not match " - "my string %s\n", policydb_str, POLICYDB_STRING); + "my string %s\n", + policydb_str, POLICYDB_STRING); kfree(policydb_str); goto bad; } @@ -2486,7 +2497,7 @@ int policydb_read(struct policydb *p, void *fp) policydb_str = NULL; /* Read the version and table sizes. */ - rc = next_entry(buf, fp, sizeof(u32)*4); + rc = next_entry(buf, fp, sizeof(u32) * 4); if (rc) goto bad; @@ -2496,7 +2507,8 @@ int policydb_read(struct policydb *p, void *fp) p->policyvers > POLICYDB_VERSION_MAX) { pr_err("SELinux: policydb version %d does not match " "my version range %d-%d\n", - le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); + le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, + POLICYDB_VERSION_MAX); goto bad; } @@ -2506,8 +2518,8 @@ int policydb_read(struct policydb *p, void *fp) rc = -EINVAL; if (p->policyvers < POLICYDB_VERSION_MLS) { pr_err("SELinux: security policydb version %d " - "(MLS) not backwards compatible\n", - p->policyvers); + "(MLS) not backwards compatible\n", + p->policyvers); goto bad; } } @@ -2530,22 +2542,23 @@ int policydb_read(struct policydb *p, void *fp) info = policydb_lookup_compat(p->policyvers); if (!info) { pr_err("SELinux: unable to find policy compat info " - "for version %d\n", p->policyvers); + "for version %d\n", + p->policyvers); goto bad; } rc = -EINVAL; if (le32_to_cpu(buf[2]) != info->sym_num || - le32_to_cpu(buf[3]) != info->ocon_num) { + le32_to_cpu(buf[3]) != info->ocon_num) { pr_err("SELinux: policydb table sizes (%d,%d) do " - "not match mine (%d,%d)\n", le32_to_cpu(buf[2]), - le32_to_cpu(buf[3]), - info->sym_num, info->ocon_num); + "not match mine (%d,%d)\n", + le32_to_cpu(buf[2]), le32_to_cpu(buf[3]), info->sym_num, + info->ocon_num); goto bad; } for (i = 0; i < info->sym_num; i++) { - rc = next_entry(buf, fp, sizeof(u32)*2); + rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc) goto bad; nprim = le32_to_cpu(buf[0]); @@ -2606,7 +2619,7 @@ int policydb_read(struct policydb *p, void *fp) if (!rtd) goto bad; - rc = next_entry(buf, fp, sizeof(u32)*3); + rc = next_entry(buf, fp, sizeof(u32) * 3); if (rc) goto bad; @@ -2650,7 +2663,7 @@ int policydb_read(struct policydb *p, void *fp) lra->next = ra; else p->role_allow = ra; - rc = next_entry(buf, fp, sizeof(u32)*2); + rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc) goto bad; @@ -2698,9 +2711,8 @@ int policydb_read(struct policydb *p, void *fp) goto bad; rc = -ENOMEM; - p->type_attr_map_array = kvcalloc(p->p_types.nprim, - sizeof(*p->type_attr_map_array), - GFP_KERNEL); + p->type_attr_map_array = kvcalloc( + p->p_types.nprim, sizeof(*p->type_attr_map_array), GFP_KERNEL); if (!p->type_attr_map_array) goto bad; @@ -2773,7 +2785,7 @@ static int mls_write_range_helper(struct mls_range *r, void *fp) items = 2; else items = 3; - buf[0] = cpu_to_le32(items-1); + buf[0] = cpu_to_le32(items - 1); buf[1] = cpu_to_le32(r->level[0].sens); if (!eq) buf[2] = cpu_to_le32(r->level[1].sens); @@ -2916,8 +2928,7 @@ static int role_allow_write(struct role_allow *r, void *fp) * Write a security context structure * to a policydb binary representation file. */ -static int context_write(struct policydb *p, struct context *c, - void *fp) +static int context_write(struct policydb *p, struct context *c, void *fp) { int rc; __le32 buf[3]; @@ -3045,7 +3056,7 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node, if (rc) return rc; if (p->policyvers >= - POLICYDB_VERSION_CONSTRAINT_NAMES) { + POLICYDB_VERSION_CONSTRAINT_NAMES) { rc = type_set_write(e->type_names, fp); if (rc) return rc; @@ -3266,7 +3277,8 @@ static int user_write(void *vkey, void *datum, void *ptr) return 0; } -static int (*const write_f[SYM_NUM]) (void *key, void *datum, void *datap) = { +/* clang-format off */ +static int (*const write_f[SYM_NUM])(void *key, void *datum, void *datap) = { common_write, class_write, role_write, @@ -3276,9 +3288,10 @@ static int (*const write_f[SYM_NUM]) (void *key, void *datum, void *datap) = { sens_write, cat_write, }; +/* clang-format on */ -static int ocontext_write(struct policydb *p, const struct policydb_compat_info *info, - void *fp) +static int ocontext_write(struct policydb *p, + const struct policydb_compat_info *info, void *fp) { unsigned int i, j; int rc; @@ -3360,9 +3373,13 @@ static int ocontext_write(struct policydb *p, const struct policydb_compat_info break; case OCON_NODE6: for (j = 0; j < 4; j++) - nodebuf[j] = c->u.node6.addr[j]; /* network order */ + nodebuf[j] = + c->u.node6.addr + [j]; /* network order */ for (j = 0; j < 4; j++) - nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */ + nodebuf[j + 4] = + c->u.node6.mask + [j]; /* network order */ rc = put_entry(nodebuf, sizeof(u32), 8, fp); if (rc) return rc; @@ -3372,7 +3389,8 @@ static int ocontext_write(struct policydb *p, const struct policydb_compat_info break; case OCON_IBPKEY: /* subnet_prefix is in CPU order */ - prefixbuf[0] = cpu_to_be64(c->u.ibpkey.subnet_prefix); + prefixbuf[0] = + cpu_to_be64(c->u.ibpkey.subnet_prefix); rc = put_entry(prefixbuf, sizeof(u64), 1, fp); if (rc) @@ -3395,7 +3413,8 @@ static int ocontext_write(struct policydb *p, const struct policydb_compat_info rc = put_entry(buf, sizeof(u32), 2, fp); if (rc) return rc; - rc = put_entry(c->u.ibendport.dev_name, 1, len, fp); + rc = put_entry(c->u.ibendport.dev_name, 1, len, + fp); if (rc) return rc; rc = context_write(p, &c->context[0], fp); @@ -3521,7 +3540,8 @@ static int filename_write_helper_compat(void *key, void *data, void *ptr) u32 bit, len = strlen(ft->name); do { - ebitmap_for_each_positive_bit(&datum->stypes, node, bit) { + ebitmap_for_each_positive_bit(&datum->stypes, node, bit) + { buf[0] = cpu_to_le32(len); rc = put_entry(buf, sizeof(u32), 1, fp); if (rc) @@ -3645,8 +3665,8 @@ int policydb_write(struct policydb *p, void *fp) */ if (p->policyvers < POLICYDB_VERSION_AVTAB) { pr_err("SELinux: refusing to write policy version %d." - " Because it is less than version %d\n", p->policyvers, - POLICYDB_VERSION_AVTAB); + " Because it is less than version %d\n", + p->policyvers, POLICYDB_VERSION_AVTAB); return -EINVAL; } @@ -3674,7 +3694,8 @@ int policydb_write(struct policydb *p, void *fp) info = policydb_lookup_compat(p->policyvers); if (!info) { pr_err("SELinux: compatibility lookup failed for policy " - "version %d\n", p->policyvers); + "version %d\n", + p->policyvers); return -EINVAL; } diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index b97cda4897..4bba386264 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -8,15 +8,13 @@ /* * Updated: Trusted Computer Solutions, Inc. + * Support for enhanced MLS infrastructure. + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * - * Support for enhanced MLS infrastructure. - * - * Updated: Frank Mayer and Karl MacMillan - * - * Added conditional policy language extensions - * - * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. - * Copyright (C) 2003 - 2004 Tresys Technology, LLC + * Updated: Frank Mayer and + * Karl MacMillan + * Added conditional policy language extensions + * Copyright (C) 2003-2004 Tresys Technology, LLC */ #ifndef _SS_POLICYDB_H_ @@ -39,104 +37,103 @@ /* Permission attributes */ struct perm_datum { - u32 value; /* permission bit + 1 */ + u32 value; /* permission bit + 1 */ }; /* Attributes of a common prefix for access vectors */ struct common_datum { - u32 value; /* internal common value */ - struct symtab permissions; /* common permissions */ + u32 value; /* internal common value */ + struct symtab permissions; /* common permissions */ }; /* Class attributes */ struct class_datum { - u32 value; /* class value */ - char *comkey; /* common name */ - struct common_datum *comdatum; /* common datum */ - struct symtab permissions; /* class-specific permission symbol table */ - struct constraint_node *constraints; /* constraints on class permissions */ - struct constraint_node *validatetrans; /* special transition rules */ + u32 value; /* class value */ + char *comkey; /* common name */ + struct common_datum *comdatum; /* common datum */ + struct symtab permissions; /* class-specific permission symbol table */ + struct constraint_node *constraints; /* constraints on class perms */ + struct constraint_node *validatetrans; /* special transition rules */ /* Options how a new object user, role, and type should be decided */ -#define DEFAULT_SOURCE 1 -#define DEFAULT_TARGET 2 +#define DEFAULT_SOURCE 1 +#define DEFAULT_TARGET 2 char default_user; char default_role; char default_type; /* Options how a new object range should be decided */ -#define DEFAULT_SOURCE_LOW 1 -#define DEFAULT_SOURCE_HIGH 2 -#define DEFAULT_SOURCE_LOW_HIGH 3 -#define DEFAULT_TARGET_LOW 4 -#define DEFAULT_TARGET_HIGH 5 -#define DEFAULT_TARGET_LOW_HIGH 6 +#define DEFAULT_SOURCE_LOW 1 +#define DEFAULT_SOURCE_HIGH 2 +#define DEFAULT_SOURCE_LOW_HIGH 3 +#define DEFAULT_TARGET_LOW 4 +#define DEFAULT_TARGET_HIGH 5 +#define DEFAULT_TARGET_LOW_HIGH 6 #define DEFAULT_GLBLUB 7 char default_range; }; /* Role attributes */ struct role_datum { - u32 value; /* internal role value */ - u32 bounds; /* boundary of role */ - struct ebitmap dominates; /* set of roles dominated by this role */ - struct ebitmap types; /* set of authorized types for role */ + u32 value; /* internal role value */ + u32 bounds; /* boundary of role */ + struct ebitmap dominates; /* set of roles dominated by this role */ + struct ebitmap types; /* set of authorized types for role */ }; struct role_trans_key { - u32 role; /* current role */ - u32 type; /* program executable type, or new object type */ - u32 tclass; /* process class, or new object class */ + u32 role; /* current role */ + u32 type; /* program executable type, or new object type */ + u32 tclass; /* process class, or new object class */ }; struct role_trans_datum { - u32 new_role; /* new role */ + u32 new_role; /* new role */ }; struct filename_trans_key { - u32 ttype; /* parent dir context */ - u16 tclass; /* class of new object */ - const char *name; /* last path component */ + u32 ttype; /* parent dir context */ + u16 tclass; /* class of new object */ + const char *name; /* last path component */ }; struct filename_trans_datum { - struct ebitmap stypes; /* bitmap of source types for this otype */ - u32 otype; /* resulting type of new object */ - struct filename_trans_datum *next; /* record for next otype*/ + struct ebitmap stypes; /* bitmap of source types for this otype */ + u32 otype; /* resulting type of new object */ + struct filename_trans_datum *next; /* record for next otype*/ }; struct role_allow { - u32 role; /* current role */ - u32 new_role; /* new role */ + u32 role; /* current role */ + u32 new_role; /* new role */ struct role_allow *next; }; /* Type attributes */ struct type_datum { - u32 value; /* internal type value */ - u32 bounds; /* boundary of type */ - unsigned char primary; /* primary name? */ - unsigned char attribute;/* attribute ?*/ + u32 value; /* internal type value */ + u32 bounds; /* boundary of type */ + unsigned char primary; /* primary name? */ + unsigned char attribute; /* attribute ?*/ }; /* User attributes */ struct user_datum { - u32 value; /* internal user value */ - u32 bounds; /* bounds of user */ - struct ebitmap roles; /* set of authorized roles for user */ - struct mls_range range; /* MLS range (min - max) for user */ - struct mls_level dfltlevel; /* default login MLS level for user */ + u32 value; /* internal user value */ + u32 bounds; /* bounds of user */ + struct ebitmap roles; /* set of authorized roles for user */ + struct mls_range range; /* MLS range (min - max) for user */ + struct mls_level dfltlevel; /* default login MLS level for user */ }; - /* Sensitivity attributes */ struct level_datum { - struct mls_level *level; /* sensitivity and associated categories */ - unsigned char isalias; /* is this sensitivity an alias for another? */ + struct mls_level *level; /* sensitivity and associated categories */ + unsigned char isalias; /* is this sensitivity an alias for another? */ }; /* Category attributes */ struct cat_datum { - u32 value; /* internal category bit + 1 */ - unsigned char isalias; /* is this category an alias for another? */ + u32 value; /* internal category bit + 1 */ + unsigned char isalias; /* is this category an alias for another? */ }; struct range_trans { @@ -147,7 +144,7 @@ struct range_trans { /* Boolean data type */ struct cond_bool_datum { - __u32 value; /* internal type value */ + __u32 value; /* internal type value */ int state; }; @@ -173,20 +170,20 @@ struct type_set { */ struct ocontext { union { - char *name; /* name of initial SID, fs, netif, fstype, path */ + char *name; /* name of initial SID, fs, netif, fstype, path */ struct { u8 protocol; u16 low_port; u16 high_port; - } port; /* TCP or UDP port information */ + } port; /* TCP or UDP port information */ struct { u32 addr; u32 mask; - } node; /* node information */ + } node; /* node information */ struct { u32 addr[4]; u32 mask[4]; - } node6; /* IPv6 node information */ + } node6; /* IPv6 node information */ struct { u64 subnet_prefix; u16 low_pkey; @@ -198,11 +195,11 @@ struct ocontext { } ibendport; } u; union { - u32 sclass; /* security class for genfs */ - u32 behavior; /* labeling behavior for fs_use */ + u32 sclass; /* security class for genfs */ + u32 behavior; /* labeling behavior for fs_use */ } v; - struct context context[2]; /* security context(s) */ - u32 sid[2]; /* SID(s) */ + struct context context[2]; /* security context(s) */ + u32 sid[2]; /* SID(s) */ struct ocontext *next; }; @@ -221,19 +218,19 @@ struct genfs { #define SYM_BOOLS 5 #define SYM_LEVELS 6 #define SYM_CATS 7 -#define SYM_NUM 8 +#define SYM_NUM 8 /* object context array indices */ -#define OCON_ISID 0 /* initial SIDs */ -#define OCON_FS 1 /* unlabeled file systems (deprecated) */ -#define OCON_PORT 2 /* TCP and UDP port numbers */ -#define OCON_NETIF 3 /* network interfaces */ -#define OCON_NODE 4 /* nodes */ -#define OCON_FSUSE 5 /* fs_use */ -#define OCON_NODE6 6 /* IPv6 nodes */ -#define OCON_IBPKEY 7 /* Infiniband PKeys */ -#define OCON_IBENDPORT 8 /* Infiniband end ports */ -#define OCON_NUM 9 +#define OCON_ISID 0 /* initial SIDs */ +#define OCON_FS 1 /* unlabeled file systems (deprecated) */ +#define OCON_PORT 2 /* TCP and UDP port numbers */ +#define OCON_NETIF 3 /* network interfaces */ +#define OCON_NODE 4 /* nodes */ +#define OCON_FSUSE 5 /* fs_use */ +#define OCON_NODE6 6 /* IPv6 nodes */ +#define OCON_IBPKEY 7 /* Infiniband PKeys */ +#define OCON_IBENDPORT 8 /* Infiniband end ports */ +#define OCON_NUM 9 /* The policy database */ struct policydb { @@ -243,15 +240,15 @@ struct policydb { struct symtab symtab[SYM_NUM]; #define p_commons symtab[SYM_COMMONS] #define p_classes symtab[SYM_CLASSES] -#define p_roles symtab[SYM_ROLES] -#define p_types symtab[SYM_TYPES] -#define p_users symtab[SYM_USERS] -#define p_bools symtab[SYM_BOOLS] -#define p_levels symtab[SYM_LEVELS] -#define p_cats symtab[SYM_CATS] +#define p_roles symtab[SYM_ROLES] +#define p_types symtab[SYM_TYPES] +#define p_users symtab[SYM_USERS] +#define p_bools symtab[SYM_BOOLS] +#define p_levels symtab[SYM_LEVELS] +#define p_cats symtab[SYM_CATS] /* symbol names indexed by (value - 1) */ - char **sym_val_to_name[SYM_NUM]; + char **sym_val_to_name[SYM_NUM]; /* class, role, and user attributes indexed by (value - 1) */ struct class_datum **class_val_to_struct; @@ -324,25 +321,25 @@ extern int policydb_role_isvalid(struct policydb *p, unsigned int role); extern int policydb_read(struct policydb *p, void *fp); extern int policydb_write(struct policydb *p, void *fp); -extern struct filename_trans_datum *policydb_filenametr_search( - struct policydb *p, struct filename_trans_key *key); +extern struct filename_trans_datum * +policydb_filenametr_search(struct policydb *p, struct filename_trans_key *key); -extern struct mls_range *policydb_rangetr_search( - struct policydb *p, struct range_trans *key); +extern struct mls_range *policydb_rangetr_search(struct policydb *p, + struct range_trans *key); -extern struct role_trans_datum *policydb_roletr_search( - struct policydb *p, struct role_trans_key *key); +extern struct role_trans_datum * +policydb_roletr_search(struct policydb *p, struct role_trans_key *key); -#define POLICYDB_CONFIG_MLS 1 +#define POLICYDB_CONFIG_MLS 1 /* the config flags related to unknown classes/perms are bits 2 and 3 */ -#define REJECT_UNKNOWN 0x00000002 -#define ALLOW_UNKNOWN 0x00000004 +#define REJECT_UNKNOWN 0x00000002 +#define ALLOW_UNKNOWN 0x00000004 -#define OBJECT_R "object_r" +#define OBJECT_R "object_r" #define OBJECT_R_VAL 1 -#define POLICYDB_MAGIC SELINUX_MAGIC +#define POLICYDB_MAGIC SELINUX_MAGIC #define POLICYDB_STRING "SE Linux" struct policy_file { @@ -366,7 +363,8 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) return 0; } -static inline int put_entry(const void *buf, size_t bytes, size_t num, struct policy_file *fp) +static inline int put_entry(const void *buf, size_t bytes, size_t num, + struct policy_file *fp) { size_t len; @@ -382,7 +380,8 @@ static inline int put_entry(const void *buf, size_t bytes, size_t num, struct po return 0; } -static inline char *sym_name(struct policydb *p, unsigned int sym_num, unsigned int element_nr) +static inline char *sym_name(struct policydb *p, unsigned int sym_num, + unsigned int element_nr) { return p->sym_val_to_name[sym_num][element_nr]; } @@ -390,5 +389,4 @@ static inline char *sym_name(struct policydb *p, unsigned int sym_num, unsigned extern u16 string_to_security_class(struct policydb *p, const char *name); extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); -#endif /* _SS_POLICYDB_H_ */ - +#endif /* _SS_POLICYDB_H_ */ diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index e88b1b6c4a..ded250e525 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -3508,7 +3508,8 @@ void selinux_audit_rule_free(void *vrule) } } -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, + gfp_t gfp) { struct selinux_state *state = &selinux_state; struct selinux_policy *policy; @@ -3549,7 +3550,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) return -EINVAL; } - tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); + tmprule = kzalloc(sizeof(struct selinux_audit_rule), gfp); if (!tmprule) return -ENOMEM; context_init(&tmprule->au_ctxt); diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index d24b0a3d19..93358e7a64 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h @@ -4,6 +4,7 @@ * * Author : Stephen Smalley, */ + #ifndef _SS_SERVICES_H_ #define _SS_SERVICES_H_ @@ -43,4 +44,4 @@ int services_convert_context(struct convert_context_args *args, struct context *oldc, struct context *newc, gfp_t gfp_flags); -#endif /* _SS_SERVICES_H_ */ +#endif /* _SS_SERVICES_H_ */ diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index 732fd8e22a..c8848cbba8 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -7,6 +7,7 @@ * * Copyright (C) 2018 Red Hat, Inc. */ + #include #include #include @@ -29,7 +30,7 @@ struct sidtab_str_cache { }; #define index_to_sid(index) ((index) + SECINITSID_NUM + 1) -#define sid_to_index(sid) ((sid) - (SECINITSID_NUM + 1)) +#define sid_to_index(sid) ((sid) - (SECINITSID_NUM + 1)) int sidtab_init(struct sidtab *s) { @@ -140,9 +141,11 @@ int sidtab_hash_stats(struct sidtab *sidtab, char *page) if (chain_len > max_chain_len) max_chain_len = chain_len; - return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n" - "longest chain: %d\n", entries, - slots_used, SIDTAB_HASH_BUCKETS, max_chain_len); + return scnprintf(page, PAGE_SIZE, + "entries: %d\nbuckets used: %d/%d\n" + "longest chain: %d\n", + entries, slots_used, SIDTAB_HASH_BUCKETS, + max_chain_len); } static u32 sidtab_level_from_count(u32 count) @@ -162,15 +165,15 @@ static int sidtab_alloc_roots(struct sidtab *s, u32 level) u32 l; if (!s->roots[0].ptr_leaf) { - s->roots[0].ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, - GFP_ATOMIC); + s->roots[0].ptr_leaf = + kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_ATOMIC); if (!s->roots[0].ptr_leaf) return -ENOMEM; } for (l = 1; l <= level; ++l) if (!s->roots[l].ptr_inner) { - s->roots[l].ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, - GFP_ATOMIC); + s->roots[l].ptr_inner = + kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_ATOMIC); if (!s->roots[l].ptr_inner) return -ENOMEM; s->roots[l].ptr_inner->entries[0] = s->roots[l - 1]; @@ -203,16 +206,16 @@ static struct sidtab_entry *sidtab_do_lookup(struct sidtab *s, u32 index, if (!entry->ptr_inner) { if (alloc) - entry->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, - GFP_ATOMIC); + entry->ptr_inner = kzalloc( + SIDTAB_NODE_ALLOC_SIZE, GFP_ATOMIC); if (!entry->ptr_inner) return NULL; } } if (!entry->ptr_leaf) { if (alloc) - entry->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, - GFP_ATOMIC); + entry->ptr_leaf = + kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_ATOMIC); if (!entry->ptr_leaf) return NULL; } @@ -262,8 +265,7 @@ struct sidtab_entry *sidtab_search_entry_force(struct sidtab *s, u32 sid) return sidtab_search_core(s, sid, 1); } -int sidtab_context_to_sid(struct sidtab *s, struct context *context, - u32 *sid) +int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid) { unsigned long flags; u32 count, hash = context_compute_hash(context); @@ -327,8 +329,8 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, goto out_unlock; } - rc = services_convert_context(convert->args, - context, &dst_convert->context, + rc = services_convert_context(convert->args, context, + &dst_convert->context, GFP_ATOMIC); if (rc) { context_destroy(&dst->context); @@ -338,8 +340,8 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, dst_convert->hash = context_compute_hash(&dst_convert->context); target->count = count + 1; - hash_add_rcu(target->context_to_sid, - &dst_convert->list, dst_convert->hash); + hash_add_rcu(target->context_to_sid, &dst_convert->list, + dst_convert->hash); } if (context->len) @@ -373,8 +375,8 @@ static void sidtab_convert_hashtable(struct sidtab *s, u32 count) } static int sidtab_convert_tree(union sidtab_entry_inner *edst, - union sidtab_entry_inner *esrc, - u32 *pos, u32 count, u32 level, + union sidtab_entry_inner *esrc, u32 *pos, + u32 count, u32 level, struct sidtab_convert_params *convert) { int rc; @@ -382,8 +384,8 @@ static int sidtab_convert_tree(union sidtab_entry_inner *edst, if (level != 0) { if (!edst->ptr_inner) { - edst->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, - GFP_KERNEL); + edst->ptr_inner = + kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_KERNEL); if (!edst->ptr_inner) return -ENOMEM; } @@ -399,17 +401,18 @@ static int sidtab_convert_tree(union sidtab_entry_inner *edst, } } else { if (!edst->ptr_leaf) { - edst->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, - GFP_KERNEL); + edst->ptr_leaf = + kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_KERNEL); if (!edst->ptr_leaf) return -ENOMEM; } i = 0; while (i < SIDTAB_LEAF_ENTRIES && *pos < count) { - rc = services_convert_context(convert->args, - &esrc->ptr_leaf->entries[i].context, - &edst->ptr_leaf->entries[i].context, - GFP_KERNEL); + rc = services_convert_context( + convert->args, + &esrc->ptr_leaf->entries[i].context, + &edst->ptr_leaf->entries[i].context, + GFP_KERNEL); if (rc) return rc; (*pos)++; @@ -489,13 +492,15 @@ void sidtab_cancel_convert(struct sidtab *s) spin_unlock_irqrestore(&s->lock, flags); } -void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) __acquires(&s->lock) +void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) + __acquires(&s->lock) { spin_lock_irqsave(&s->lock, *flags); s->frozen = true; s->convert = NULL; } -void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) __releases(&s->lock) +void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) + __releases(&s->lock) { spin_unlock_irqrestore(&s->lock, *flags); } @@ -600,8 +605,8 @@ out_unlock: kfree_rcu(victim, rcu_member); } -int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry, - char **out, u32 *out_len) +int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry, char **out, + u32 *out_len) { struct sidtab_str_cache *cache; int rc = 0; diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h index 22258201cd..832c85c70d 100644 --- a/security/selinux/ss/sidtab.h +++ b/security/selinux/ss/sidtab.h @@ -8,6 +8,7 @@ * * Copyright (C) 2018 Red Hat, Inc. */ + #ifndef _SS_SIDTAB_H_ #define _SS_SIDTAB_H_ @@ -29,25 +30,26 @@ struct sidtab_entry { union sidtab_entry_inner { struct sidtab_node_inner *ptr_inner; - struct sidtab_node_leaf *ptr_leaf; + struct sidtab_node_leaf *ptr_leaf; }; /* align node size to page boundary */ #define SIDTAB_NODE_ALLOC_SHIFT PAGE_SHIFT -#define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE +#define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE -#define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size) - 1) + 1)) +#define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size)-1) + 1)) -#define SIDTAB_INNER_SHIFT \ - (SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner))) +#define SIDTAB_INNER_SHIFT \ + (SIDTAB_NODE_ALLOC_SHIFT - \ + size_to_shift(sizeof(union sidtab_entry_inner))) #define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT) #define SIDTAB_LEAF_ENTRIES \ (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry)) #define SIDTAB_MAX_BITS 32 -#define SIDTAB_MAX U32_MAX +#define SIDTAB_MAX U32_MAX /* ensure enough tree levels for SIDTAB_MAX entries */ -#define SIDTAB_MAX_LEVEL \ +#define SIDTAB_MAX_LEVEL \ DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \ SIDTAB_INNER_SHIFT) @@ -69,7 +71,7 @@ struct sidtab_convert_params { struct sidtab *target; }; -#define SIDTAB_HASH_BITS CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS +#define SIDTAB_HASH_BITS CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS #define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) struct sidtab { @@ -125,8 +127,10 @@ int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params); void sidtab_cancel_convert(struct sidtab *s); -void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) __acquires(&s->lock); -void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) __releases(&s->lock); +void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) + __acquires(&s->lock); +void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) + __releases(&s->lock); int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid); @@ -137,8 +141,8 @@ int sidtab_hash_stats(struct sidtab *sidtab, char *page); #if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry, const char *str, u32 str_len); -int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry, - char **out, u32 *out_len); +int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry, char **out, + u32 *out_len); #else static inline void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry, @@ -146,13 +150,11 @@ static inline void sidtab_sid2str_put(struct sidtab *s, { } static inline int sidtab_sid2str_get(struct sidtab *s, - struct sidtab_entry *entry, - char **out, u32 *out_len) + struct sidtab_entry *entry, char **out, + u32 *out_len) { return -ENOENT; } #endif /* CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 */ -#endif /* _SS_SIDTAB_H_ */ - - +#endif /* _SS_SIDTAB_H_ */ diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c index 43d7f0319c..c04f8d4478 100644 --- a/security/selinux/ss/symtab.c +++ b/security/selinux/ss/symtab.c @@ -4,6 +4,7 @@ * * Author : Stephen Smalley, */ + #include #include #include @@ -19,7 +20,8 @@ static unsigned int symhash(const void *key) keyp = key; size = strlen(keyp); for (p = keyp; (p - keyp) < size; p++) - val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p); + val = (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ + (*p); return val; } diff --git a/security/selinux/ss/symtab.h b/security/selinux/ss/symtab.h index 0a3b5de79a..8e667cdbf3 100644 --- a/security/selinux/ss/symtab.h +++ b/security/selinux/ss/symtab.h @@ -7,14 +7,15 @@ * * Author : Stephen Smalley, */ + #ifndef _SS_SYMTAB_H_ #define _SS_SYMTAB_H_ #include "hashtab.h" struct symtab { - struct hashtab table; /* hash table (keyed on a string) */ - u32 nprim; /* number of primary names in table */ + struct hashtab table; /* hash table (keyed on a string) */ + u32 nprim; /* number of primary names in table */ }; int symtab_init(struct symtab *s, u32 size); @@ -22,6 +23,4 @@ int symtab_init(struct symtab *s, u32 size); int symtab_insert(struct symtab *s, char *name, void *datum); void *symtab_search(struct symtab *s, const char *name); -#endif /* _SS_SYMTAB_H_ */ - - +#endif /* _SS_SYMTAB_H_ */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 6f9a80783a..c6df5c00c7 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -994,57 +994,62 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, struct xattr *xattrs, int *xattr_count) { struct task_smack *tsp = smack_cred(current_cred()); + struct inode_smack *issp = smack_inode(inode); struct smack_known *skp = smk_of_task(tsp); struct smack_known *isp = smk_of_inode(inode); struct smack_known *dsp = smk_of_inode(dir); struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count); int may; - if (xattr) { - /* - * If equal, transmuting already occurred in - * smack_dentry_create_files_as(). No need to check again. - */ - if (tsp->smk_task != tsp->smk_transmuted) { - rcu_read_lock(); - may = smk_access_entry(skp->smk_known, dsp->smk_known, - &skp->smk_rules); - rcu_read_unlock(); - } + /* + * If equal, transmuting already occurred in + * smack_dentry_create_files_as(). No need to check again. + */ + if (tsp->smk_task != tsp->smk_transmuted) { + rcu_read_lock(); + may = smk_access_entry(skp->smk_known, dsp->smk_known, + &skp->smk_rules); + rcu_read_unlock(); + } + + /* + * In addition to having smk_task equal to smk_transmuted, + * if the access rule allows transmutation and the directory + * requests transmutation then by all means transmute. + * Mark the inode as changed. + */ + if ((tsp->smk_task == tsp->smk_transmuted) || + (may > 0 && ((may & MAY_TRANSMUTE) != 0) && + smk_inode_transmutable(dir))) { + struct xattr *xattr_transmute; /* - * In addition to having smk_task equal to smk_transmuted, - * if the access rule allows transmutation and the directory - * requests transmutation then by all means transmute. - * Mark the inode as changed. + * The caller of smack_dentry_create_files_as() + * should have overridden the current cred, so the + * inode label was already set correctly in + * smack_inode_alloc_security(). */ - if ((tsp->smk_task == tsp->smk_transmuted) || - (may > 0 && ((may & MAY_TRANSMUTE) != 0) && - smk_inode_transmutable(dir))) { - struct xattr *xattr_transmute; + if (tsp->smk_task != tsp->smk_transmuted) + isp = issp->smk_inode = dsp; + + issp->smk_flags |= SMK_INODE_TRANSMUTE; + xattr_transmute = lsm_get_xattr_slot(xattrs, + xattr_count); + if (xattr_transmute) { + xattr_transmute->value = kmemdup(TRANS_TRUE, + TRANS_TRUE_SIZE, + GFP_NOFS); + if (!xattr_transmute->value) + return -ENOMEM; - /* - * The caller of smack_dentry_create_files_as() - * should have overridden the current cred, so the - * inode label was already set correctly in - * smack_inode_alloc_security(). - */ - if (tsp->smk_task != tsp->smk_transmuted) - isp = dsp; - xattr_transmute = lsm_get_xattr_slot(xattrs, - xattr_count); - if (xattr_transmute) { - xattr_transmute->value = kmemdup(TRANS_TRUE, - TRANS_TRUE_SIZE, - GFP_NOFS); - if (!xattr_transmute->value) - return -ENOMEM; - - xattr_transmute->value_len = TRANS_TRUE_SIZE; - xattr_transmute->name = XATTR_SMACK_TRANSMUTE; - } + xattr_transmute->value_len = TRANS_TRUE_SIZE; + xattr_transmute->name = XATTR_SMACK_TRANSMUTE; } + } + issp->smk_flags |= SMK_INODE_INSTANT; + + if (xattr) { xattr->value = kstrdup(isp->smk_known, GFP_NOFS); if (!xattr->value) return -ENOMEM; @@ -1233,12 +1238,14 @@ static int smack_inode_permission(struct inode *inode, int mask) /** * smack_inode_setattr - Smack check for setting attributes + * @idmap: idmap of the mount * @dentry: the object * @iattr: for the force flag * * Returns 0 if access is permitted, an error code otherwise */ -static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) +static int smack_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + struct iattr *iattr) { struct smk_audit_info ad; int rc; @@ -2096,12 +2103,7 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old) struct task_smack *old_tsp = smack_cred(old); struct task_smack *new_tsp = smack_cred(new); - new_tsp->smk_task = old_tsp->smk_task; - new_tsp->smk_forked = old_tsp->smk_task; - mutex_init(&new_tsp->smk_rules_lock); - INIT_LIST_HEAD(&new_tsp->smk_rules); - - /* cbs copy rule list */ + init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task); } /** @@ -4690,11 +4692,13 @@ static int smack_post_notification(const struct cred *w_cred, * @op: required testing operator (=, !=, >, <, ...) * @rulestr: smack label to be audited * @vrule: pointer to save our own audit rule representation + * @gfp: type of the memory for the allocation * * Prepare to audit cases where (@field @op @rulestr) is true. * The label to be audited is created if necessay. */ -static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) +static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, + gfp_t gfp) { struct smack_known *skp; char **rule = (char **)vrule; -- cgit v1.2.3