Commit a5fbeb61 authored by Thiago Jung Bauermann's avatar Thiago Jung Bauermann Committed by Mimi Zohar

ima: Factor xattr_verify() out of ima_appraise_measurement()

Verify xattr signature in a separate function so that the logic in
ima_appraise_measurement() remains clear when it gains the ability to also
verify an appended module signature.

The code in the switch statement is unchanged except for having to
dereference the status and cause variables (since they're now pointers),
and fixing the style of a block comment to appease checkpatch.
Suggested-by: default avatarMimi Zohar <zohar@linux.ibm.com>
Signed-off-by: default avatarThiago Jung Bauermann <bauerman@linux.ibm.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
parent 9044d627
...@@ -199,6 +199,83 @@ int ima_read_xattr(struct dentry *dentry, ...@@ -199,6 +199,83 @@ int ima_read_xattr(struct dentry *dentry,
return ret; return ret;
} }
/*
* xattr_verify - verify xattr digest or signature
*
* Verify whether the hash or signature matches the file contents.
*
* Return 0 on success, error code otherwise.
*/
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)
{
int rc = -EINVAL, hash_start = 0;
switch (xattr_value->type) {
case IMA_XATTR_DIGEST_NG:
/* first byte contains algorithm id */
hash_start = 1;
/* fall through */
case IMA_XATTR_DIGEST:
if (iint->flags & IMA_DIGSIG_REQUIRED) {
*cause = "IMA-signature-required";
*status = INTEGRITY_FAIL;
break;
}
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
iint->ima_hash->length)
/*
* xattr length may be longer. md5 hash in previous
* version occupied 20 bytes in xattr, instead of 16
*/
rc = memcmp(&xattr_value->data[hash_start],
iint->ima_hash->digest,
iint->ima_hash->length);
else
rc = -EINVAL;
if (rc) {
*cause = "invalid-hash";
*status = INTEGRITY_FAIL;
break;
}
*status = INTEGRITY_PASS;
break;
case EVM_IMA_XATTR_DIGSIG:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value,
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length);
if (rc == -EOPNOTSUPP) {
*status = INTEGRITY_UNKNOWN;
break;
}
if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
func == KEXEC_KERNEL_CHECK)
rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
(const char *)xattr_value,
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length);
if (rc) {
*cause = "invalid-signature";
*status = INTEGRITY_FAIL;
} else {
*status = INTEGRITY_PASS;
}
break;
default:
*status = INTEGRITY_UNKNOWN;
*cause = "unknown-ima-data";
break;
}
return rc;
}
/* /*
* ima_appraise_measurement - appraise file measurement * ima_appraise_measurement - appraise file measurement
* *
...@@ -218,7 +295,7 @@ int ima_appraise_measurement(enum ima_hooks func, ...@@ -218,7 +295,7 @@ int ima_appraise_measurement(enum ima_hooks func,
struct dentry *dentry = file_dentry(file); struct dentry *dentry = file_dentry(file);
struct inode *inode = d_backing_inode(dentry); struct inode *inode = d_backing_inode(dentry);
enum integrity_status status = INTEGRITY_UNKNOWN; enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0; int rc = xattr_len;
if (!(inode->i_opflags & IOP_XATTR)) if (!(inode->i_opflags & IOP_XATTR))
return INTEGRITY_UNKNOWN; return INTEGRITY_UNKNOWN;
...@@ -256,65 +333,9 @@ int ima_appraise_measurement(enum ima_hooks func, ...@@ -256,65 +333,9 @@ int ima_appraise_measurement(enum ima_hooks func,
WARN_ONCE(true, "Unexpected integrity status %d\n", status); WARN_ONCE(true, "Unexpected integrity status %d\n", status);
} }
switch (xattr_value->type) { if (xattr_value)
case IMA_XATTR_DIGEST_NG: rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
/* first byte contains algorithm id */ &cause);
hash_start = 1;
/* fall through */
case IMA_XATTR_DIGEST:
if (iint->flags & IMA_DIGSIG_REQUIRED) {
cause = "IMA-signature-required";
status = INTEGRITY_FAIL;
break;
}
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
iint->ima_hash->length)
/* xattr length may be longer. md5 hash in previous
version occupied 20 bytes in xattr, instead of 16
*/
rc = memcmp(&xattr_value->data[hash_start],
iint->ima_hash->digest,
iint->ima_hash->length);
else
rc = -EINVAL;
if (rc) {
cause = "invalid-hash";
status = INTEGRITY_FAIL;
break;
}
status = INTEGRITY_PASS;
break;
case EVM_IMA_XATTR_DIGSIG:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value,
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length);
if (rc == -EOPNOTSUPP) {
status = INTEGRITY_UNKNOWN;
break;
}
if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
func == KEXEC_KERNEL_CHECK)
rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
(const char *)xattr_value,
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length);
if (rc) {
cause = "invalid-signature";
status = INTEGRITY_FAIL;
} else {
status = INTEGRITY_PASS;
}
break;
default:
status = INTEGRITY_UNKNOWN;
cause = "unknown-ima-data";
break;
}
out: out:
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment