diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 88da0825a87275a7e2ebc95b2098afcaa1439eee..31fefc0157c543062043156dfbb84e02f26e80ca 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1737,6 +1737,15 @@ "enforce-evm" | "log-evm" } default: "enforce" + ima_appraise_digest_list= [IMA] + Format: { "digest" | "digest-nometadata" } + + digest: enables appraisal of files with digest lists + until EVM is initialized. + + digest-nometadata: enables appraisal of files with + digest lists even after EVM is initialized. + ima_appraise_tcb [IMA] Deprecated. Use ima_policy= instead. The builtin appraise policy appraises all files owned by uid=0. diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 06931466f200be4049a6c286ae90c750e201570d..a1e5b35498995c467882cea7295256cb3f36af45 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -313,7 +313,8 @@ int ima_appraise_measurement(enum ima_hooks func, struct integrity_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 xattr_len, const struct modsig *modsig, + struct ima_digest *found_digest); int ima_must_appraise(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, @@ -331,7 +332,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, - const struct modsig *modsig) + const struct modsig *modsig, + struct ima_digest *found_digest) { return INTEGRITY_UNKNOWN; } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 2e3e4c51b7aa670fd26f93e5c272b87ad88e008f..3d848e1b7e6941cc00b64f3461b4c37ab839c8ce 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -15,6 +15,7 @@ #include #include "ima.h" +#include "ima_digest_list.h" static bool ima_appraise_req_evm __ro_after_init; static int __init default_appraise_setup(char *str) @@ -52,6 +53,22 @@ static int __init default_appraise_setup(char *str) __setup("ima_appraise=", default_appraise_setup); +static bool ima_appraise_no_metadata __ro_after_init; +#ifdef CONFIG_IMA_DIGEST_LIST +static int __init appraise_digest_list_setup(char *str) +{ + if (!strncmp(str, "digest", 6)) { + ima_digest_list_actions |= IMA_APPRAISE; + + if (!strcmp(str + 6, "-nometadata")) + ima_appraise_no_metadata = true; + } + + return 1; +} +__setup("ima_appraise_digest_list=", appraise_digest_list_setup); +#endif + /* * is_ima_appraise_enabled - return appraise status * @@ -91,6 +108,9 @@ static int ima_fix_xattr(struct dentry *dentry, } else { offset = 0; iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG; + if (test_bit(IMA_DIGEST_LIST, &iint->atomic_flags)) + iint->ima_hash->xattr.ng.type = + EVM_IMA_XATTR_DIGEST_LIST; iint->ima_hash->xattr.ng.algo = algo; } rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, @@ -178,17 +198,32 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, */ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len, - enum integrity_status *status, const char **cause) + enum integrity_status *status, const char **cause, + struct ima_digest *found_digest) { int rc = -EINVAL, hash_start = 0; + if (found_digest && *status != INTEGRITY_PASS && + *status != INTEGRITY_PASS_IMMUTABLE) + set_bit(IMA_DIGEST_LIST, &iint->atomic_flags); + switch (xattr_value->type) { + case EVM_IMA_XATTR_DIGEST_LIST: + set_bit(IMA_DIGEST_LIST, &iint->atomic_flags); + + if (!ima_appraise_no_metadata) { + *cause = "IMA-xattr-untrusted"; + *status = INTEGRITY_FAIL; + break; + } + fallthrough; case IMA_XATTR_DIGEST_NG: /* first byte contains algorithm id */ hash_start = 1; fallthrough; case IMA_XATTR_DIGEST: - if (*status != INTEGRITY_PASS_IMMUTABLE) { + if (*status != INTEGRITY_PASS_IMMUTABLE && + (!found_digest || !ima_digest_is_immutable(found_digest))) { if (iint->flags & IMA_DIGSIG_REQUIRED) { *cause = "IMA-signature-required"; *status = INTEGRITY_FAIL; @@ -321,14 +356,16 @@ int ima_appraise_measurement(enum ima_hooks func, struct integrity_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 xattr_len, const struct modsig *modsig, + struct ima_digest *found_digest) { static const char op[] = "appraise_data"; const char *cause = "unknown"; struct dentry *dentry = file_dentry(file); struct inode *inode = d_backing_inode(dentry); enum integrity_status status = INTEGRITY_UNKNOWN; - int rc = xattr_len; + int rc = xattr_len, rc_evm; + char _buf[sizeof(struct evm_ima_xattr_data) + 1 + SHA512_DIGEST_SIZE]; bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig; /* If not appraising a modsig, we need an xattr. */ @@ -339,6 +376,25 @@ int ima_appraise_measurement(enum ima_hooks func, xattr_len == sizeof(struct signature_v2_hdr)) rc = -ENODATA; + if (rc == -ENODATA && found_digest && + !(file->f_mode & FMODE_CREATED)) { + struct evm_ima_xattr_data *xattr_data = NULL; + + rc_evm = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, + (char **)&xattr_data, 0, GFP_NOFS); + if (rc_evm > 0) { + kfree(xattr_data); + } else { + xattr_value = (struct evm_ima_xattr_data *)_buf; + xattr_value->type = IMA_XATTR_DIGEST_NG; + xattr_value->data[0] = found_digest->algo; + memcpy(&xattr_value->data[1], found_digest->digest, + hash_digest_size[found_digest->algo]); + xattr_len = hash_digest_size[found_digest->algo] + 2; + rc = xattr_len; + } + } + /* If reading the xattr failed and there's no modsig, error out. */ if (rc <= 0 && !try_modsig) { if (rc && rc != -ENODATA) @@ -363,7 +419,7 @@ int ima_appraise_measurement(enum ima_hooks func, break; case INTEGRITY_UNKNOWN: if (ima_appraise_req_evm && - xattr_value->type != EVM_IMA_XATTR_DIGSIG) + xattr_value->type != EVM_IMA_XATTR_DIGSIG && !found_digest) goto out; break; case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */ @@ -372,6 +428,23 @@ int ima_appraise_measurement(enum ima_hooks func, break; fallthrough; case INTEGRITY_NOLABEL: /* No security.evm xattr. */ + /* + * If the digest-nometadata mode is selected, allow access + * without metadata check. EVM will eventually create an HMAC + * based on current xattr values. + */ + if (ima_appraise_no_metadata && found_digest) + break; + /* Allow access to digest lists without metadata, only if they + * are signed or found in a digest list (immutable) + */ + if (func == DIGEST_LIST_CHECK) { + if (xattr_value->type == EVM_IMA_XATTR_DIGSIG) + break; + if (found_digest && + ima_digest_is_immutable(found_digest)) + break; + } cause = "missing-HMAC"; goto out; case INTEGRITY_FAIL_IMMUTABLE: @@ -386,7 +459,7 @@ int ima_appraise_measurement(enum ima_hooks func, if (xattr_value) rc = xattr_verify(func, iint, xattr_value, xattr_len, &status, - &cause); + &cause, found_digest); /* * If we have a modsig and either no imasig or the imasig's key isn't diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 54594b9430242154cd4ac1feec1da6f39a58ed27..bc62d94e390d4bb6fa7d27e36be8aa6eb7aa83f1 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -413,8 +413,10 @@ static int process_measurement(struct file *file, const struct cred *cred, if (rc != -EPERM) { inode_lock(inode); rc = ima_appraise_measurement(func, iint, file, - pathname, xattr_value, - xattr_len, modsig); + pathname, xattr_value, + xattr_len, modsig, + ima_digest_allow(found_digest, + IMA_APPRAISE)); inode_unlock(inode); } if (!rc) diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index f02b2aa4c81314e33ebd180e9d4e0751067dc50b..b33f6e9bb4a540ea68873baf2a5bb93c9bf64c1a 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -71,6 +71,7 @@ #define IMA_CHANGE_ATTR 2 #define IMA_DIGSIG 3 #define IMA_MUST_MEASURE 4 +#define IMA_DIGEST_LIST 5 enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01,