summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Kasatkin <dmitry.kasatkin@intel.com>2011-08-31 14:07:06 +0300
committerMimi Zohar <zohar@linux.vnet.ibm.com>2012-09-07 14:57:48 -0400
commit8606404fa555c2ee691376fcc640ab89fe752035 (patch)
tree4b2d2e43b7ad196b46757faff10d04803381a543
parent5a44b41207174e1882ce0c24a752f4cfb65dab07 (diff)
downloadlinux-8606404fa555c2ee691376fcc640ab89fe752035.tar.gz
linux-8606404fa555c2ee691376fcc640ab89fe752035.tar.bz2
linux-8606404fa555c2ee691376fcc640ab89fe752035.zip
ima: digital signature verification support
This patch adds support for digital signature based integrity appraisal. With this patch, 'security.ima' contains either the file data hash or a digital signature of the file data hash. The file data hash provides the security attribute of file integrity. In addition to file integrity, a digital signature provides the security attribute of authenticity. Unlike EVM, when the file metadata changes, the digital signature is replaced with an HMAC, modification of the file data does not cause the 'security.ima' digital signature to be replaced with a hash. As a result, after any modification, subsequent file integrity appraisals would fail. Although digitally signed files can be modified, but by not updating 'security.ima' to reflect these modifications, in essence digitally signed files could be considered 'immutable'. IMA uses a different keyring than EVM. While the EVM keyring should not be updated after initialization and locked, the IMA keyring should allow updating or adding new keys when upgrading or installing packages. Changelog v4: - Change IMA_DIGSIG to hex equivalent Changelog v3: - Permit files without any 'security.ima' xattr to be labeled properly. Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
-rw-r--r--security/integrity/ima/ima_appraise.c70
-rw-r--r--security/integrity/integrity.h1
2 files changed, 52 insertions, 19 deletions
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index f9979976aa5d..4cdf36ad884a 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -63,7 +63,7 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint,
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
- struct evm_ima_xattr_data xattr_value;
+ struct evm_ima_xattr_data *xattr_value = NULL;
enum integrity_status status = INTEGRITY_UNKNOWN;
const char *op = "appraise_data";
char *cause = "unknown";
@@ -77,8 +77,8 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint,
if (iint->flags & IMA_APPRAISED)
return iint->ima_status;
- rc = inode->i_op->getxattr(dentry, XATTR_NAME_IMA, (u8 *)&xattr_value,
- sizeof xattr_value);
+ rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value,
+ 0, GFP_NOFS);
if (rc <= 0) {
if (rc && rc != -ENODATA)
goto out;
@@ -89,8 +89,7 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint,
goto out;
}
- status = evm_verifyxattr(dentry, XATTR_NAME_IMA, (u8 *)&xattr_value,
- rc, iint);
+ status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) {
if ((status == INTEGRITY_NOLABEL)
|| (status == INTEGRITY_NOXATTRS))
@@ -100,30 +99,58 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint,
goto out;
}
- rc = memcmp(xattr_value.digest, iint->ima_xattr.digest,
- IMA_DIGEST_SIZE);
- if (rc) {
- status = INTEGRITY_FAIL;
- cause = "invalid-hash";
- print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE,
- &xattr_value, sizeof xattr_value);
- print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE,
- (u8 *)&iint->ima_xattr,
- sizeof iint->ima_xattr);
- goto out;
+ switch (xattr_value->type) {
+ case IMA_XATTR_DIGEST:
+ rc = memcmp(xattr_value->digest, iint->ima_xattr.digest,
+ IMA_DIGEST_SIZE);
+ if (rc) {
+ cause = "invalid-hash";
+ status = INTEGRITY_FAIL;
+ print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE,
+ xattr_value, sizeof(*xattr_value));
+ print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE,
+ (u8 *)&iint->ima_xattr,
+ sizeof iint->ima_xattr);
+ break;
+ }
+ status = INTEGRITY_PASS;
+ break;
+ case EVM_IMA_XATTR_DIGSIG:
+ iint->flags |= IMA_DIGSIG;
+ rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
+ xattr_value->digest, rc - 1,
+ iint->ima_xattr.digest,
+ IMA_DIGEST_SIZE);
+ if (rc == -EOPNOTSUPP) {
+ status = INTEGRITY_UNKNOWN;
+ } else if (rc) {
+ cause = "invalid-signature";
+ status = INTEGRITY_FAIL;
+ } else {
+ status = INTEGRITY_PASS;
+ }
+ break;
+ default:
+ status = INTEGRITY_UNKNOWN;
+ cause = "unknown-ima-data";
+ break;
}
- status = INTEGRITY_PASS;
- iint->flags |= IMA_APPRAISED;
+
out:
if (status != INTEGRITY_PASS) {
- if (ima_appraise & IMA_APPRAISE_FIX) {
+ if ((ima_appraise & IMA_APPRAISE_FIX) &&
+ (!xattr_value ||
+ xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
ima_fix_xattr(dentry, iint);
status = INTEGRITY_PASS;
}
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
op, cause, rc, 0);
+ } else {
+ iint->flags |= IMA_APPRAISED;
}
iint->ima_status = status;
+ kfree(xattr_value);
return status;
}
@@ -135,9 +162,14 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
struct dentry *dentry = file->f_dentry;
int rc = 0;
+ /* do not collect and update hash for digital signatures */
+ if (iint->flags & IMA_DIGSIG)
+ return;
+
rc = ima_collect_measurement(iint, file);
if (rc < 0)
return;
+
ima_fix_xattr(dentry, iint);
}
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 91ccef1c704b..4eec1b14193e 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -21,6 +21,7 @@
#define IMA_APPRAISE 0x04
#define IMA_APPRAISED 0x08
#define IMA_COLLECTED 0x10
+#define IMA_DIGSIG 0x20
enum evm_ima_xattr_type {
IMA_XATTR_DIGEST = 0x01,