On Wed, Mar 21, 2012 at 8:54 PM, Mimi Zohar <zohar@xxxxxxxxxxxxxxxxxx> wrote: > 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'. > > 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@xxxxxxxxxx> Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@xxxxxxxxx> > --- > Documentation/kernel-parameters.txt | 4 + > include/linux/xattr.h | 3 + > security/integrity/evm/evm_main.c | 3 + > security/integrity/iint.c | 3 +- > security/integrity/ima/Kconfig | 15 +++ > security/integrity/ima/Makefile | 2 + > security/integrity/ima/ima.h | 37 +++++++- > security/integrity/ima/ima_api.c | 50 +++++++--- > security/integrity/ima/ima_appraise.c | 168 +++++++++++++++++++++++++++++++++ > security/integrity/ima/ima_crypto.c | 8 ++- > security/integrity/ima/ima_main.c | 78 ++++++++++----- > security/integrity/ima/ima_policy.c | 32 +++++-- > security/integrity/integrity.h | 8 +- > 13 files changed, 358 insertions(+), 53 deletions(-) > create mode 100644 security/integrity/ima/ima_appraise.c > > diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt > index 033d4e6..a86765d 100644 > --- a/Documentation/kernel-parameters.txt > +++ b/Documentation/kernel-parameters.txt > @@ -1004,6 +1004,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) > diff --git a/include/linux/xattr.h b/include/linux/xattr.h > index e5d1220..77a3e68 100644 > --- a/include/linux/xattr.h > +++ b/include/linux/xattr.h > @@ -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 > > diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c > index 8901501..eb54845 100644 > --- a/security/integrity/evm/evm_main.c > +++ b/security/integrity/evm/evm_main.c > @@ -34,6 +34,9 @@ char *evm_config_xattrnames[] = { > #ifdef CONFIG_SECURITY_SMACK > XATTR_NAME_SMACK, > #endif > +#ifdef CONFIG_IMA_APPRAISE > + XATTR_NAME_IMA, > +#endif > XATTR_NAME_CAPS, > NULL > }; > diff --git a/security/integrity/iint.c b/security/integrity/iint.c > index 399641c..e600986 100644 > --- a/security/integrity/iint.c > +++ b/security/integrity/iint.c > @@ -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); > } > @@ -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; > } > > diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig > index 35664fe..b7465a1 100644 > --- a/security/integrity/ima/Kconfig > +++ b/security/integrity/ima/Kconfig > @@ -54,3 +54,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. > diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile > index 5690c02..bd31516 100644 > --- a/security/integrity/ima/Makefile > +++ b/security/integrity/ima/Makefile > @@ -7,3 +7,5 @@ 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_audit.o > + > +ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o > diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h > index 3ccf7ac..d5bf463 100644 > --- a/security/integrity/ima/ima.h > +++ b/security/integrity/ima/ima.h > @@ -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 { > @@ -98,6 +99,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); > @@ -114,14 +116,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 > > diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c > index 88a2788..55deeb1 100644 > --- a/security/integrity/ima/ima_api.c > +++ b/security/integrity/ima/ima_api.c > @@ -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"; > > /* > @@ -93,7 +97,7 @@ err_out: > } > > /** > - * 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) > @@ -105,15 +109,22 @@ err_out: > * 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); > } > > /* > @@ -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; > } > > @@ -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, > diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c > new file mode 100644 > index 0000000..4865f61 > --- /dev/null > +++ b/security/integrity/ima/ima_appraise.c > @@ -0,0 +1,168 @@ > +/* > + * Copyright (C) 2011 IBM Corporation > + * > + * Author: > + * Mimi Zohar <zohar@xxxxxxxxxx> > + * > + * 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) > +{ > + return 0; > +} > + > +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; > +} > diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c > index 9b3ade7..b21ee5b 100644 > --- a/security/integrity/ima/ima_crypto.c > +++ b/security/integrity/ima/ima_crypto.c > @@ -48,7 +48,7 @@ int ima_calc_hash(struct file *file, char *digest) > struct scatterlist sg[1]; > loff_t i_size, offset = 0; > char *rbuf; > - int rc; > + int rc, read = 0; > > rc = init_desc(&desc); > if (rc != 0) > @@ -59,6 +59,10 @@ int ima_calc_hash(struct file *file, char *digest) > rc = -ENOMEM; > goto out; > } > + if (!(file->f_mode & FMODE_READ)) { > + file->f_mode |= FMODE_READ; > + read = 1; > + } > i_size = i_size_read(file->f_dentry->d_inode); > while (offset < i_size) { > int rbuf_len; > @@ -80,6 +84,8 @@ int ima_calc_hash(struct file *file, char *digest) > kfree(rbuf); > if (!rc) > rc = crypto_hash_final(&desc, digest); > + if (read) > + file->f_mode &= ~FMODE_READ; > out: > crypto_free_hash(desc.tfm); > return rc; > diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c > index 5b222eb..fba2f7b 100644 > --- a/security/integrity/ima/ima_main.c > +++ b/security/integrity/ima/ima_main.c > @@ -22,12 +22,19 @@ > #include <linux/mount.h> > #include <linux/mman.h> > #include <linux/slab.h> > +#include <linux/xattr.h> > #include <linux/ima.h> > > #include "ima.h" > > int ima_initialized; > > +#ifdef CONFIG_IMA_APPRAISE > +int ima_appraise = IMA_APPRAISE_ENFORCE; > +#else > +int ima_appraise; > +#endif > + > char *ima_hash = "sha1"; > static int __init hash_setup(char *str) > { > @@ -52,7 +59,7 @@ static void ima_rdwr_violation_check(struct file *file) > struct dentry *dentry = file->f_path.dentry; > struct inode *inode = dentry->d_inode; > fmode_t mode = file->f_mode; > - int rc; > + int must_measure; > bool send_tomtou = false, send_writers = false; > > if (!S_ISREG(inode->i_mode) || !ima_initialized) > @@ -66,8 +73,8 @@ static void ima_rdwr_violation_check(struct file *file) > goto out; > } > > - rc = ima_must_measure(inode, MAY_READ, FILE_CHECK); > - if (rc < 0) > + must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK); > + if (!must_measure) > goto out; > > if (atomic_read(&inode->i_writecount) > 0) > @@ -84,17 +91,21 @@ out: > } > > static void ima_check_last_writer(struct integrity_iint_cache *iint, > - struct inode *inode, > - struct file *file) > + struct inode *inode, struct file *file) > { > fmode_t mode = file->f_mode; > > - mutex_lock(&iint->mutex); > - if (mode & FMODE_WRITE && > - atomic_read(&inode->i_writecount) == 1 && > - iint->version != inode->i_version) > - iint->flags &= ~IMA_MEASURED; > - mutex_unlock(&iint->mutex); > + if (!(mode & FMODE_WRITE)) > + return; > + > + mutex_lock(&inode->i_mutex); > + if (atomic_read(&inode->i_writecount) == 1 && > + iint->version != inode->i_version) { > + iint->flags &= ~(IMA_COLLECTED | IMA_APPRAISED | IMA_MEASURED); > + if (iint->flags & IMA_APPRAISE) > + ima_update_xattr(iint, file); > + } > + mutex_unlock(&inode->i_mutex); > } > > /** > @@ -123,14 +134,17 @@ static int process_measurement(struct file *file, const unsigned char *filename, > { > struct inode *inode = file->f_dentry->d_inode; > struct integrity_iint_cache *iint; > - int rc = 0; > + int rc = -ENOMEM, action, must_appraise; > > if (!ima_initialized || !S_ISREG(inode->i_mode)) > return 0; > > - rc = ima_must_measure(inode, mask, function); > - if (rc != 0) > - return rc; > + /* Determine if in appraise/measurement policy, > + * returns IMA_MEASURE, IMA_APPRAISE bitmask. */ > + action = ima_must_appraise_or_measure(inode, mask, function); > + if (!action) > + return 0; > + > retry: > iint = integrity_iint_find(inode); > if (!iint) { > @@ -140,18 +154,32 @@ retry: > return rc; > } > > - mutex_lock(&iint->mutex); > + must_appraise = action & IMA_APPRAISE; > > - rc = iint->flags & IMA_MEASURED ? 1 : 0; > - if (rc != 0) > + mutex_lock(&inode->i_mutex); > + > + /* Determine if already appraised/measured based on bitmask > + * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED) */ > + iint->flags |= action; > + action &= ~((iint->flags & (IMA_MEASURED | IMA_APPRAISED)) >> 1); > + > + /* Nothing to do, just return existing appraised status */ > + if (!action) { > + if (iint->flags & IMA_APPRAISED) > + rc = iint->ima_status; > goto out; > + } > > rc = ima_collect_measurement(iint, file); > - if (!rc) > + if (rc != 0) > + goto out; > + if (action & IMA_MEASURE) > ima_store_measurement(iint, file, filename); > + if (action & IMA_APPRAISE) > + rc = ima_appraise_measurement(iint, file, filename); > out: > - mutex_unlock(&iint->mutex); > - return rc; > + mutex_unlock(&inode->i_mutex); > + return (rc && must_appraise) ? -EACCES : 0; > } > > /** > @@ -167,14 +195,14 @@ out: > */ > int ima_file_mmap(struct file *file, unsigned long prot) > { > - int rc; > + int rc = 0; > > if (!file) > return 0; > if (prot & PROT_EXEC) > rc = process_measurement(file, file->f_dentry->d_name.name, > MAY_EXEC, FILE_MMAP); > - return 0; > + return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; > } > EXPORT_SYMBOL_GPL(ima_file_mmap); > > @@ -197,7 +225,7 @@ int ima_bprm_check(struct linux_binprm *bprm) > > rc = process_measurement(bprm->file, bprm->filename, > MAY_EXEC, BPRM_CHECK); > - return 0; > + return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; > } > > /** > @@ -218,7 +246,7 @@ int ima_file_check(struct file *file, int mask) > rc = process_measurement(file, file->f_dentry->d_name.name, > mask & (MAY_READ | MAY_WRITE | MAY_EXEC), > FILE_CHECK); > - return 0; > + return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; > } > EXPORT_SYMBOL_GPL(ima_file_check); > > diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c > index d8edff2..8ee301c 100644 > --- a/security/integrity/ima/ima_policy.c > +++ b/security/integrity/ima/ima_policy.c > @@ -25,7 +25,13 @@ > #define IMA_FSMAGIC 0x0004 > #define IMA_UID 0x0008 > > -enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; > +#define UNKNOWN 0 > +#define MEASURE 1 /* same as IMA_MEASURE */ > +#define DONT_MEASURE 2 > +#define MEASURE_MASK 3 > +#define APPRAISE 4 /* same as IMA_APPRAISE */ > +#define DONT_APPRAISE 8 > +#define APPRAISE_MASK 12 > > #define MAX_LSM_RULES 6 > enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, > @@ -34,7 +40,7 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, > > struct ima_measure_rule_entry { > struct list_head list; > - enum ima_action action; > + int action; > unsigned int flags; > enum ima_hooks func; > int mask; > @@ -161,18 +167,28 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, > * as elements in the list are never deleted, nor does the list > * change.) > */ > -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) > { > struct ima_measure_rule_entry *entry; > + int action = 0, actmask = flags | (flags << 1); > > list_for_each_entry(entry, ima_measure, list) { > - bool rc; > > - rc = ima_match_rules(entry, inode, func, mask); > - if (rc) > - return entry->action; > + if (!(entry->action & actmask)) > + continue; > + > + if (!ima_match_rules(entry, inode, func, mask)) > + continue; > + > + action |= (entry->action & (IMA_APPRAISE | IMA_MEASURE)); > + actmask &= (entry->action & APPRAISE_MASK) ? > + ~APPRAISE_MASK : ~MEASURE_MASK; > + if (!actmask) > + break; > } > - return 0; > + > + return action; > } > > /** > diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h > index 7a25ece..295702d 100644 > --- a/security/integrity/integrity.h > +++ b/security/integrity/integrity.h > @@ -16,7 +16,11 @@ > #include <crypto/sha.h> > > /* iint cache flags */ > -#define IMA_MEASURED 0x01 > +#define IMA_MEASURE 1 > +#define IMA_MEASURED 2 > +#define IMA_APPRAISE 4 > +#define IMA_APPRAISED 8 > +#define IMA_COLLECTED 16 > > enum evm_ima_xattr_type { > IMA_XATTR_DIGEST = 0x01, > @@ -36,7 +40,7 @@ struct integrity_iint_cache { > u64 version; /* track inode changes */ > unsigned char flags; > u8 digest[SHA1_DIGEST_SIZE]; > - struct mutex mutex; /* protects: version, flags, digest */ > + enum integrity_status ima_status; > enum integrity_status evm_status; > }; > > -- > 1.7.6.5 > -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html