evm: permit only valid security.evm xattrs to be updated

In addition to requiring CAP_SYS_ADMIN permission to modify/delete
security.evm, prohibit invalid security.evm xattrs from changing,
unless in fixmode. This patch prevents inadvertent 'fixing' of
security.evm to reflect offline modifications.

Changelog v7:
- rename boot paramater 'evm_mode' to 'evm'

Reported-by: Roberto Sassu <roberto.sassu@polito.it>
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
This commit is contained in:
Mimi Zohar 2011-05-12 18:33:20 -04:00
parent 24e0198efe
commit 7102ebcd65
2 changed files with 69 additions and 14 deletions

View file

@ -48,6 +48,7 @@ parameter is applicable:
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
EFI EFI Partitioning (GPT) is enabled EFI EFI Partitioning (GPT) is enabled
EIDE EIDE/ATAPI support is enabled. EIDE EIDE/ATAPI support is enabled.
EVM Extended Verification Module
FB The frame buffer device is enabled. FB The frame buffer device is enabled.
GCOV GCOV profiling is enabled. GCOV GCOV profiling is enabled.
HW Appropriate hardware is enabled. HW Appropriate hardware is enabled.
@ -750,6 +751,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
This option is obsoleted by the "netdev=" option, which This option is obsoleted by the "netdev=" option, which
has equivalent usage. See its documentation for details. has equivalent usage. See its documentation for details.
evm= [EVM]
Format: { "fix" }
Permit 'security.evm' to be updated regardless of
current integrity status.
failslab= failslab=
fail_page_alloc= fail_page_alloc=
fail_make_request=[KNL] fail_make_request=[KNL]

View file

@ -37,13 +37,25 @@ char *evm_config_xattrnames[] = {
NULL NULL
}; };
static int evm_fixmode;
static int __init evm_set_fixmode(char *str)
{
if (strncmp(str, "fix", 3) == 0)
evm_fixmode = 1;
return 0;
}
__setup("evm=", evm_set_fixmode);
/* /*
* evm_verify_hmac - calculate and compare the HMAC with the EVM xattr * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr
* *
* Compute the HMAC on the dentry's protected set of extended attributes * Compute the HMAC on the dentry's protected set of extended attributes
* and compare it against the stored security.evm xattr. (For performance, * and compare it against the stored security.evm xattr.
* use the previoulsy retrieved xattr value and length to calculate the *
* HMAC.) * For performance:
* - use the previoulsy retrieved xattr value and length to calculate the
* HMAC.)
* - cache the verification result in the iint, when available.
* *
* Returns integrity status * Returns integrity status
*/ */
@ -54,9 +66,10 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
struct integrity_iint_cache *iint) struct integrity_iint_cache *iint)
{ {
struct evm_ima_xattr_data xattr_data; struct evm_ima_xattr_data xattr_data;
enum integrity_status evm_status;
int rc; int rc;
if (iint->evm_status == INTEGRITY_PASS) if (iint && iint->evm_status == INTEGRITY_PASS)
return iint->evm_status; return iint->evm_status;
/* if status is not PASS, try to check again - against -ENOMEM */ /* if status is not PASS, try to check again - against -ENOMEM */
@ -71,18 +84,21 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
sizeof xattr_data, GFP_NOFS); sizeof xattr_data, GFP_NOFS);
if (rc < 0) if (rc < 0)
goto err_out; goto err_out;
iint->evm_status = INTEGRITY_PASS; evm_status = INTEGRITY_PASS;
return iint->evm_status; goto out;
err_out: err_out:
switch (rc) { switch (rc) {
case -ENODATA: /* file not labelled */ case -ENODATA: /* file not labelled */
iint->evm_status = INTEGRITY_NOLABEL; evm_status = INTEGRITY_NOLABEL;
break; break;
default: default:
iint->evm_status = INTEGRITY_FAIL; evm_status = INTEGRITY_FAIL;
} }
return iint->evm_status; out:
if (iint)
iint->evm_status = evm_status;
return evm_status;
} }
static int evm_protected_xattr(const char *req_xattr_name) static int evm_protected_xattr(const char *req_xattr_name)
@ -157,6 +173,22 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
return 0; return 0;
} }
/*
* evm_verify_current_integrity - verify the dentry's metadata integrity
* @dentry: pointer to the affected dentry
*
* Verify and return the dentry's metadata integrity. The exceptions are
* before EVM is initialized or in 'fix' mode.
*/
static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
if (!evm_initialized || !S_ISREG(inode->i_mode) || evm_fixmode)
return 0;
return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
}
/** /**
* evm_inode_setxattr - protect the EVM extended attribute * evm_inode_setxattr - protect the EVM extended attribute
* @dentry: pointer to the affected dentry * @dentry: pointer to the affected dentry
@ -164,13 +196,22 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
* @xattr_value: pointer to the new extended attribute value * @xattr_value: pointer to the new extended attribute value
* @xattr_value_len: pointer to the new extended attribute value length * @xattr_value_len: pointer to the new extended attribute value length
* *
* Prevent 'security.evm' from being modified * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that
* the current value is valid.
*/ */
int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len) const void *xattr_value, size_t xattr_value_len)
{ {
return evm_protect_xattr(dentry, xattr_name, xattr_value,
xattr_value_len); enum integrity_status evm_status;
int ret;
ret = evm_protect_xattr(dentry, xattr_name, xattr_value,
xattr_value_len);
if (ret)
return ret;
evm_status = evm_verify_current_integrity(dentry);
return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
} }
/** /**
@ -178,11 +219,19 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
* @dentry: pointer to the affected dentry * @dentry: pointer to the affected dentry
* @xattr_name: pointer to the affected extended attribute name * @xattr_name: pointer to the affected extended attribute name
* *
* Prevent 'security.evm' from being removed. * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
* the current value is valid.
*/ */
int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{ {
return evm_protect_xattr(dentry, xattr_name, NULL, 0); enum integrity_status evm_status;
int ret;
ret = evm_protect_xattr(dentry, xattr_name, NULL, 0);
if (ret)
return ret;
evm_status = evm_verify_current_integrity(dentry);
return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
} }
/** /**