|
From: Mikhail K. <vie...@vi...> - 2017-01-05 21:42:10
|
version 2 changes:
1) evm_verify_hmac() prevent work with EVM portable signature. If file signed by EVM portable signature, evm_verify_hmac() return INTEGRITY_FAIL;
2) evm_inode_post_setxattr() now count on EVM portable signature.
If EVM digsig verification is ok - update securety.evm in order to have HMAC.
If EVM digsig verification fail, sign file with zero-filled EVM signature, we should have INTEGRITY_FAIL return from evm_verify_hmac() on next call for sure. Remove EVM signature in this case not enought, since in this case evm_verify_hmac() could return INTEGRITY_NOLABEL or INTEGRITY_NOXATTRS.
Patch could be tested evmctl with "i" flag.
Warning about usage: EVM portable signature should be used with patched archiver, that will add "security.evm" xattr after all xattrs are added to the file during unpack. I tested with "security.evm"+"security.ima" and it's working fine with tar default code, but "security.capability"+"security.evm"+"security.ima" fail because "security.evm" added before "security.capability".
Signed-off-by: Dmitry Kasatkin <d.k...@sa...>
Signed-off-by: Mikhail Kurinnoi <vie...@vi...>
--- a/security/integrity/digsig.c 2016-12-31 13:06:26.331828091 +0300
+++ b/security/integrity/digsig.c 2017-01-05 23:33:23.614541837 +0300
@@ -71,6 +71,7 @@ int integrity_digsig_verify(const unsign
return digsig_verify(keyring[id], sig + 1, siglen - 1,
digest, digestlen);
case 2:
+ case 3:
return asymmetric_verify(keyring[id], sig, siglen,
digest, digestlen);
}
--- a/security/integrity/evm/evm_crypto.c 2016-12-31 13:06:26.331828091 +0300
+++ b/security/integrity/evm/evm_crypto.c 2017-01-05 23:35:48.577389813 +0300
@@ -169,6 +169,23 @@ static void hmac_add_misc(struct shash_d
crypto_shash_final(desc, digest);
}
+static void hmac_add_misc_portable_digsig(struct shash_desc *desc, struct inode *inode,
+ char *digest)
+{
+ struct h_misc {
+ uid_t uid;
+ gid_t gid;
+ umode_t mode;
+ } hmac_misc;
+
+ memset(&hmac_misc, 0, sizeof(hmac_misc));
+ 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_final(desc, digest);
+}
+
/*
* Calculate the HMAC value across the set of protected security xattrs.
*
@@ -219,7 +236,10 @@ static int evm_calc_hmac_or_hash(struct
xattr_size = size;
crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
}
- hmac_add_misc(desc, inode, digest);
+ if (type == EVM_IMA_XATTR_DIGSIG)
+ hmac_add_misc_portable_digsig(desc, inode, digest);
+ else
+ hmac_add_misc(desc, inode, digest);
out:
kfree(xattr_value);
@@ -237,10 +257,12 @@ int evm_calc_hmac(struct dentry *dentry,
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 version, char *digest)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
- req_xattr_value_len, IMA_XATTR_DIGEST, digest);
+ req_xattr_value_len,
+ version == 3 ? EVM_IMA_XATTR_DIGSIG : IMA_XATTR_DIGEST,
+ digest);
}
/*
--- a/security/integrity/evm/evm.h 2016-11-29 01:32:07.248219481 +0300
+++ b/security/integrity/evm/evm.h 2017-01-05 23:34:06.551383033 +0300
@@ -48,7 +48,7 @@ int evm_calc_hmac(struct dentry *dentry,
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);
+ size_t req_xattr_value_len, int version, char *digest);
int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
char *hmac_val);
int evm_init_secfs(void);
--- a/security/integrity/evm/evm_main.c 2016-12-31 13:06:26.331828091 +0300
+++ b/security/integrity/evm/evm_main.c 2017-01-05 23:37:07.266943910 +0300
@@ -116,7 +116,7 @@ static enum integrity_status evm_verify_
struct evm_ima_xattr_data *xattr_data = NULL;
struct evm_ima_xattr_data calc;
enum integrity_status evm_status = INTEGRITY_PASS;
- int rc, xattr_len;
+ int rc, xattr_len, version;
if (iint && iint->evm_status == INTEGRITY_PASS)
return iint->evm_status;
@@ -159,8 +159,11 @@ static enum integrity_status evm_verify_
rc = -EINVAL;
break;
case EVM_IMA_XATTR_DIGSIG:
+ version = ((const char *)xattr_data)[1];
+ if (version == 3)
+ break;
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
- xattr_value_len, calc.digest);
+ xattr_value_len, version, calc.digest);
if (rc)
break;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
@@ -372,6 +375,44 @@ static void evm_reset_status(struct inod
iint->evm_status = INTEGRITY_UNKNOWN;
}
+void evm_update_portable_digsig(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;
+ struct evm_ima_xattr_data calc;
+ struct evm_ima_xattr_data xattr_data_fail;
+ int version, rc;
+
+ if ((xattr_data->type != EVM_IMA_XATTR_DIGSIG) || \
+ (strcmp(xattr_name, XATTR_NAME_EVM) != 0))
+ return;
+
+ version = ((const char *)xattr_data)[1];
+ if (version != 3)
+ return;
+
+ evm_reset_status(dentry->d_inode);
+
+ rc = evm_calc_hash(dentry, xattr_name, xattr_value,
+ xattr_value_len, version, calc.digest);
+ if (rc)
+ goto digsig_fail;
+ rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
+ (const char *)xattr_data, xattr_value_len,
+ calc.digest, sizeof(calc.digest));
+ if (rc)
+ goto digsig_fail;
+
+ evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
+ return;
+
+digsig_fail:
+ memset(&xattr_data_fail, 0, sizeof(xattr_data_fail));
+ __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
+ &xattr_data_fail,
+ sizeof(xattr_data_fail), 0);
+}
+
/**
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
* @dentry: pointer to the affected dentry
@@ -388,8 +429,12 @@ static void evm_reset_status(struct inod
void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len)
{
- if (!evm_initialized || (!evm_protected_xattr(xattr_name)
- && !posix_xattr_acl(xattr_name)))
+ if (!evm_initialized)
+ return;
+
+ evm_update_portable_digsig(dentry, xattr_name, xattr_value, xattr_value_len);
+
+ if (!evm_protected_xattr(xattr_name) && !posix_xattr_acl(xattr_name))
return;
evm_reset_status(dentry->d_inode);
|