ima: integrity appraisal extension
IMA currently maintains an integrity measurement list used to assert the
integrity of the running system to a third party. The IMA-appraisal
extension adds local integrity validation and enforcement of the
measurement against a "good" value stored as an extended attribute
'security.ima'. The initial methods for validating 'security.ima' are
hashed based, which provides file data integrity, and digital signature
based, which in addition to providing file data integrity, provides
authenticity.
This patch creates and maintains the 'security.ima' xattr, containing
the file data hash measurement. Protection of the xattr is provided by
EVM, if enabled and configured.
Based on policy, IMA calls evm_verifyxattr() to verify a file's metadata
integrity and, assuming success, compares the file's current hash value
with the one stored as an extended attribute in 'security.ima'.
Changelov v4:
- changed iint cache flags to hex values
Changelog v3:
- change appraisal default for filesystems without xattr support to fail
Changelog v2:
- fix audit msg 'res' value
- removed unused 'ima_appraise=' values
Changelog v1:
- removed unused iint mutex (Dmitry Kasatkin)
- setattr hook must not reset appraised (Dmitry Kasatkin)
- evm_verifyxattr() now differentiates between no 'security.evm' xattr
(INTEGRITY_NOLABEL) and no EVM 'protected' xattrs included in the
'security.evm' (INTEGRITY_NOXATTRS).
- replace hash_status with ima_status (Dmitry Kasatkin)
- re-initialize slab element ima_status on free (Dmitry Kasatkin)
- include 'security.ima' in EVM if CONFIG_IMA_APPRAISE, not CONFIG_IMA
- merged half "ima: ima_must_appraise_or_measure API change" (Dmitry Kasatkin)
- removed unnecessary error variable in process_measurement() (Dmitry Kasatkin)
- use ima_inode_post_setattr() stub function, if IMA_APPRAISE not configured
(moved ima_inode_post_setattr() to ima_appraise.c)
- make sure ima_collect_measurement() can read file
Changelog:
- add 'iint' to evm_verifyxattr() call (Dimitry Kasatkin)
- fix the race condition between chmod, which takes the i_mutex and then
iint->mutex, and ima_file_free() and process_measurement(), which take
the locks in the reverse order, by eliminating iint->mutex. (Dmitry Kasatkin)
- cleanup of ima_appraise_measurement() (Dmitry Kasatkin)
- changes as a result of the iint not allocated for all regular files, but
only for those measured/appraised.
- don't try to appraise new/empty files
- expanded ima_appraisal description in ima/Kconfig
- IMA appraise definitions required even if IMA_APPRAISE not enabled
- add return value to ima_must_appraise() stub
- unconditionally set status = INTEGRITY_PASS *after* testing status,
not before. (Found by Joe Perches)
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-02-13 22:15:05 +07:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2011 IBM Corporation
|
|
|
|
*
|
|
|
|
* Author:
|
|
|
|
* Mimi Zohar <zohar@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, version 2 of the License.
|
|
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/file.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/xattr.h>
|
|
|
|
#include <linux/magic.h>
|
|
|
|
#include <linux/ima.h>
|
|
|
|
#include <linux/evm.h>
|
|
|
|
|
|
|
|
#include "ima.h"
|
|
|
|
|
|
|
|
static int __init default_appraise_setup(char *str)
|
|
|
|
{
|
|
|
|
if (strncmp(str, "off", 3) == 0)
|
|
|
|
ima_appraise = 0;
|
|
|
|
else if (strncmp(str, "fix", 3) == 0)
|
|
|
|
ima_appraise = IMA_APPRAISE_FIX;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
__setup("ima_appraise=", default_appraise_setup);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ima_must_appraise - set appraise flag
|
|
|
|
*
|
|
|
|
* Return 1 to appraise
|
|
|
|
*/
|
|
|
|
int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask)
|
|
|
|
{
|
ima: add appraise action keywords and default rules
Unlike the IMA measurement policy, the appraise policy can not be dependent
on runtime process information, such as the task uid, as the 'security.ima'
xattr is written on file close and must be updated each time the file changes,
regardless of the current task uid.
This patch extends the policy language with 'fowner', defines an appraise
policy, which appraises all files owned by root, and defines 'ima_appraise_tcb',
a new boot command line option, to enable the appraise policy.
Changelog v3:
- separate the measure from the appraise rules in order to support measuring
without appraising and appraising without measuring.
- change appraisal default for filesystems without xattr support to fail
- update default appraise policy for cgroups
Changelog v1:
- don't appraise RAMFS (Dmitry Kasatkin)
- merged rest of "ima: ima_must_appraise_or_measure API change" commit
(Dmtiry Kasatkin)
ima_must_appraise_or_measure() called ima_match_policy twice, which
searched the policy for a matching rule. Once for a matching measurement
rule and subsequently for an appraisal rule. Searching the policy twice
is unnecessary overhead, which could be noticeable with a large policy.
The new version of ima_must_appraise_or_measure() does everything in a
single iteration using a new version of ima_match_policy(). It returns
IMA_MEASURE, IMA_APPRAISE mask.
With the use of action mask only one efficient matching function
is enough. Removed other specific versions of matching functions.
Changelog:
- change 'owner' to 'fowner' to conform to the new LSM conditions posted by
Roberto Sassu.
- fix calls to ima_log_string()
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2011-03-10 10:25:48 +07:00
|
|
|
if (!ima_appraise)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return ima_match_policy(inode, func, mask, IMA_APPRAISE);
|
ima: integrity appraisal extension
IMA currently maintains an integrity measurement list used to assert the
integrity of the running system to a third party. The IMA-appraisal
extension adds local integrity validation and enforcement of the
measurement against a "good" value stored as an extended attribute
'security.ima'. The initial methods for validating 'security.ima' are
hashed based, which provides file data integrity, and digital signature
based, which in addition to providing file data integrity, provides
authenticity.
This patch creates and maintains the 'security.ima' xattr, containing
the file data hash measurement. Protection of the xattr is provided by
EVM, if enabled and configured.
Based on policy, IMA calls evm_verifyxattr() to verify a file's metadata
integrity and, assuming success, compares the file's current hash value
with the one stored as an extended attribute in 'security.ima'.
Changelov v4:
- changed iint cache flags to hex values
Changelog v3:
- change appraisal default for filesystems without xattr support to fail
Changelog v2:
- fix audit msg 'res' value
- removed unused 'ima_appraise=' values
Changelog v1:
- removed unused iint mutex (Dmitry Kasatkin)
- setattr hook must not reset appraised (Dmitry Kasatkin)
- evm_verifyxattr() now differentiates between no 'security.evm' xattr
(INTEGRITY_NOLABEL) and no EVM 'protected' xattrs included in the
'security.evm' (INTEGRITY_NOXATTRS).
- replace hash_status with ima_status (Dmitry Kasatkin)
- re-initialize slab element ima_status on free (Dmitry Kasatkin)
- include 'security.ima' in EVM if CONFIG_IMA_APPRAISE, not CONFIG_IMA
- merged half "ima: ima_must_appraise_or_measure API change" (Dmitry Kasatkin)
- removed unnecessary error variable in process_measurement() (Dmitry Kasatkin)
- use ima_inode_post_setattr() stub function, if IMA_APPRAISE not configured
(moved ima_inode_post_setattr() to ima_appraise.c)
- make sure ima_collect_measurement() can read file
Changelog:
- add 'iint' to evm_verifyxattr() call (Dimitry Kasatkin)
- fix the race condition between chmod, which takes the i_mutex and then
iint->mutex, and ima_file_free() and process_measurement(), which take
the locks in the reverse order, by eliminating iint->mutex. (Dmitry Kasatkin)
- cleanup of ima_appraise_measurement() (Dmitry Kasatkin)
- changes as a result of the iint not allocated for all regular files, but
only for those measured/appraised.
- don't try to appraise new/empty files
- expanded ima_appraisal description in ima/Kconfig
- IMA appraise definitions required even if IMA_APPRAISE not enabled
- add return value to ima_must_appraise() stub
- unconditionally set status = INTEGRITY_PASS *after* testing status,
not before. (Found by Joe Perches)
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-02-13 22:15:05 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ima_fix_xattr(struct dentry *dentry,
|
|
|
|
struct integrity_iint_cache *iint)
|
|
|
|
{
|
|
|
|
iint->digest[0] = IMA_XATTR_DIGEST;
|
|
|
|
__vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
|
|
|
|
iint->digest, IMA_DIGEST_SIZE + 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ima_appraise_measurement - appraise file measurement
|
|
|
|
*
|
|
|
|
* Call evm_verifyxattr() to verify the integrity of 'security.ima'.
|
|
|
|
* Assuming success, compare the xattr hash with the collected measurement.
|
|
|
|
*
|
|
|
|
* Return 0 on success, error code otherwise
|
|
|
|
*/
|
|
|
|
int ima_appraise_measurement(struct integrity_iint_cache *iint,
|
|
|
|
struct file *file, const unsigned char *filename)
|
|
|
|
{
|
|
|
|
struct dentry *dentry = file->f_dentry;
|
|
|
|
struct inode *inode = dentry->d_inode;
|
|
|
|
u8 xattr_value[IMA_DIGEST_SIZE];
|
|
|
|
enum integrity_status status = INTEGRITY_UNKNOWN;
|
|
|
|
const char *op = "appraise_data";
|
|
|
|
char *cause = "unknown";
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!ima_appraise)
|
|
|
|
return 0;
|
|
|
|
if (!inode->i_op->getxattr)
|
|
|
|
return INTEGRITY_UNKNOWN;
|
|
|
|
|
|
|
|
if (iint->flags & IMA_APPRAISED)
|
|
|
|
return iint->ima_status;
|
|
|
|
|
|
|
|
rc = inode->i_op->getxattr(dentry, XATTR_NAME_IMA, xattr_value,
|
|
|
|
IMA_DIGEST_SIZE);
|
|
|
|
if (rc <= 0) {
|
|
|
|
if (rc && rc != -ENODATA)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
cause = "missing-hash";
|
|
|
|
status =
|
|
|
|
(inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
cause = "missing-HMAC";
|
|
|
|
else if (status == INTEGRITY_FAIL)
|
|
|
|
cause = "invalid-HMAC";
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = memcmp(xattr_value, iint->digest, IMA_DIGEST_SIZE);
|
|
|
|
if (rc) {
|
|
|
|
status = INTEGRITY_FAIL;
|
|
|
|
cause = "invalid-hash";
|
|
|
|
print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE,
|
|
|
|
xattr_value, IMA_DIGEST_SIZE);
|
|
|
|
print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE,
|
|
|
|
iint->digest, IMA_DIGEST_SIZE);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
status = INTEGRITY_PASS;
|
|
|
|
iint->flags |= IMA_APPRAISED;
|
|
|
|
out:
|
|
|
|
if (status != INTEGRITY_PASS) {
|
|
|
|
if (ima_appraise & IMA_APPRAISE_FIX) {
|
|
|
|
ima_fix_xattr(dentry, iint);
|
|
|
|
status = INTEGRITY_PASS;
|
|
|
|
}
|
|
|
|
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
|
|
|
|
op, cause, rc, 0);
|
|
|
|
}
|
|
|
|
iint->ima_status = status;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ima_update_xattr - update 'security.ima' hash value
|
|
|
|
*/
|
|
|
|
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
|
|
|
|
{
|
|
|
|
struct dentry *dentry = file->f_dentry;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
rc = ima_collect_measurement(iint, file);
|
|
|
|
if (rc < 0)
|
|
|
|
return;
|
|
|
|
ima_fix_xattr(dentry, iint);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ima_inode_post_setattr - reflect file metadata changes
|
|
|
|
* @dentry: pointer to the affected dentry
|
|
|
|
*
|
|
|
|
* Changes to a dentry's metadata might result in needing to appraise.
|
|
|
|
*
|
|
|
|
* This function is called from notify_change(), which expects the caller
|
|
|
|
* to lock the inode's i_mutex.
|
|
|
|
*/
|
|
|
|
void ima_inode_post_setattr(struct dentry *dentry)
|
|
|
|
{
|
|
|
|
struct inode *inode = dentry->d_inode;
|
|
|
|
struct integrity_iint_cache *iint;
|
|
|
|
int must_appraise, rc;
|
|
|
|
|
|
|
|
if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)
|
|
|
|
|| !inode->i_op->removexattr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
|
|
|
|
iint = integrity_iint_find(inode);
|
|
|
|
if (iint) {
|
|
|
|
if (must_appraise)
|
|
|
|
iint->flags |= IMA_APPRAISE;
|
|
|
|
else
|
|
|
|
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED);
|
|
|
|
}
|
|
|
|
if (!must_appraise)
|
|
|
|
rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA);
|
|
|
|
return;
|
|
|
|
}
|