Skip to content

Commit

Permalink
ima: integrity appraisal extension
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mimi Zohar committed Sep 7, 2012
1 parent 4199d35 commit 2fe5d6d
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 53 deletions.
4 changes: 4 additions & 0 deletions Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
ihash_entries= [KNL]
Set number of hash buckets for inode cache.

ima_appraise= [IMA] appraise integrity measurements
Format: { "off" | "enforce" | "fix" }
default: "enforce"

ima_audit= [IMA]
Format: { "0" | "1" }
0 -- integrity auditing messages. (Default)
Expand Down
3 changes: 3 additions & 0 deletions include/linux/xattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#define XATTR_EVM_SUFFIX "evm"
#define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX

#define XATTR_IMA_SUFFIX "ima"
#define XATTR_NAME_IMA XATTR_SECURITY_PREFIX XATTR_IMA_SUFFIX

#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX

Expand Down
3 changes: 3 additions & 0 deletions security/integrity/evm/evm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ char *evm_config_xattrnames[] = {
#endif
#ifdef CONFIG_SECURITY_SMACK
XATTR_NAME_SMACK,
#endif
#ifdef CONFIG_IMA_APPRAISE
XATTR_NAME_IMA,
#endif
XATTR_NAME_CAPS,
NULL
Expand Down
3 changes: 2 additions & 1 deletion security/integrity/iint.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ static void iint_free(struct integrity_iint_cache *iint)
{
iint->version = 0;
iint->flags = 0UL;
iint->ima_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
kmem_cache_free(iint_cache, iint);
}
Expand Down Expand Up @@ -157,7 +158,7 @@ static void init_once(void *foo)
memset(iint, 0, sizeof *iint);
iint->version = 0;
iint->flags = 0UL;
mutex_init(&iint->mutex);
iint->ima_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
}

Expand Down
15 changes: 15 additions & 0 deletions security/integrity/ima/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,18 @@ config IMA_LSM_RULES
default y
help
Disabling this option will disregard LSM based policy rules.

config IMA_APPRAISE
bool "Appraise integrity measurements"
depends on IMA
default n
help
This option enables local measurement integrity appraisal.
It requires the system to be labeled with a security extended
attribute containing the file hash measurement. To protect
the security extended attributes from offline attack, enable
and configure EVM.

For more information on integrity appraisal refer to:
<http://linux-ima.sourceforge.net>
If unsure, say N.
1 change: 1 addition & 0 deletions security/integrity/ima/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ obj-$(CONFIG_IMA) += ima.o
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
ima_policy.o
ima-$(CONFIG_IMA_AUDIT) += ima_audit.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
37 changes: 35 additions & 2 deletions security/integrity/ima/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
extern int ima_initialized;
extern int ima_used_chip;
extern char *ima_hash;
extern int ima_appraise;

/* IMA inode template definition */
struct ima_template_data {
Expand Down Expand Up @@ -107,6 +108,7 @@ static inline unsigned long ima_hash_key(u8 *digest)
}

/* LIM API function definitions */
int ima_must_appraise_or_measure(struct inode *inode, int mask, int function);
int ima_must_measure(struct inode *inode, int mask, int function);
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file);
Expand All @@ -123,14 +125,45 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);

/* IMA policy related functions */
enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK };
enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR };

int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask);
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags);
void ima_init_policy(void);
void ima_update_policy(void);
ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);

/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
#define IMA_APPRAISE_FIX 0x02

#ifdef CONFIG_IMA_APPRAISE
int ima_appraise_measurement(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename);
int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);

#else
static inline int ima_appraise_measurement(struct integrity_iint_cache *iint,
struct file *file,
const unsigned char *filename)
{
return INTEGRITY_UNKNOWN;
}

static inline int ima_must_appraise(struct inode *inode,
enum ima_hooks func, int mask)
{
return 0;
}

static inline void ima_update_xattr(struct integrity_iint_cache *iint,
struct file *file)
{
}
#endif

/* LSM based policy rules require audit */
#ifdef CONFIG_IMA_LSM_RULES

Expand Down
50 changes: 36 additions & 14 deletions security/integrity/ima/ima_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
* License.
*
* File: ima_api.c
* Implements must_measure, collect_measurement, store_measurement,
* and store_template.
* Implements must_appraise_or_measure, collect_measurement,
* appraise_measurement, store_measurement and store_template.
*/
#include <linux/module.h>
#include <linux/slab.h>

#include <linux/file.h>
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/evm.h>
#include "ima.h"

static const char *IMA_TEMPLATE_NAME = "ima";

/*
Expand Down Expand Up @@ -93,7 +97,7 @@ void ima_add_violation(struct inode *inode, const unsigned char *filename,
}

/**
* ima_must_measure - measure decision based on policy.
* ima_must_appraise_or_measure - appraise & measure decision based on policy.
* @inode: pointer to inode to measure
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
* @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP)
Expand All @@ -105,15 +109,22 @@ void ima_add_violation(struct inode *inode, const unsigned char *filename,
* mask: contains the permission mask
* fsmagic: hex value
*
* Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
* or other error, return an error code.
*/
int ima_must_measure(struct inode *inode, int mask, int function)
* Returns IMA_MEASURE, IMA_APPRAISE mask.
*
*/
int ima_must_appraise_or_measure(struct inode *inode, int mask, int function)
{
int must_measure;
int flags = IMA_MEASURE | IMA_APPRAISE;

if (!ima_appraise)
flags &= ~IMA_APPRAISE;

return ima_match_policy(inode, function, mask, flags);
}

must_measure = ima_match_policy(inode, function, mask);
return must_measure ? 0 : -EACCES;
int ima_must_measure(struct inode *inode, int mask, int function)
{
return ima_match_policy(inode, function, mask, IMA_MEASURE);
}

/*
Expand All @@ -129,16 +140,24 @@ int ima_must_measure(struct inode *inode, int mask, int function)
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file)
{
int result = -EEXIST;
struct inode *inode = file->f_dentry->d_inode;
const char *filename = file->f_dentry->d_name.name;
int result = 0;

if (!(iint->flags & IMA_MEASURED)) {
if (!(iint->flags & IMA_COLLECTED)) {
u64 i_version = file->f_dentry->d_inode->i_version;

memset(iint->digest, 0, IMA_DIGEST_SIZE);
result = ima_calc_hash(file, iint->digest);
if (!result)
if (!result) {
iint->version = i_version;
iint->flags |= IMA_COLLECTED;
}
}
if (result)
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
filename, "collect_data", "failed",
result, 0);
return result;
}

Expand Down Expand Up @@ -167,6 +186,9 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
struct ima_template_entry *entry;
int violation = 0;

if (iint->flags & IMA_MEASURED)
return;

entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
Expand Down
Loading

0 comments on commit 2fe5d6d

Please sign in to comment.