diff options
Diffstat (limited to 'security/integrity/evm')
| -rw-r--r-- | security/integrity/evm/Kconfig | 45 | ||||
| -rw-r--r-- | security/integrity/evm/evm.h | 33 | ||||
| -rw-r--r-- | security/integrity/evm/evm_crypto.c | 21 | ||||
| -rw-r--r-- | security/integrity/evm/evm_main.c | 69 | ||||
| -rw-r--r-- | security/integrity/evm/evm_posix_acl.c | 3 | ||||
| -rw-r--r-- | security/integrity/evm/evm_secfs.c | 12 |
6 files changed, 130 insertions, 53 deletions
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index afbb59dd262..d606f3d12d6 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -1,13 +1,52 @@ config EVM boolean "EVM support" - depends on SECURITY && KEYS && (TRUSTED_KEYS=y || TRUSTED_KEYS=n) + depends on SECURITY + select KEYS + select ENCRYPTED_KEYS select CRYPTO_HMAC - select CRYPTO_MD5 select CRYPTO_SHA1 - select ENCRYPTED_KEYS default n help EVM protects a file's security extended attributes against integrity attacks. If you are unsure how to answer this question, answer N. + +if EVM + +menu "EVM options" + +config EVM_ATTR_FSUUID + bool "FSUUID (version 2)" + default y + depends on EVM + help + Include filesystem UUID for HMAC calculation. + + Default value is 'selected', which is former version 2. + if 'not selected', it is former version 1 + + WARNING: changing the HMAC calculation method or adding + additional info to the calculation, requires existing EVM + labeled file systems to be relabeled. + +config EVM_EXTRA_SMACK_XATTRS + bool "Additional SMACK xattrs" + depends on EVM && SECURITY_SMACK + default n + help + Include additional SMACK xattrs for HMAC calculation. + + In addition to the original security xattrs (eg. security.selinux, + security.SMACK64, security.capability, and security.ima) included + in the HMAC calculation, enabling this option includes newly defined + Smack xattrs: security.SMACK64EXEC, security.SMACK64TRANSMUTE and + security.SMACK64MMAP. + + WARNING: changing the HMAC calculation method or adding + additional info to the calculation, requires existing EVM + labeled file systems to be relabeled. + +endmenu + +endif diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index c885247ebcf..88bfe77efa1 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -25,26 +25,29 @@ extern int evm_initialized; extern char *evm_hmac; extern char *evm_hash; +#define EVM_ATTR_FSUUID 0x0001 + +extern int evm_hmac_attrs; + extern struct crypto_shash *hmac_tfm; extern struct crypto_shash *hash_tfm; /* List of EVM protected security xattrs */ extern char *evm_config_xattrnames[]; -extern int evm_init_key(void); -extern int evm_update_evmxattr(struct dentry *dentry, - const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len); -extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); -extern int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); -extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr, - char *hmac_val); -extern int evm_init_secfs(void); -extern void evm_cleanup_secfs(void); +int evm_init_key(void); +int evm_update_evmxattr(struct dentry *dentry, + const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len); +int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, char *digest); +int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, char *digest); +int evm_init_hmac(struct inode *inode, const struct xattr *xattr, + char *hmac_val); +int evm_init_secfs(void); #endif diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 49a464f5595..5e9687f02e1 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -13,6 +13,8 @@ * Using root's kernel master key (kmk), calculate the HMAC */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/crypto.h> #include <linux/xattr.h> @@ -103,13 +105,16 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, umode_t mode; } hmac_misc; - memset(&hmac_misc, 0, sizeof hmac_misc); + memset(&hmac_misc, 0, sizeof(hmac_misc)); hmac_misc.ino = inode->i_ino; hmac_misc.generation = inode->i_generation; - hmac_misc.uid = inode->i_uid; - hmac_misc.gid = inode->i_gid; + hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid); + hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); hmac_misc.mode = inode->i_mode; - crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc); + crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); + if (evm_hmac_attrs & EVM_ATTR_FSUUID) + crypto_shash_update(desc, inode->i_sb->s_uuid, + sizeof(inode->i_sb->s_uuid)); crypto_shash_final(desc, digest); } @@ -134,7 +139,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, int error; int size; - if (!inode->i_op || !inode->i_op->getxattr) + if (!inode->i_op->getxattr) return -EOPNOTSUPP; desc = init_desc(type); if (IS_ERR(desc)) @@ -205,9 +210,9 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM, &xattr_data, sizeof(xattr_data), 0); - } - else if (rc == -ENODATA) + } else if (rc == -ENODATA && inode->i_op->removexattr) { rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM); + } return rc; } @@ -218,7 +223,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, desc = init_desc(EVM_XATTR_HMAC); if (IS_ERR(desc)) { - printk(KERN_INFO "init_desc failed\n"); + pr_info("init_desc failed\n"); return PTR_ERR(desc); } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 8901501425f..3bcb80df4d0 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -14,8 +14,11 @@ * evm_inode_removexattr, and evm_verifyxattr */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/crypto.h> +#include <linux/audit.h> #include <linux/xattr.h> #include <linux/integrity.h> #include <linux/evm.h> @@ -24,8 +27,12 @@ int evm_initialized; +static char *integrity_status_msg[] = { + "pass", "fail", "no_label", "no_xattrs", "unknown" +}; char *evm_hmac = "hmac(sha1)"; char *evm_hash = "sha1"; +int evm_hmac_attrs; char *evm_config_xattrnames[] = { #ifdef CONFIG_SECURITY_SELINUX @@ -33,6 +40,14 @@ char *evm_config_xattrnames[] = { #endif #ifdef CONFIG_SECURITY_SMACK XATTR_NAME_SMACK, +#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS + XATTR_NAME_SMACKEXEC, + XATTR_NAME_SMACKTRANSMUTE, + XATTR_NAME_SMACKMMAP, +#endif +#endif +#ifdef CONFIG_IMA_APPRAISE + XATTR_NAME_IMA, #endif XATTR_NAME_CAPS, NULL @@ -47,6 +62,14 @@ static int __init evm_set_fixmode(char *str) } __setup("evm=", evm_set_fixmode); +static void __init evm_init_config(void) +{ +#ifdef CONFIG_EVM_ATTR_FSUUID + evm_hmac_attrs |= EVM_ATTR_FSUUID; +#endif + pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs); +} + static int evm_find_protected_xattrs(struct dentry *dentry) { struct inode *inode = dentry->d_inode; @@ -54,7 +77,7 @@ static int evm_find_protected_xattrs(struct dentry *dentry) int error; int count = 0; - if (!inode->i_op || !inode->i_op->getxattr) + if (!inode->i_op->getxattr) return -EOPNOTSUPP; for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) { @@ -115,7 +138,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, goto out; } - xattr_len = rc - 1; + xattr_len = rc; /* check value type */ switch (xattr_data->type) { @@ -135,7 +158,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, if (rc) break; rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, - xattr_data->digest, xattr_len, + (const char *)xattr_data, xattr_len, calc.digest, sizeof(calc.digest)); if (!rc) { /* we probably want to replace rsa with hmac here */ @@ -258,9 +281,15 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, if ((evm_status == INTEGRITY_PASS) || (evm_status == INTEGRITY_NOXATTRS)) return 0; - return -EPERM; + goto out; } evm_status = evm_verify_current_integrity(dentry); +out: + if (evm_status != INTEGRITY_PASS) + integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode, + dentry->d_name.name, "appraise_metadata", + integrity_status_msg[evm_status], + -EPERM, 0); return evm_status == INTEGRITY_PASS ? 0 : -EPERM; } @@ -271,12 +300,20 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, * @xattr_value: pointer to the new extended attribute value * @xattr_value_len: pointer to the new extended attribute value length * - * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that - * the current value is valid. + * Before allowing the 'security.evm' protected xattr to be updated, + * verify the existing value is valid. As only the kernel should have + * access to the EVM encrypted key needed to calculate the HMAC, prevent + * userspace from writing HMAC value. Writing 'security.evm' requires + * requires CAP_SYS_ADMIN privileges. */ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { + const struct evm_ima_xattr_data *xattr_data = xattr_value; + + if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0) + && (xattr_data->type == EVM_XATTR_HMAC)) + return -EPERM; return evm_protect_xattr(dentry, xattr_name, xattr_value, xattr_value_len); } @@ -353,6 +390,9 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) if ((evm_status == INTEGRITY_PASS) || (evm_status == INTEGRITY_NOXATTRS)) return 0; + integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode, + dentry->d_name.name, "appraise_metadata", + integrity_status_msg[evm_status], -EPERM, 0); return -EPERM; } @@ -401,7 +441,7 @@ int evm_inode_init_security(struct inode *inode, evm_xattr->value = xattr_data; evm_xattr->value_len = sizeof(*xattr_data); - evm_xattr->name = kstrdup(XATTR_EVM_SUFFIX, GFP_NOFS); + evm_xattr->name = XATTR_EVM_SUFFIX; return 0; out: kfree(xattr_data); @@ -413,9 +453,11 @@ static int __init init_evm(void) { int error; + evm_init_config(); + error = evm_init_secfs(); if (error < 0) { - printk(KERN_INFO "EVM: Error registering secfs\n"); + pr_info("Error registering secfs\n"); goto err; } @@ -424,15 +466,6 @@ err: return error; } -static void __exit cleanup_evm(void) -{ - evm_cleanup_secfs(); - if (hmac_tfm) - crypto_free_shash(hmac_tfm); - if (hash_tfm) - crypto_free_shash(hash_tfm); -} - /* * evm_display_config - list the EVM protected security extended attributes */ @@ -441,7 +474,7 @@ static int __init evm_display_config(void) char **xattrname; for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) - printk(KERN_INFO "EVM: %s\n", *xattrname); + pr_info("%s\n", *xattrname); return 0; } diff --git a/security/integrity/evm/evm_posix_acl.c b/security/integrity/evm/evm_posix_acl.c index b1753e98bf9..46408b9e62e 100644 --- a/security/integrity/evm/evm_posix_acl.c +++ b/security/integrity/evm/evm_posix_acl.c @@ -11,8 +11,9 @@ #include <linux/module.h> #include <linux/xattr.h> +#include <linux/evm.h> -int posix_xattr_acl(char *xattr) +int posix_xattr_acl(const char *xattr) { int xattr_len = strlen(xattr); diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index ac762995057..cf12a04717d 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -13,6 +13,8 @@ * - Get the key and enable EVM */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/uaccess.h> #include <linux/module.h> #include "evm.h" @@ -79,9 +81,9 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf, error = evm_init_key(); if (!error) { evm_initialized = 1; - pr_info("EVM: initialized\n"); + pr_info("initialized\n"); } else - pr_err("EVM: initialization failed\n"); + pr_err("initialization failed\n"); return count; } @@ -100,9 +102,3 @@ int __init evm_init_secfs(void) error = -EFAULT; return error; } - -void __exit evm_cleanup_secfs(void) -{ - if (evm_init_tpm) - securityfs_remove(evm_init_tpm); -} |
