This list is closed, nobody may subscribe to it.
| 2007 |
Jan
|
Feb
(10) |
Mar
(26) |
Apr
(8) |
May
(3) |
Jun
|
Jul
(26) |
Aug
(10) |
Sep
|
Oct
|
Nov
(2) |
Dec
(4) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2008 |
Jan
|
Feb
(13) |
Mar
(4) |
Apr
(3) |
May
(5) |
Jun
|
Jul
(7) |
Aug
(8) |
Sep
(5) |
Oct
(16) |
Nov
|
Dec
(6) |
| 2009 |
Jan
(2) |
Feb
|
Mar
(3) |
Apr
|
May
|
Jun
(19) |
Jul
(4) |
Aug
|
Sep
(13) |
Oct
(10) |
Nov
(12) |
Dec
(2) |
| 2010 |
Jan
|
Feb
(2) |
Mar
(17) |
Apr
(28) |
May
|
Jun
(17) |
Jul
(11) |
Aug
(12) |
Sep
(2) |
Oct
|
Nov
|
Dec
(1) |
| 2011 |
Jan
|
Feb
|
Mar
(20) |
Apr
(10) |
May
(1) |
Jun
|
Jul
|
Aug
(15) |
Sep
(14) |
Oct
(2) |
Nov
|
Dec
|
| 2012 |
Jan
(1) |
Feb
(53) |
Mar
(15) |
Apr
(4) |
May
(2) |
Jun
(13) |
Jul
|
Aug
|
Sep
(12) |
Oct
|
Nov
|
Dec
(6) |
| 2013 |
Jan
(7) |
Feb
(8) |
Mar
(4) |
Apr
(5) |
May
|
Jun
|
Jul
|
Aug
(5) |
Sep
(6) |
Oct
|
Nov
(5) |
Dec
(8) |
| 2014 |
Jan
(17) |
Feb
(24) |
Mar
(8) |
Apr
(7) |
May
(18) |
Jun
(15) |
Jul
(5) |
Aug
(2) |
Sep
(49) |
Oct
(28) |
Nov
(7) |
Dec
(30) |
| 2015 |
Jan
(40) |
Feb
|
Mar
(9) |
Apr
(2) |
May
(9) |
Jun
(31) |
Jul
(33) |
Aug
(5) |
Sep
(20) |
Oct
|
Nov
(3) |
Dec
(12) |
| 2016 |
Jan
(14) |
Feb
(29) |
Mar
(10) |
Apr
(4) |
May
(4) |
Jun
|
Jul
(5) |
Aug
(19) |
Sep
(21) |
Oct
(2) |
Nov
(36) |
Dec
(30) |
| 2017 |
Jan
(101) |
Feb
(12) |
Mar
(7) |
Apr
(2) |
May
(29) |
Jun
(22) |
Jul
(7) |
Aug
(93) |
Sep
(27) |
Oct
(39) |
Nov
|
Dec
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:38
|
This patch adds local measurement integrity appraisal to IMA. (Taken
from the original EVM postings.) New is the creation and maintainance
of an extended attribute 'security.ima' containing the file hash
measurement. Protection of the xattr is provided by EVM, if enabled
and configured.
Based on policy, IMA calls evm_verifyxattr() to verify the security.ima
xattr integrity and, assuming success, compares the xattr hash value with
the collected file measurement.
Signed-off-by: Mimi Zohar <zo...@us...>
Acked-by: Serge Hallyn <se...@us...>
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index d80930d..b977884 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -965,6 +965,10 @@ and is between 256 and 4096 characters. It is defined in the file
ihash_entries= [KNL]
Set number of hash buckets for inode cache.
+ ima_appraise= [IMA] appraise integrity measurements
+ Format: { "off" | "enforce" | "log" | "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 e90377e..4f6608f 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -37,6 +37,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 acc5176..278e0de 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -32,6 +32,9 @@ char *evm_config_xattrnames[] = {
#ifdef CONFIG_SECURITY_SMACK
XATTR_NAME_SMACK,
#endif
+#ifdef CONFIG_IMA
+ XATTR_NAME_IMA,
+#endif
XATTR_NAME_CAPS,
NULL
};
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index f694b63..4863cdc 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -136,6 +136,7 @@ static void init_once(void *foo)
iint->readcount = 0;
iint->writecount = 0;
iint->opencount = 0;
+ iint->hash_status = INTEGRITY_UNKNOWN;
iint->hmac_status = INTEGRITY_UNKNOWN;
kref_init(&iint->refcount);
}
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index dc60e40..39abced 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -55,3 +55,17 @@ 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.
+ To protect 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 5995e70..2d1d99b 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -37,9 +37,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
/* set during initialization */
+extern char *ima_xattr_name;
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 {
@@ -97,8 +99,9 @@ static inline unsigned long ima_hash_key(u8 *digest)
}
/* LIM API function definitions */
-int ima_must_measure(struct integrity_iint_cache *iint, struct inode *inode,
- int mask, int function);
+int ima_must_appraise_or_measure(struct integrity_iint_cache *iint,
+ struct inode *inode, int mask, int function,
+ int *must_measure, int *must_appraise);
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file);
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
@@ -116,7 +119,7 @@ void iint_free(struct kref *kref);
void iint_rcu_free(struct rcu_head *rcu);
/* 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);
void ima_init_policy(void);
@@ -124,6 +127,39 @@ void ima_update_policy(void);
int ima_parse_add_rule(char *);
void ima_delete_rules(void);
+/* Appraise integrity measurements */
+#ifdef CONFIG_IMA_APPRAISE
+#define IMA_APPRAISE_ENABLED 0x01
+#define IMA_APPRAISE_ENFORCE 0x02
+#define IMA_APPRAISE_LOG 0x04
+#define IMA_APPRAISE_FIX 0x08
+
+int ima_appraise_measurement(struct integrity_iint_cache *iint,
+ struct file *file, const unsigned char *filename);
+int ima_must_appraise(struct integrity_iint_cache *iint, 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 integrity_iint_cache *iint,
+ struct inode *inode,
+ enum ima_hooks func, int mask)
+{
+}
+
+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 bb307fb..8c5375c 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -9,12 +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/file.h>
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/evm.h>
#include "ima.h"
+
static const char *IMA_TEMPLATE_NAME = "ima";
/*
@@ -92,10 +97,12 @@ 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)
+ * @must_measure: pointer to measure flag
+ * @must_appraise: pointer to appraise flag
*
* The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic=
@@ -106,20 +113,32 @@ err_out:
*
* Must be called with iint->mutex held.
*
- * Return 0 to measure. Return 1 if already measured.
+ * Set must_appraise to 1 to appraise measurement.
+ * Set must_measure to 1 to add to measurement list.
+ *
* For matching a DONT_MEASURE policy, no policy, or other
- * error, return an error code.
+ * error, return an error code, otherwise 0.
*/
-int ima_must_measure(struct integrity_iint_cache *iint, struct inode *inode,
- int mask, int function)
+int ima_must_appraise_or_measure(struct integrity_iint_cache *iint,
+ struct inode *inode, int mask, int function,
+ int *must_measure, int *must_appraise)
{
- int must_measure;
+ int rc;
- if (iint->flags & IMA_MEASURED)
- return 1;
+ if (must_appraise)
+ *must_appraise = ima_must_appraise(iint, inode, function, mask);
- must_measure = ima_match_policy(inode, function, mask);
- return must_measure ? 0 : -EACCES;
+ if (iint->flags & IMA_MEASURED) {
+ if (must_measure)
+ *must_measure = 0;
+ return 0;
+ }
+ rc = ima_match_policy(inode, function, mask);
+ if (rc)
+ iint->flags |= IMA_MEASURE;
+ if (must_measure)
+ *must_measure = rc ? 1 : 0;
+ return rc ? 0 : -EACCES;
}
/*
@@ -135,15 +154,17 @@ int ima_must_measure(struct integrity_iint_cache *iint, struct inode *inode,
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file)
{
- int result = -EEXIST;
+ 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;
+ }
}
return result;
}
@@ -173,6 +194,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..a6acde5
--- /dev/null
+++ b/security/integrity/ima/ima_appraise.c
@@ -0,0 +1,135 @@
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/magic.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, "log", 3) == 0)
+ ima_appraise = IMA_APPRAISE_ENABLED | IMA_APPRAISE_LOG;
+ else if (strncmp(str, "fix", 3) == 0)
+ ima_appraise = IMA_APPRAISE_ENABLED | 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 integrity_iint_cache *iint, struct inode *inode,
+ enum ima_hooks func, int mask)
+{
+ return 0;
+}
+
+static void ima_fix_xattr(struct dentry *dentry,
+ struct integrity_iint_cache *iint)
+{
+ __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
+ iint->digest, IMA_DIGEST_SIZE, 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 || !inode->i_op->getxattr)
+ return 0;
+ if (iint->flags & IMA_APPRAISED)
+ return iint->hash_status;
+
+ rc = inode->i_op->getxattr(dentry, XATTR_NAME_IMA, xattr_value,
+ IMA_DIGEST_SIZE);
+ if (rc < 0)
+ goto err_out;
+ status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc);
+ if ((rc > 0)
+ && ((status == INTEGRITY_PASS) || (status == INTEGRITY_UNKNOWN))) {
+ if (memcmp(xattr_value, iint->digest, IMA_DIGEST_SIZE) != 0) {
+ 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);
+ if (ima_appraise & IMA_APPRAISE_FIX)
+ ima_fix_xattr(dentry, iint);
+ integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
+ filename, op, cause, 1, 0);
+ } else
+ status = INTEGRITY_PASS;
+ iint->flags |= IMA_APPRAISED;
+ } else {
+ if (status == INTEGRITY_NOLABEL)
+ cause = "missing-HMAC";
+ else if (status == INTEGRITY_FAIL)
+ cause = "invalid-HMAC";
+
+ if (ima_appraise & IMA_APPRAISE_FIX)
+ ima_fix_xattr(dentry, iint);
+ integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
+ op, cause, 1, 0);
+ }
+ iint->hash_status = status;
+ return status;
+err_out:
+ if (rc == -ENODATA) {
+ if (iint->version == 1)
+ return 0;
+ cause = "missing-hash";
+ if (ima_appraise & IMA_APPRAISE_FIX)
+ ima_fix_xattr(dentry, iint);
+ integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
+ op, cause, 1, 0);
+ iint->hash_status = INTEGRITY_NOLABEL;
+ return iint->hash_status;
+ }
+ printk(KERN_INFO "%s: %d %s\n", __func__, rc, filename);
+ return 0;
+}
+
+/*
+ * 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 read = 0;
+ int rc = 0;
+
+ if (!(file->f_mode & FMODE_READ)) {
+ file->f_mode |= FMODE_READ;
+ read = 1;
+ }
+ rc = ima_collect_measurement(iint, file);
+ if (read)
+ file->f_mode &= ~FMODE_READ;
+ if (rc < 0)
+ return;
+ __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
+ iint->digest, IMA_DIGEST_SIZE, 0);
+}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 7eeb76e..635a3be 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -22,11 +22,18 @@
#include <linux/binfmts.h>
#include <linux/mount.h>
#include <linux/mman.h>
+#include <linux/xattr.h>
#include "ima.h"
int ima_initialized;
+#ifdef CONFIG_IMA_APPRAISE
+int ima_appraise = IMA_APPRAISE_ENABLED | IMA_APPRAISE_ENFORCE;
+#else
+int ima_appraise;
+#endif
+
char *ima_hash = "sha1";
static int __init hash_setup(char *str)
{
@@ -154,7 +161,8 @@ void ima_counts_get(struct file *file)
if (!iint)
return;
mutex_lock(&iint->mutex);
- rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK);
+ rc = ima_must_appraise_or_measure(iint, inode, MAY_READ, FILE_CHECK,
+ NULL, NULL);
if (rc < 0)
goto out;
@@ -185,8 +193,12 @@ static void ima_dec_counts(struct integrity_iint_cache *iint,
if (mode & FMODE_WRITE) {
iint->writecount--;
if (iint->writecount == 0) {
- if (iint->version != inode->i_version)
- iint->flags &= ~IMA_MEASURED;
+ if (iint->version != inode->i_version) {
+ iint->flags &= ~(IMA_COLLECTED | IMA_APPRAISED
+ | IMA_MEASURED);
+ if (iint->flags & IMA_APPRAISE)
+ ima_update_xattr(iint, file);
+ }
}
}
@@ -199,6 +211,7 @@ static void ima_dec_counts(struct integrity_iint_cache *iint,
iint->opencount);
dump_stack();
}
+ return;
}
/**
@@ -230,7 +243,7 @@ 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;
+ int rc, err = 0, must_measure, must_appraise;
if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0;
@@ -239,17 +252,25 @@ static int process_measurement(struct file *file, const unsigned char *filename,
return -ENOMEM;
mutex_lock(&iint->mutex);
- rc = ima_must_measure(iint, inode, mask, function);
- if (rc != 0)
+ rc = ima_must_appraise_or_measure(iint, inode, mask, function,
+ &must_measure, &must_appraise);
+ if (!must_measure && !must_appraise) {
+ if (iint->flags & IMA_APPRAISED)
+ err = iint->hash_status;
goto out;
+ }
rc = ima_collect_measurement(iint, file);
- if (!rc)
+ if (rc != 0)
+ goto out;
+ if (must_measure)
ima_store_measurement(iint, file, filename);
+ if (must_appraise)
+ err = ima_appraise_measurement(iint, file, filename);
out:
mutex_unlock(&iint->mutex);
kref_put(&iint->refcount, iint_free);
- return rc;
+ return (!err) ? 0 : -EACCES;
}
/**
@@ -265,14 +286,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;
}
/**
@@ -294,7 +315,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;
}
/**
@@ -314,10 +335,41 @@ 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);
+/**
+ * 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
+ */
+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;
+
+ iint = integrity_iint_find_get(inode);
+ if (!iint)
+ return;
+
+ mutex_lock(&iint->mutex);
+ iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED);
+ must_appraise = ima_must_appraise(iint, inode, MAY_ACCESS,
+ POST_SETATTR);
+ if (!must_appraise)
+ rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA);
+ mutex_unlock(&iint->mutex);
+ kref_put(&iint->refcount, iint_free);
+ return;
+}
+
static int __init init_ima(void)
{
int error;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index c83e475..3a9b3de 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -18,13 +18,18 @@
#define MAX_DIGEST_SIZE SHA1_DIGEST_SIZE
/* iint cache flags */
-#define IMA_MEASURED 1
+#define IMA_MEASURE 1
+#define IMA_MEASURED 2
+#define IMA_APPRAISE 4
+#define IMA_APPRAISED 8
+#define IMA_COLLECTED 16
/* integrity data associated with an inode */
struct integrity_iint_cache {
u64 version; /* track inode changes */
unsigned long flags;
u8 digest[MAX_DIGEST_SIZE];
+ enum integrity_status hash_status;
struct mutex mutex; /* protects: version, flags, digest */
long readcount; /* measured files readcount */
long writecount; /* measured files writecount */
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:37
|
Initialize 'security.evm' for new files. Reduce number of arguments
by defining 'struct xattr'.
Signed-off-by: Mimi Zohar <zo...@us...>
Acked-by: Serge Hallyn <se...@us...>
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 8626263..3602bd1 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -9,6 +9,7 @@
#define _LINUX_EVM_H
#include <linux/integrity.h>
+#include <linux/xattr.h>
#ifdef CONFIG_EVM
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
@@ -25,6 +26,9 @@ extern void evm_inode_post_setxattr(struct dentry *dentry,
extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
extern void evm_inode_post_removexattr(struct dentry *dentry,
const char *xattr_name);
+extern int evm_inode_post_init_security(struct inode *inode,
+ const struct xattr *new,
+ struct xattr *evm);
#else
static enum integrity_status evm_verifyxattr(struct dentry *dentry,
char *xattr_name,
@@ -65,5 +69,12 @@ static inline void evm_inode_post_removexattr(struct dentry *dentry,
return;
}
+static inline int evm_inode_post_init_security(struct inode *inode,
+ const struct xattr *new,
+ struct xattr *evm)
+{
+ return -EOPNOTSUPP;
+}
+
#endif /* CONFIG_EVM_H */
#endif /* LINUX_EVM_H */
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index d1afa51..e90377e 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -60,6 +60,12 @@ struct xattr_handler {
size_t size, int flags, int handler_flags);
};
+struct xattr {
+ char *name;
+ void *value;
+ size_t value_len;
+};
+
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index 0b6f7b2..a4b6907 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -12,6 +12,7 @@
* File: evm.h
*
*/
+#include <linux/xattr.h>
#include <linux/security.h>
#include "../integrity.h"
@@ -31,5 +32,7 @@ extern int evm_update_evmxattr(struct dentry *dentry,
extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, char *digest);
+extern int evm_init_hmac(struct inode *inode, struct xattr *xattr,
+ char *hmac_val);
extern int evm_init_secfs(void);
extern void evm_cleanup_secfs(void);
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 4f1be71..5fe322d 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -150,6 +150,25 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
return rc;
}
+int evm_init_hmac(struct inode *inode, struct xattr *lsm_xattr, char *hmac_val)
+{
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ int error;
+
+ error = init_desc(&desc);
+ if (error != 0) {
+ printk(KERN_INFO "init_desc failed\n");
+ return error;
+ }
+
+ sg_init_one(sg, lsm_xattr->value, lsm_xattr->value_len);
+ crypto_hash_update(&desc, sg, lsm_xattr->value_len);
+ hmac_add_misc(&desc, inode, hmac_val);
+ crypto_free_hash(desc.tfm);
+ return 0;
+}
+
/*
* Get the key from the TPM for the SHA1-HMAC
*/
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 59dc148..acc5176 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -96,6 +96,12 @@ static int evm_protected_xattr(const char *req_xattr_name)
found = 1;
break;
}
+ if (strncmp(req_xattr_name,
+ *xattrname + XATTR_SECURITY_PREFIX_LEN,
+ strlen(req_xattr_name)) == 0) {
+ found = 1;
+ break;
+ }
}
return found;
}
@@ -256,6 +262,36 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
return;
}
+/*
+ * evm_inode_post_init_security - initializes security.evm
+ */
+int evm_inode_post_init_security(struct inode *inode, struct xattr *lsm_xattr,
+ struct xattr *evm_xattr)
+{
+ u8 *hmac_val;
+ int rc;
+
+ if (!evm_initialized || !evm_protected_xattr(lsm_xattr->name))
+ return -EOPNOTSUPP;
+
+ hmac_val = kzalloc(MAX_DIGEST_SIZE, GFP_NOFS);
+ if (!hmac_val)
+ return -ENOMEM;
+
+ rc = evm_init_hmac(inode, lsm_xattr, hmac_val);
+ if (rc < 0)
+ goto out;
+
+ evm_xattr->value = hmac_val;
+ evm_xattr->value_len = evm_hmac_size;
+ evm_xattr->name = XATTR_EVM_SUFFIX;
+ return 0;
+out:
+ kfree(hmac_val);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(evm_inode_post_init_security);
+
static struct crypto_hash *tfm_hmac; /* preload crypto alg */
static int __init init_evm(void)
{
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:34
|
After creating the initial LSM security extended attribute, call
evm_inode_post_init_security() to create the 'security.evm'
extended attribute.
(Support for other fs still needed.)
Signed-off-by: Mimi Zohar <zo...@us...>
Acked-by: Serge Hallyn <se...@us...>
diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
index c815584..3987a1b 100644
--- a/fs/ext2/xattr_security.c
+++ b/fs/ext2/xattr_security.c
@@ -8,6 +8,7 @@
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include "xattr.h"
static size_t
@@ -49,21 +50,37 @@ int
ext2_init_security(struct inode *inode, struct inode *dir)
{
int err;
- size_t len;
- void *value;
- char *name;
+ struct xattr lsm_xattr;
+ struct xattr evm_xattr;
- err = security_inode_init_security(inode, dir, &name, &value, &len);
+ err = security_inode_init_security(inode, dir, &lsm_xattr.name,
+ &lsm_xattr.value,
+ &lsm_xattr.value_len);
if (err) {
if (err == -EOPNOTSUPP)
return 0;
return err;
}
err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY,
- name, value, len, 0);
- kfree(name);
- kfree(value);
+ lsm_xattr.name, lsm_xattr.value,
+ lsm_xattr.value_len, 0);
+ if (err < 0)
+ goto out;
+
+ err = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+ if (err)
+ goto out;
+ err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY,
+ evm_xattr.name, evm_xattr.value,
+ evm_xattr.value_len, 0);
+ kfree(evm_xattr.value);
+out:
+ kfree(lsm_xattr.name);
+ kfree(lsm_xattr.value);
+ if (err == -EOPNOTSUPP)
+ return 0;
return err;
+
}
struct xattr_handler ext2_xattr_security_handler = {
diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c
index 4743487..eba57a9 100644
--- a/fs/ext3/xattr_security.c
+++ b/fs/ext3/xattr_security.c
@@ -9,6 +9,7 @@
#include <linux/ext3_jbd.h>
#include <linux/ext3_fs.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include "xattr.h"
static size_t
@@ -51,20 +52,35 @@ int
ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
{
int err;
- size_t len;
- void *value;
- char *name;
+ struct xattr lsm_xattr;
+ struct xattr evm_xattr;
- err = security_inode_init_security(inode, dir, &name, &value, &len);
+ err = security_inode_init_security(inode, dir, &lsm_xattr.name,
+ &lsm_xattr.value,
+ &lsm_xattr.value_len);
if (err) {
if (err == -EOPNOTSUPP)
return 0;
return err;
}
err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
- name, value, len, 0);
- kfree(name);
- kfree(value);
+ lsm_xattr.name, lsm_xattr.value,
+ lsm_xattr.value_len, 0);
+ if (err < 0)
+ goto out;
+
+ err = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+ if (err)
+ goto out;
+ err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
+ evm_xattr.name, evm_xattr.value,
+ evm_xattr.value_len, 0);
+ kfree(evm_xattr.value);
+out:
+ kfree(lsm_xattr.name);
+ kfree(lsm_xattr.value);
+ if (err == -EOPNOTSUPP)
+ return 0;
return err;
}
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
index 983c253..d8ecbee 100644
--- a/fs/ext4/xattr_security.c
+++ b/fs/ext4/xattr_security.c
@@ -7,6 +7,7 @@
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include "ext4_jbd2.h"
#include "ext4.h"
#include "xattr.h"
@@ -51,20 +52,35 @@ int
ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
{
int err;
- size_t len;
- void *value;
- char *name;
+ struct xattr lsm_xattr;
+ struct xattr evm_xattr;
- err = security_inode_init_security(inode, dir, &name, &value, &len);
+ err = security_inode_init_security(inode, dir, &lsm_xattr.name,
+ &lsm_xattr.value,
+ &lsm_xattr.value_len);
if (err) {
if (err == -EOPNOTSUPP)
return 0;
return err;
}
err = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SECURITY,
- name, value, len, 0);
- kfree(name);
- kfree(value);
+ lsm_xattr.name, lsm_xattr.value,
+ lsm_xattr.value_len, 0);
+ if (err < 0)
+ goto out;
+
+ err = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+ if (err)
+ goto out;
+ err = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SECURITY,
+ evm_xattr.name, evm_xattr.value,
+ evm_xattr.value_len, 0);
+ kfree(evm_xattr.value);
+out:
+ kfree(lsm_xattr.name);
+ kfree(lsm_xattr.value);
+ if (err == -EOPNOTSUPP)
+ return 0;
return err;
}
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:20
|
Changing the inode's metadata may require the 'security.evm' extended
attribute to be re-calculated and updated.
Signed-off-by: Mimi Zohar <zo...@us...>
diff --git a/fs/attr.c b/fs/attr.c
index 96d394b..2391242 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -14,6 +14,7 @@
#include <linux/fcntl.h>
#include <linux/quotaops.h>
#include <linux/security.h>
+#include <linux/evm.h>
/* Taken over from the old code... */
@@ -225,8 +226,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (ia_valid & ATTR_SIZE)
up_write(&dentry->d_inode->i_alloc_sem);
- if (!error)
+ if (!error) {
fsnotify_change(dentry, ia_valid);
+ evm_inode_post_setattr(dentry, ia_valid);
+ }
return error;
}
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 93edadd..8626263 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -15,6 +15,7 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
char *xattr_name,
char *xattr_value,
size_t xattr_value_len);
+extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
extern int evm_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size);
extern void evm_inode_post_setxattr(struct dentry *dentry,
@@ -33,6 +34,11 @@ static enum integrity_status evm_verifyxattr(struct dentry *dentry,
return INTEGRITY_UNKNOWN;
}
+static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
+{
+ return;
+}
+
static inline int evm_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size)
{
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:18
|
When an EVM protected extended attribute is removed, update 'security.evm'.
Signed-off-by: Mimi Zohar <zo...@us...>
Acked-by: Serge Hallyn <se...@us...>
diff --git a/fs/xattr.c b/fs/xattr.c
index 341ad71..9372e77 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -14,6 +14,7 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include <linux/syscalls.h>
#include <linux/module.h>
#include <linux/fsnotify.h>
@@ -294,8 +295,10 @@ vfs_removexattr(struct dentry *dentry, const char *name)
error = inode->i_op->removexattr(dentry, name);
mutex_unlock(&inode->i_mutex);
- if (!error)
+ if (!error) {
fsnotify_xattr(dentry);
+ evm_inode_post_removexattr(dentry, name);
+ }
return error;
}
EXPORT_SYMBOL_GPL(vfs_removexattr);
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 1a30beb..93edadd 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -22,6 +22,8 @@ extern void evm_inode_post_setxattr(struct dentry *dentry,
const void *xattr_value,
size_t xattr_value_len);
extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
+extern void evm_inode_post_removexattr(struct dentry *dentry,
+ const char *xattr_name);
#else
static enum integrity_status evm_verifyxattr(struct dentry *dentry,
char *xattr_name,
@@ -50,5 +52,12 @@ static inline int evm_inode_removexattr(struct dentry *dentry,
{
return 0;
}
+
+static inline void evm_inode_post_removexattr(struct dentry *dentry,
+ const char *xattr_name)
+{
+ return;
+}
+
#endif /* CONFIG_EVM_H */
#endif /* LINUX_EVM_H */
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:11
|
Integrity appraisal measures files on file_free and stores the file measurement as an xattr. Measure the file before releasing it. Signed-off-by: Mimi Zohar <zo...@us...> Acked-by: Serge Hallyn <se...@us...> diff --git a/fs/file_table.c b/fs/file_table.c index b98404b..c97f112 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -250,10 +250,10 @@ void __fput(struct file *file) if (file->f_op && file->f_op->fasync) file->f_op->fasync(-1, file, 0); } + ima_file_free(file); if (file->f_op && file->f_op->release) file->f_op->release(inode, file); security_file_free(file); - ima_file_free(file); if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) cdev_put(inode->i_cdev); fops_put(file->f_op); -- 1.6.6 |
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:11
|
Imbed the evm calls evm_inode_setxattr(), evm_inode_post_setxattr(),
evm_inode_removexattr() in the security hooks. evm_inode_setxattr()
protects security.evm xattr. evm_inode_post_setxattr() and
evm_inode_removexattr() updates the hmac associated with an inode.
(Assumes an LSM module protects the setting/removing of xattr.)
Signed-off-by: Mimi Zohar <zo...@us...>
Acked-by: Serge Hallyn <se...@us...>
diff --git a/include/linux/evm.h b/include/linux/evm.h
new file mode 100644
index 0000000..1a30beb
--- /dev/null
+++ b/include/linux/evm.h
@@ -0,0 +1,54 @@
+/*
+ * evm.h
+ *
+ * Copyright (c) 2009 IBM Corporation
+ * Author: Mimi Zohar <zo...@us...>
+ */
+
+#ifndef _LINUX_EVM_H
+#define _LINUX_EVM_H
+
+#include <linux/integrity.h>
+
+#ifdef CONFIG_EVM
+extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
+ char *xattr_name,
+ char *xattr_value,
+ size_t xattr_value_len);
+extern int evm_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size);
+extern void evm_inode_post_setxattr(struct dentry *dentry,
+ const char *xattr_name,
+ const void *xattr_value,
+ size_t xattr_value_len);
+extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
+#else
+static enum integrity_status evm_verifyxattr(struct dentry *dentry,
+ char *xattr_name,
+ char *xattr_value,
+ size_t xattr_value_len)
+{
+ return INTEGRITY_UNKNOWN;
+}
+
+static inline int evm_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size)
+{
+ return 0;
+}
+
+static inline void evm_inode_post_setxattr(struct dentry *dentry,
+ const char *xattr_name,
+ const void *xattr_value,
+ size_t xattr_value_len)
+{
+ return;
+}
+
+static inline int evm_inode_removexattr(struct dentry *dentry,
+ const char *xattr_name)
+{
+ return 0;
+}
+#endif /* CONFIG_EVM_H */
+#endif /* LINUX_EVM_H */
diff --git a/security/security.c b/security/security.c
index 2f82216..754cb25 100644
--- a/security/security.c
+++ b/security/security.c
@@ -18,6 +18,7 @@
#include <linux/security.h>
#include <linux/integrity.h>
#include <linux/ima.h>
+#include <linux/evm.h>
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
@@ -591,9 +592,14 @@ void security_inode_delete(struct inode *inode)
int security_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
+ int ret;
+
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_setxattr(dentry, name, value, size, flags);
+ ret = security_ops->inode_setxattr(dentry, name, value, size, flags);
+ if (ret)
+ return ret;
+ return evm_inode_setxattr(dentry, name, value, size);
}
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
@@ -602,6 +608,7 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return;
security_ops->inode_post_setxattr(dentry, name, value, size, flags);
+ evm_inode_post_setxattr(dentry, name, value, size);
}
int security_inode_getxattr(struct dentry *dentry, const char *name)
@@ -620,9 +627,14 @@ int security_inode_listxattr(struct dentry *dentry)
int security_inode_removexattr(struct dentry *dentry, const char *name)
{
+ int ret;
+
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_removexattr(dentry, name);
+ ret = security_ops->inode_removexattr(dentry, name);
+ if (ret)
+ return ret;
+ return evm_inode_removexattr(dentry, name);
}
int security_inode_need_killpriv(struct dentry *dentry)
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:04
|
EVM protects a file's security extended attributes against integrity attacks. It maintains an HMAC-sha1 value across the extended attributes, storing the value as the extended attribute 'security.evm'. EVM has gone through a number of iterations, initially as an LSM module, subsequently as a LIM integrity provider, and now, when co-located with a security_ hook, embedded directly in the security_ hook, similar to IMA. This is the first part of a local file integrity verification system. While this part does authenticate the selected extended attributes, and cryptographically bind them to the inode, coming extensions will bind other directory and inode metadata for more complete protection. The set of protected security extended attributes is configured at compile. EVM depends on the Kernel Key Retention System to provide it with the kernel master key for the HMAC operation. The kernel master key is securely loaded onto the root's keyring, typically by 'loadkernkey', which either uses the TPM sealed secret key, if available, or a password requested from the console. To signal EVM, that the key has been loaded onto the keyring, 'echo 1 > <securityfs>/evm'. This is normally done in the initrd, which has already been measured as part of the trusted boot. (Refer to http://www.research.ibm.com/gsal/tcpa.) EVM adds the following three calls to the existing security hooks, evm_inode_setxattr(), evm_inode_post_setxattr(), and evm_inode_removexattr. To initialize and update the 'security.evm' extended attribute, EVM defines three calls: evm_inode_post_init(), evm_inode_post_setattr() and evm_inode_post_removexattr() hooks. To verify the integrity of an extended attribute, EVM exports evm_verifyxattr(). Signed-off-by: Mimi Zohar <zo...@us...> diff --git a/include/linux/integrity.h b/include/linux/integrity.h index 276081f..fa9c199 100644 --- a/include/linux/integrity.h +++ b/include/linux/integrity.h @@ -10,6 +10,13 @@ #ifndef _LINUX_INTEGRITY_H #define _LINUX_INTEGRITY_H +enum integrity_status { + INTEGRITY_PASS = 0, + INTEGRITY_FAIL, + INTEGRITY_NOLABEL, + INTEGRITY_UNKNOWN, +}; + #ifdef CONFIG_INTEGRITY extern int integrity_inode_alloc(struct inode *inode); extern void integrity_inode_free(struct inode *inode); diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 8698de3..d1afa51 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -34,6 +34,9 @@ #define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1) /* Security namespace */ +#define XATTR_EVM_SUFFIX "evm" +#define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX + #define XATTR_SELINUX_SUFFIX "selinux" #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 2704691..4bf00ac 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -1,6 +1,7 @@ # config INTEGRITY def_bool y - depends on IMA + depends on IMA || EVM source security/integrity/ima/Kconfig +source security/integrity/evm/Kconfig diff --git a/security/integrity/Makefile b/security/integrity/Makefile index 6eddd61..0ae44ae 100644 --- a/security/integrity/Makefile +++ b/security/integrity/Makefile @@ -8,3 +8,5 @@ integrity-y := iint.o subdir-$(CONFIG_IMA) += ima obj-$(CONFIG_IMA) += ima/built-in.o +subdir-$(CONFIG_EVM) += evm +obj-$(CONFIG_EVM) += evm/built-in.o diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig new file mode 100644 index 0000000..8a546f7 --- /dev/null +++ b/security/integrity/evm/Kconfig @@ -0,0 +1,13 @@ +config EVM + boolean "EVM support" + depends on SECURITY && KEYS + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 + default n + help + A configurable set of security extended attributes are HMAC + protected against modification using the TPM's kernel root key, + if configured, or with a pass-phrase. + + If you are unsure how to answer this question, answer N. diff --git a/security/integrity/evm/Makefile b/security/integrity/evm/Makefile new file mode 100644 index 0000000..3d38273 --- /dev/null +++ b/security/integrity/evm/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for building the Extended Verification Module(EVM) +# +obj-$(CONFIG_EVM) += evm.o + +evm-y := evm_main.o evm_crypto.o evm_secfs.o + diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h new file mode 100644 index 0000000..0b6f7b2 --- /dev/null +++ b/security/integrity/evm/evm.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2005-2010 IBM Corporation + * + * Authors: + * Mimi Zohar <zo...@us...> + * Kylene Hall <kj...@us...> + * + * 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. + * + * File: evm.h + * + */ +#include <linux/security.h> +#include "../integrity.h" + +extern int evm_initialized; +extern char *evm_hmac; +extern int evm_hmac_size; + +/* List of EVM protected security xattrs */ +extern char *evm_config_xattrnames[]; + +extern int evm_init_tpmkernkey(void); +extern int evm_update_evmxattr(struct dentry *dentry, + const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, + struct integrity_iint_cache *iint); +extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, char *digest); +extern int evm_init_secfs(void); +extern void evm_cleanup_secfs(void); diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c new file mode 100644 index 0000000..4f1be71 --- /dev/null +++ b/security/integrity/evm/evm_crypto.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2005-2010 IBM Corporation + * + * Authors: + * Mimi Zohar <zo...@us...> + * Kylene Hall <kj...@us...> + * + * 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. + * + * File: evm_crypto.c + * Using root's kernel master key (kmk), calculate the HMAC + */ + +#include <linux/module.h> +#include <linux/crypto.h> +#include <linux/xattr.h> +#include <keys/user-type.h> +#include <linux/scatterlist.h> +#include "evm.h" + +#define TPMKEY "evm_key" +#define MAX_TPMKEY 128 +static unsigned char tpm_key[MAX_TPMKEY]; +static int tpm_keylen = MAX_TPMKEY; + +static int init_desc(struct hash_desc *desc) +{ + int rc; + + desc->tfm = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(desc->tfm)) { + pr_info("Can not allocate %s (reason: %ld)\n", + evm_hmac, PTR_ERR(desc->tfm)); + rc = PTR_ERR(desc->tfm); + return rc; + } + desc->flags = 0; + crypto_hash_setkey(desc->tfm, tpm_key, tpm_keylen); + rc = crypto_hash_init(desc); + if (rc) + crypto_free_hash(desc->tfm); + return rc; +} + +/* Protect against 'cutting & pasting' security.evm xattr, include inode + * specific info. + * + * (Additional directory/file metadata needs to be added for more complete + * protection.) + */ +static void hmac_add_misc(struct hash_desc *desc, struct inode *inode, + char *digest) +{ + struct h_misc { + unsigned long ino; + __u32 generation; + uid_t uid; + gid_t gid; + umode_t mode; + } hmac_misc; + struct scatterlist sg[1]; + + memset(&hmac_misc, 0, sizeof hmac_misc); + hmac_misc.ino = inode->i_ino; + hmac_misc.generation = inode->i_generation; + hmac_misc.uid = inode->i_uid; + hmac_misc.gid = inode->i_gid; + hmac_misc.mode = inode->i_mode; + sg_init_one(sg, &hmac_misc, sizeof hmac_misc); + crypto_hash_update(desc, sg, sizeof hmac_misc); + crypto_hash_final(desc, digest); +} + +/* + * Calculate the HMAC value across the set of protected security xattrs. + * + * Instead of retrieving the requested xattr, for performance, calculate + * the hmac using the requested xattr value. Don't alloc/free memory for + * each xattr, but attempt to re-use the previously allocated memory. + */ +int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, size_t req_xattr_value_len, + char *digest) +{ + struct inode *inode = dentry->d_inode; + struct hash_desc desc; + struct scatterlist sg[1]; + char **xattrname; + size_t xattr_size = 0; + char *xattr_value = NULL; + int error; + int size; + + if (!inode->i_op || !inode->i_op->getxattr) + return -EOPNOTSUPP; + error = init_desc(&desc); + if (error) + return error; + + error = -ENODATA; + for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { + if ((req_xattr_name && req_xattr_value) + && !strcmp(*xattrname, req_xattr_name)) { + error = 0; + sg_init_one(sg, req_xattr_value, req_xattr_value_len); + crypto_hash_update(&desc, sg, req_xattr_value_len); + continue; + } + size = vfs_getxattr_alloc(dentry, *xattrname, + &xattr_value, xattr_size, GFP_NOFS); + if (size == -ENOMEM) { + error = -ENOMEM; + goto out; + } + if (size < 0) + continue; + + error = 0; + xattr_size = size; + sg_init_one(sg, xattr_value, xattr_size); + crypto_hash_update(&desc, sg, xattr_size); + } + hmac_add_misc(&desc, inode, digest); + kfree(xattr_value); +out: + crypto_free_hash(desc.tfm); + return error; +} + +/* + * Calculate the hmac and update security.evm xattr + */ +int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, + const char *xattr_value, size_t xattr_value_len, + struct integrity_iint_cache *iint) +{ + struct inode *inode = dentry->d_inode; + int rc = 0; + + memset(iint->hmac, 0, sizeof iint->hmac); + rc = evm_calc_hmac(dentry, xattr_name, xattr_value, + xattr_value_len, iint->hmac); + if (rc == 0) + rc = inode->i_op->setxattr(dentry, XATTR_NAME_EVM, + iint->hmac, evm_hmac_size, 0); + else if (rc == -ENODATA) + rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM); + return rc; +} + +/* + * Get the key from the TPM for the SHA1-HMAC + */ +int evm_init_tpmkernkey(void) +{ + struct key *kmk; + struct user_key_payload *ukp; + int len; + + kmk = request_key(&key_type_user, TPMKEY, NULL); + if (IS_ERR(kmk)) + return -ENOENT; + + down_read(&kmk->sem); + ukp = kmk->payload.data; + len = ukp->datalen; + if (len > MAX_TPMKEY) + len = MAX_TPMKEY; + tpm_keylen = len; + memcpy(tpm_key, ukp->data, len); + + /* burn the original key contents */ + memset(ukp->data, 0, len); + up_read(&kmk->sem); + key_put(kmk); + return 0; +} diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c new file mode 100644 index 0000000..59dc148 --- /dev/null +++ b/security/integrity/evm/evm_main.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2005-2010 IBM Corporation + * + * Author: + * Mimi Zohar <zo...@us...> + * Kylene Hall <kj...@us...> + * + * 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. + * + * File: evm_main.c + * implements evm_inode_setxattr, evm_inode_post_setxattr, + * evm_inode_removexattr, and evm_verifyxattr + */ + +#include <linux/module.h> +#include <linux/crypto.h> +#include <linux/xattr.h> +#include <linux/integrity.h> +#include "evm.h" + +int evm_initialized; + +char *evm_hmac = "hmac(sha1)"; +int evm_hmac_size = SHA1_DIGEST_SIZE; + +char *evm_config_xattrnames[] = { +#ifdef CONFIG_SECURITY_SELINUX + XATTR_NAME_SELINUX, +#endif +#ifdef CONFIG_SECURITY_SMACK + XATTR_NAME_SMACK, +#endif + XATTR_NAME_CAPS, + NULL +}; + +/* + * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr + * + * Compute the HMAC on the dentry's protected set of extended attributes + * and compare it against the stored security.evm xattr. (For performance, + * use the previoulsy retrieved xattr value and length to calculate the + * HMAC.) + * + * Returns integrity status + */ +static enum integrity_status evm_verify_hmac(struct dentry *dentry, + const char *xattr_name, + char *xattr_value, + size_t xattr_value_len, + struct integrity_iint_cache *iint) +{ + char hmac_val[MAX_DIGEST_SIZE]; + int rc; + + if (iint->hmac_status != INTEGRITY_UNKNOWN) + return iint->hmac_status; + + memset(hmac_val, 0, sizeof hmac_val); + rc = evm_calc_hmac(dentry, xattr_name, xattr_value, + xattr_value_len, hmac_val); + if (rc < 0) + return INTEGRITY_UNKNOWN; + + rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, hmac_val, sizeof hmac_val, + GFP_NOFS); + if (rc < 0) + goto err_out; + iint->hmac_status = INTEGRITY_PASS; + return iint->hmac_status; + +err_out: + switch (rc) { + case -ENODATA: /* file not labelled */ + iint->hmac_status = INTEGRITY_NOLABEL; + break; + case -EINVAL: + iint->hmac_status = INTEGRITY_FAIL; + break; + default: + iint->hmac_status = INTEGRITY_UNKNOWN; + } + return iint->hmac_status; +} + +static int evm_protected_xattr(const char *req_xattr_name) +{ + char **xattrname; + int found = 0; + + for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { + if (strncmp(req_xattr_name, *xattrname, + strlen(req_xattr_name)) == 0) { + found = 1; + break; + } + } + return found; +} + +/** + * evm_verifyxattr - verify the integrity of the requested xattr + * @dentry: object of the verify xattr + * @xattr_name: requested xattr + * @xattr_value: requested xattr value + * @xattr_value_len: requested xattr value length + * + * Calculate the HMAC for the given dentry and verify it + * against the stored security.evm xattr. For performance, + * use the xattr value and length previously retrieved + * to calculate the HMAC. + * + * Returns the xattr integrity status. + */ +enum integrity_status evm_verifyxattr(struct dentry *dentry, + const char *xattr_name, + void *xattr_value, size_t xattr_value_len) +{ + struct inode *inode = dentry->d_inode; + struct integrity_iint_cache *iint; + enum integrity_status status; + + if (!evm_initialized || !evm_protected_xattr(xattr_name)) + return INTEGRITY_UNKNOWN; + + iint = integrity_iint_find_get(inode); + if (!iint) + return -ENOMEM; + mutex_lock(&iint->evm_mutex); + status = evm_verify_hmac(dentry, xattr_name, xattr_value, + xattr_value_len, iint); + mutex_unlock(&iint->evm_mutex); + kref_put(&iint->refcount, iint_free); + return status; +} +EXPORT_SYMBOL_GPL(evm_verifyxattr); + +/* + * evm_protect_xattr - protect the EVM extended attribute + * + * Prevent security.evm from being modified or removed. + */ +static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, + const void *xattr_value, size_t xattr_value_len) +{ + if ((!capable(CAP_MAC_ADMIN)) + && (strcmp(xattr_name, XATTR_NAME_EVM) == 0)) + return -EPERM; + return 0; +} + +/** + * evm_inode_setxattr - protect the EVM extended attribute + * @dentry: pointer to the affected dentry + * @xattr_name: pointer to the affected extended attribute name + * @xattr_value: pointer to the new extended attribute value + * @xattr_value_len: pointer to the new extended attribute value length + * + * Prevent 'security.evm' from being modified + */ +int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, + const void *xattr_value, size_t xattr_value_len) +{ + return evm_protect_xattr(dentry, xattr_name, xattr_value, + xattr_value_len); +} + +/** + * evm_inode_removexattr - protect the EVM extended attribute + * @dentry: pointer to the affected dentry + * @xattr_name: pointer to the affected extended attribute name + * + * Prevent 'security.evm' from being removed. + */ +int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) +{ + return evm_protect_xattr(dentry, xattr_name, NULL, 0); +} + +/* + * After updating/removing an extended attribute defined in /etc/evm.config, + * update the HMAC(security.evm) to reflect the change. + */ +static void evm_postxattr(struct dentry *dentry, const char *xattr_name, + const void *xattr_value, size_t xattr_value_len) +{ + struct inode *inode = dentry->d_inode; + struct integrity_iint_cache *iint; + int rc; + + iint = integrity_iint_find_get(inode); + if (!iint) + return; + mutex_lock(&iint->evm_mutex); + iint->hmac_status = INTEGRITY_UNKNOWN; + rc = evm_update_evmxattr(dentry, xattr_name, xattr_value, + xattr_value_len, iint); + if (!rc) + iint->hmac_status = INTEGRITY_PASS; + mutex_unlock(&iint->evm_mutex); + kref_put(&iint->refcount, iint_free); +} + +/** + * evm_inode_post_setxattr - update 'security.evm' to reflect the changes + * @dentry: pointer to the affected dentry + * @xattr_name: pointer to the affected extended attribute name + * @xattr_value: pointer to the new extended attribute value + * @xattr_value_len: pointer to the new extended attribute value length + * + * Update the HMAC stored in 'security.evm' to reflect the change. + */ +void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, + const void *xattr_value, size_t xattr_value_len) +{ + if (!evm_initialized || !evm_protected_xattr(xattr_name)) + return; + + evm_postxattr(dentry, xattr_name, xattr_value, xattr_value_len); + return; +} + +/** + * evm_inode_post_removexattr - update 'security.evm' after removing the xattr + * @dentry: pointer to the affected dentry + * @xattr_name: pointer to the affected extended attribute name + * + * Update the HMAC stored in 'security.evm' to reflect removal of the xattr. + */ +void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) +{ + if (!evm_initialized || !evm_protected_xattr(xattr_name)) + return; + + evm_postxattr(dentry, xattr_name, NULL, 0); + return; +} + +/** + * evm_inode_post_setattr - update 'security.evm' after modifying metadata + * @dentry: pointer to the affected dentry + * @ia_valid: for the UID and GID status + * + * For now, update the HMAC stored in 'security.evm' to reflect UID/GID + * changes. + */ +void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) +{ + if (!evm_initialized) + return; + + if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) + evm_postxattr(dentry, NULL, NULL, 0); + return; +} + +static struct crypto_hash *tfm_hmac; /* preload crypto alg */ +static int __init init_evm(void) +{ + int error; + + tfm_hmac = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC); + error = evm_init_secfs(); + if (error < 0) { + printk(KERN_INFO "EVM: Error registering secfs\n"); + goto err; + } +err: + return error; +} + +static void __exit cleanup_evm(void) +{ + evm_cleanup_secfs(); + crypto_free_hash(tfm_hmac); +} + +/* + * evm_display_config - list the EVM protected security extended attributes + */ +static int __init evm_display_config(void) +{ + char **xattrname; + + for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) + printk(KERN_INFO "EVM: %s\n", *xattrname); + return 0; +} + +pure_initcall(evm_display_config); +late_initcall(init_evm); + +MODULE_DESCRIPTION("Extended Verification Module"); +MODULE_LICENSE("GPL"); diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c new file mode 100644 index 0000000..eeb2182 --- /dev/null +++ b/security/integrity/evm/evm_secfs.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2010 IBM Corporation + * + * Authors: + * Mimi Zohar <zo...@us...> + * + * 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. + * + * File: evm_secfs.c + * - Used to signal when key is on keyring + * - Get the key and enable EVM + */ + +#include <linux/uaccess.h> +#include <linux/module.h> +#include "evm.h" + +static struct dentry *evm_init_tpm; + +/** + * evm_read_key - read() for <securityfs>/evm + * + * @filp: file pointer, not actually used + * @buf: where to put the result + * @count: maximum to send along + * @ppos: where to start + * + * Returns number of bytes read or error code, as appropriate + */ +static ssize_t evm_read_key(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + char temp[80]; + ssize_t rc; + + if (*ppos != 0) + return 0; + + sprintf(temp, "%d", evm_initialized); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +} + +/** + * evm_write_key - write() for <securityfs>/evm + * @file: file pointer, not actually used + * @buf: where to get the data from + * @count: bytes sent + * @ppos: where to start + * + * Used to signal that key is on the kernel key ring. + * - get the integrity hmac key from the kernel key ring + * - create list of hmac protected extended attributes + * Returns number of bytes written or error code, as appropriate + */ +static ssize_t evm_write_key(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char temp[80]; + int i, error; + + if (!capable(CAP_MAC_ADMIN) || evm_initialized) + return -EPERM; + + if (count >= sizeof(temp) || count == 0) + return -EINVAL; + + if (copy_from_user(temp, buf, count) != 0) + return -EFAULT; + + temp[count] = '\0'; + + if ((sscanf(temp, "%d", &i) != 1) || (i != 1)) + return -EINVAL; + + error = evm_init_tpmkernkey(); + printk(KERN_INFO "EVM: %s (%d)\n", (error < 0) ? + "tpmkernkey initialization failed" : "tpmkernkey initialized", + i); + if (!error) + evm_initialized = 1; + return count; +} + +static const struct file_operations evm_key_ops = { + .read = evm_read_key, + .write = evm_write_key, +}; + +int __init evm_init_secfs(void) +{ + int error = 0; + + evm_init_tpm = securityfs_create_file("evm", S_IRUSR | S_IRGRP, + NULL, NULL, &evm_key_ops); + if (!evm_init_tpm || IS_ERR(evm_init_tpm)) + error = -EFAULT; + return error; +} + +void __exit evm_cleanup_secfs(void) +{ + if (evm_init_tpm) + securityfs_remove(evm_init_tpm); +} diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 9eda158..f694b63 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -132,9 +132,11 @@ static void init_once(void *foo) iint->version = 0; iint->flags = 0UL; mutex_init(&iint->mutex); + mutex_init(&iint->evm_mutex); iint->readcount = 0; iint->writecount = 0; iint->opencount = 0; + iint->hmac_status = INTEGRITY_UNKNOWN; kref_init(&iint->refcount); } diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index f1013c9..c83e475 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -31,6 +31,9 @@ struct integrity_iint_cache { long opencount; /* opens reference count */ struct kref refcount; /* ima_iint_cache reference count */ struct rcu_head rcu; + struct mutex evm_mutex; /* protects: hmac_status, hmac */ + enum integrity_status hmac_status; + u8 hmac[MAX_DIGEST_SIZE]; }; /* radix tree calls to lookup, insert, delete -- 1.6.6 |
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:45:00
|
vfs_getxattr_alloc() and vfs_xattr_cmp() are two new kernel xattr
helper functions. vfs_getxattr_alloc() first allocates memory for
the requested xattr and then retrieves it. vfs_xattr_cmp() compares
a given value with the contents of an extended attribute.
Signed-off-by: Mimi Zohar <zo...@us...>
diff --git a/fs/xattr.c b/fs/xattr.c
index 46f87e8..341ad71 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -159,6 +159,64 @@ out_noalloc:
}
EXPORT_SYMBOL_GPL(xattr_getsecurity);
+/*
+ * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
+ *
+ * Allocate memory, if not already allocated, or re-allocate correct size,
+ * before retrieving the extended attribute.
+ *
+ * Returns the result of alloc, if failed, or the getxattr operation.
+ */
+ssize_t
+vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
+ size_t xattr_size, gfp_t flags)
+{
+ struct inode *inode = dentry->d_inode;
+ char *value = *xattr_value;
+ int error;
+
+ error = xattr_permission(inode, name, MAY_READ);
+ if (error)
+ return error;
+
+ if (!inode->i_op->getxattr)
+ return -EOPNOTSUPP;
+
+ error = inode->i_op->getxattr(dentry, name, NULL, 0);
+ if (error < 0)
+ return error;
+
+ if (!value || (error > xattr_size)) {
+ value = krealloc(*xattr_value, error + 1, flags);
+ if (!value)
+ return -ENOMEM;
+ memset(value, 0, error + 1);
+ }
+
+ error = inode->i_op->getxattr(dentry, name, value, error);
+ *xattr_value = value;
+ return error;
+}
+
+/* Compare an extended attribute value with the given value */
+int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
+ const char *value, size_t size, gfp_t flags)
+{
+ char *xattr_value = NULL;
+ int rc;
+
+ rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags);
+ if (rc < 0)
+ return rc;
+
+ if ((rc != size) || (memcmp(xattr_value, value, rc) != 0))
+ rc = -EINVAL;
+ else
+ rc = 0;
+ kfree(xattr_value);
+ return rc;
+}
+
ssize_t
vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index d079bec..8698de3 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -68,7 +68,10 @@ ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer,
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
int generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags);
int generic_removexattr(struct dentry *dentry, const char *name);
-
+ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name,
+ char **xattr_value, size_t size, gfp_t flags);
+int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
+ const char *value, size_t size, gfp_t flags);
#endif /* __KERNEL__ */
#endif /* _LINUX_XATTR_H */
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:44:45
|
Make the security extended attributes names global.
Signed-off-by: Mimi Zohar <zo...@us...>
Acked-by: Serge Hallyn <se...@us...>
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 39e5ff5..90012b9 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -49,9 +49,6 @@ typedef struct __user_cap_data_struct {
} __user *cap_user_data_t;
-#define XATTR_CAPS_SUFFIX "capability"
-#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
-
#define VFS_CAP_REVISION_MASK 0xFF000000
#define VFS_CAP_REVISION_SHIFT 24
#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index fb9b7e6..d079bec 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -33,6 +33,16 @@
#define XATTR_USER_PREFIX "user."
#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
+/* Security namespace */
+#define XATTR_SELINUX_SUFFIX "selinux"
+#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+
+#define XATTR_SMACK_SUFFIX "SMACK64"
+#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
+
+#define XATTR_CAPS_SUFFIX "capability"
+#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
+
struct inode;
struct dentry;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 63c2d36..36b7a2d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -87,9 +87,6 @@
#include "netlabel.h"
#include "audit.h"
-#define XATTR_SELINUX_SUFFIX "selinux"
-#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
-
#define NUM_SEL_MNT_OPTS 5
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
diff --git a/security/smack/smack.h b/security/smack/smack.h
index c6e9aca..9c773e3 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -126,10 +126,8 @@ struct smack_known {
/*
* xattr names
*/
-#define XATTR_SMACK_SUFFIX "SMACK64"
#define XATTR_SMACK_IPIN "SMACK64IPIN"
#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
-#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:44:43
|
Move the inode integrity data(iint) management up to the
integrity layer in order to share the integrity data area
among the different integrity models.
Signed-off-by: Mimi Zohar <zo...@us...>
Acked-by: Serge Hallyn <se...@us...>
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 975837e..4dce900 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -15,8 +15,6 @@ struct linux_binprm;
#ifdef CONFIG_IMA
extern int ima_bprm_check(struct linux_binprm *bprm);
-extern int ima_inode_alloc(struct inode *inode);
-extern void ima_inode_free(struct inode *inode);
extern int ima_file_check(struct file *file, int mask);
extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot);
@@ -28,16 +26,6 @@ static inline int ima_bprm_check(struct linux_binprm *bprm)
return 0;
}
-static inline int ima_inode_alloc(struct inode *inode)
-{
- return 0;
-}
-
-static inline void ima_inode_free(struct inode *inode)
-{
- return;
-}
-
static inline int ima_file_check(struct file *file, int mask)
{
return 0;
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
new file mode 100644
index 0000000..276081f
--- /dev/null
+++ b/include/linux/integrity.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2009 IBM Corporation
+ * Author: Mimi Zohar <zo...@us...>
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#ifdef CONFIG_INTEGRITY
+extern int integrity_inode_alloc(struct inode *inode);
+extern void integrity_inode_free(struct inode *inode);
+
+#else
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+ return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{
+ return;
+}
+#endif /* CONFIG_INTEGRITY_H */
+#endif /* _LINUX_INTEGRITY_H */
diff --git a/security/Kconfig b/security/Kconfig
index 226b955..4f00287 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -141,7 +141,7 @@ source security/selinux/Kconfig
source security/smack/Kconfig
source security/tomoyo/Kconfig
-source security/integrity/ima/Kconfig
+source security/integrity/Kconfig
choice
prompt "Default security module"
diff --git a/security/Makefile b/security/Makefile
index da20a19..9269caa 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -22,5 +22,5 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
-subdir-$(CONFIG_IMA) += integrity/ima
-obj-$(CONFIG_IMA) += integrity/ima/built-in.o
+subdir-$(CONFIG_INTEGRITY) += integrity
+obj-$(CONFIG_INTEGRITY) += integrity/built-in.o
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
new file mode 100644
index 0000000..2704691
--- /dev/null
+++ b/security/integrity/Kconfig
@@ -0,0 +1,6 @@
+#
+config INTEGRITY
+ def_bool y
+ depends on IMA
+
+source security/integrity/ima/Kconfig
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
new file mode 100644
index 0000000..6eddd61
--- /dev/null
+++ b/security/integrity/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for caching inode integrity data (iint)
+#
+
+obj-$(CONFIG_INTEGRITY) += integrity.o
+
+integrity-y := iint.o
+
+subdir-$(CONFIG_IMA) += ima
+obj-$(CONFIG_IMA) += ima/built-in.o
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
new file mode 100644
index 0000000..9eda158
--- /dev/null
+++ b/security/integrity/iint.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2008-2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zo...@us...>
+ *
+ * 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.
+ *
+ * File: iint.c
+ * - implements the integrity hooks: integrity_inode_alloc,
+ * integrity_inode_free
+ * - cache integrity information associated with an inode
+ * using a radix tree.
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/radix-tree.h>
+#include "integrity.h"
+
+RADIX_TREE(integrity_iint_store, GFP_ATOMIC);
+DEFINE_SPINLOCK(integrity_iint_lock);
+
+static struct kmem_cache *iint_cache __read_mostly;
+
+/* integrity_iint_find_get - return the iint associated with an inode
+ *
+ * integrity_iint_find_get gets a reference to the iint. Caller must
+ * remember to put the iint reference.
+ */
+struct integrity_iint_cache *integrity_iint_find_get(struct inode *inode)
+{
+ struct integrity_iint_cache *iint;
+
+ rcu_read_lock();
+ iint = radix_tree_lookup(&integrity_iint_store, (unsigned long)inode);
+ if (!iint)
+ goto out;
+ kref_get(&iint->refcount);
+out:
+ rcu_read_unlock();
+ return iint;
+}
+
+/**
+ * integrity_inode_alloc - allocate an iint associated with an inode
+ * @inode: pointer to the inode
+ */
+int integrity_inode_alloc(struct inode *inode)
+{
+ struct integrity_iint_cache *iint = NULL;
+ int rc = 0;
+
+ iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
+ if (!iint)
+ return -ENOMEM;
+
+ rc = radix_tree_preload(GFP_NOFS);
+ if (rc < 0)
+ goto out;
+
+ spin_lock(&integrity_iint_lock);
+ rc = radix_tree_insert(&integrity_iint_store, (unsigned long)inode,
+ iint);
+ spin_unlock(&integrity_iint_lock);
+ radix_tree_preload_end();
+out:
+ if (rc < 0)
+ kmem_cache_free(iint_cache, iint);
+
+ return rc;
+}
+
+/* iint_free - called when the iint refcount goes to zero */
+void iint_free(struct kref *kref)
+{
+ struct integrity_iint_cache *iint =
+ container_of(kref, struct integrity_iint_cache, refcount);
+ iint->version = 0;
+ iint->flags = 0UL;
+ if (iint->readcount != 0) {
+ printk(KERN_INFO "%s: readcount: %ld\n", __func__,
+ iint->readcount);
+ iint->readcount = 0;
+ }
+ if (iint->writecount != 0) {
+ printk(KERN_INFO "%s: writecount: %ld\n", __func__,
+ iint->writecount);
+ iint->writecount = 0;
+ }
+ if (iint->opencount != 0) {
+ printk(KERN_INFO "%s: opencount: %ld\n", __func__,
+ iint->opencount);
+ iint->opencount = 0;
+ }
+ kref_init(&iint->refcount);
+ kmem_cache_free(iint_cache, iint);
+}
+
+void iint_rcu_free(struct rcu_head *rcu_head)
+{
+ struct integrity_iint_cache *iint =
+ container_of(rcu_head, struct integrity_iint_cache, rcu);
+ kref_put(&iint->refcount, iint_free);
+}
+
+/**
+ * integrity_inode_free - called on security_inode_free
+ * @inode: pointer to the inode
+ *
+ * Free the integrity information(iint) associated with an inode.
+ */
+void integrity_inode_free(struct inode *inode)
+{
+ struct integrity_iint_cache *iint;
+
+ spin_lock(&integrity_iint_lock);
+ iint = radix_tree_delete(&integrity_iint_store, (unsigned long)inode);
+ spin_unlock(&integrity_iint_lock);
+ if (iint)
+ call_rcu(&iint->rcu, iint_rcu_free);
+}
+
+static void init_once(void *foo)
+{
+ struct integrity_iint_cache *iint = foo;
+
+ memset(iint, 0, sizeof *iint);
+ iint->version = 0;
+ iint->flags = 0UL;
+ mutex_init(&iint->mutex);
+ iint->readcount = 0;
+ iint->writecount = 0;
+ iint->opencount = 0;
+ kref_init(&iint->refcount);
+}
+
+static int __init integrity_iintcache_init(void)
+{
+ iint_cache =
+ kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
+ 0, SLAB_PANIC, init_once);
+ return 0;
+}
+
+security_initcall(integrity_iintcache_init);
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 3d7846d..dc60e40 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -4,6 +4,7 @@ config IMA
bool "Integrity Measurement Architecture(IMA)"
depends on ACPI
depends on SECURITY
+ select INTEGRITY
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index 787c4cb..5690c02 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -6,4 +6,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_iint.o ima_audit.o
+ ima_policy.o ima_audit.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 47fb65d..5995e70 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -24,11 +24,13 @@
#include <linux/tpm.h>
#include <linux/audit.h>
+#include "../integrity.h"
+
enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII };
enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
/* digest size for IMA, fits SHA1 or MD5 */
-#define IMA_DIGEST_SIZE 20
+#define IMA_DIGEST_SIZE SHA1_DIGEST_SIZE
#define IMA_EVENT_NAME_LEN_MAX 255
#define IMA_HASH_BITS 9
@@ -94,38 +96,22 @@ static inline unsigned long ima_hash_key(u8 *digest)
return hash_long(*digest, IMA_HASH_BITS);
}
-/* iint cache flags */
-#define IMA_MEASURED 1
-
-/* integrity data associated with an inode */
-struct ima_iint_cache {
- u64 version; /* track inode changes */
- unsigned long flags;
- u8 digest[IMA_DIGEST_SIZE];
- struct mutex mutex; /* protects: version, flags, digest */
- long readcount; /* measured files readcount */
- long writecount; /* measured files writecount */
- long opencount; /* opens reference count */
- struct kref refcount; /* ima_iint_cache reference count */
- struct rcu_head rcu;
-};
-
/* LIM API function definitions */
-int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
+int ima_must_measure(struct integrity_iint_cache *iint, struct inode *inode,
int mask, int function);
-int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file);
-void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
+int ima_collect_measurement(struct integrity_iint_cache *iint,
+ struct file *file);
+void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode);
-void ima_template_show(struct seq_file *m, void *e,
- enum ima_show_type show);
+void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show);
/* radix tree calls to lookup, insert, delete
* integrity data associated with an inode.
*/
-struct ima_iint_cache *ima_iint_insert(struct inode *inode);
-struct ima_iint_cache *ima_iint_find_get(struct inode *inode);
+struct integrity_iint_cache *ima_iint_insert(struct inode *inode);
+struct integrity_iint_cache *ima_iint_find_get(struct inode *inode);
void iint_free(struct kref *kref);
void iint_rcu_free(struct rcu_head *rcu);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 2a5e0bc..bb307fb 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -110,7 +110,7 @@ err_out:
* For matching a DONT_MEASURE policy, no policy, or other
* error, return an error code.
*/
-int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
+int ima_must_measure(struct integrity_iint_cache *iint, struct inode *inode,
int mask, int function)
{
int must_measure;
@@ -132,7 +132,8 @@ int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
*
* Return 0 on success, error code otherwise
*/
-int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
+int ima_collect_measurement(struct integrity_iint_cache *iint,
+ struct file *file)
{
int result = -EEXIST;
@@ -162,8 +163,8 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
*
* Must be called with iint->mutex held.
*/
-void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
- const unsigned char *filename)
+void ima_store_measurement(struct integrity_iint_cache *iint,
+ struct file *file, const unsigned char *filename)
{
const char *op = "add_template_measure";
const char *audit_cause = "ENOMEM";
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
deleted file mode 100644
index 01ddf31..0000000
--- a/security/integrity/ima/ima_iint.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2008 IBM Corporation
- *
- * Authors:
- * Mimi Zohar <zo...@us...>
- *
- * 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.
- *
- * File: ima_iint.c
- * - implements the IMA hooks: ima_inode_alloc, ima_inode_free
- * - cache integrity information associated with an inode
- * using a radix tree.
- */
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/radix-tree.h>
-#include "ima.h"
-
-RADIX_TREE(ima_iint_store, GFP_ATOMIC);
-DEFINE_SPINLOCK(ima_iint_lock);
-
-static struct kmem_cache *iint_cache __read_mostly;
-
-/* ima_iint_find_get - return the iint associated with an inode
- *
- * ima_iint_find_get gets a reference to the iint. Caller must
- * remember to put the iint reference.
- */
-struct ima_iint_cache *ima_iint_find_get(struct inode *inode)
-{
- struct ima_iint_cache *iint;
-
- rcu_read_lock();
- iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode);
- if (!iint)
- goto out;
- kref_get(&iint->refcount);
-out:
- rcu_read_unlock();
- return iint;
-}
-
-/**
- * ima_inode_alloc - allocate an iint associated with an inode
- * @inode: pointer to the inode
- */
-int ima_inode_alloc(struct inode *inode)
-{
- struct ima_iint_cache *iint = NULL;
- int rc = 0;
-
- iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
- if (!iint)
- return -ENOMEM;
-
- rc = radix_tree_preload(GFP_NOFS);
- if (rc < 0)
- goto out;
-
- spin_lock(&ima_iint_lock);
- rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
- spin_unlock(&ima_iint_lock);
- radix_tree_preload_end();
-out:
- if (rc < 0)
- kmem_cache_free(iint_cache, iint);
-
- return rc;
-}
-
-/* iint_free - called when the iint refcount goes to zero */
-void iint_free(struct kref *kref)
-{
- struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache,
- refcount);
- iint->version = 0;
- iint->flags = 0UL;
- if (iint->readcount != 0) {
- printk(KERN_INFO "%s: readcount: %ld\n", __func__,
- iint->readcount);
- iint->readcount = 0;
- }
- if (iint->writecount != 0) {
- printk(KERN_INFO "%s: writecount: %ld\n", __func__,
- iint->writecount);
- iint->writecount = 0;
- }
- if (iint->opencount != 0) {
- printk(KERN_INFO "%s: opencount: %ld\n", __func__,
- iint->opencount);
- iint->opencount = 0;
- }
- kref_init(&iint->refcount);
- kmem_cache_free(iint_cache, iint);
-}
-
-void iint_rcu_free(struct rcu_head *rcu_head)
-{
- struct ima_iint_cache *iint = container_of(rcu_head,
- struct ima_iint_cache, rcu);
- kref_put(&iint->refcount, iint_free);
-}
-
-/**
- * ima_inode_free - called on security_inode_free
- * @inode: pointer to the inode
- *
- * Free the integrity information(iint) associated with an inode.
- */
-void ima_inode_free(struct inode *inode)
-{
- struct ima_iint_cache *iint;
-
- spin_lock(&ima_iint_lock);
- iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
- spin_unlock(&ima_iint_lock);
- if (iint)
- call_rcu(&iint->rcu, iint_rcu_free);
-}
-
-static void init_once(void *foo)
-{
- struct ima_iint_cache *iint = foo;
-
- memset(iint, 0, sizeof *iint);
- iint->version = 0;
- iint->flags = 0UL;
- mutex_init(&iint->mutex);
- iint->readcount = 0;
- iint->writecount = 0;
- iint->opencount = 0;
- kref_init(&iint->refcount);
-}
-
-static int __init ima_iintcache_init(void)
-{
- iint_cache =
- kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
- SLAB_PANIC, init_once);
- return 0;
-}
-security_initcall(ima_iintcache_init);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 983037f..7eeb76e 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -18,6 +18,7 @@
*/
#include <linux/module.h>
#include <linux/file.h>
+#include <linux/fs.h>
#include <linux/binfmts.h>
#include <linux/mount.h>
#include <linux/mman.h>
@@ -96,7 +97,7 @@ out:
*/
enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
static void ima_read_write_check(enum iint_pcr_error error,
- struct ima_iint_cache *iint,
+ struct integrity_iint_cache *iint,
struct inode *inode,
const unsigned char *filename)
{
@@ -117,7 +118,7 @@ static void ima_read_write_check(enum iint_pcr_error error,
/*
* Update the counts given an fmode_t
*/
-static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
+static void ima_inc_counts(struct integrity_iint_cache *iint, fmode_t mode)
{
BUG_ON(!mutex_is_locked(&iint->mutex));
@@ -144,12 +145,12 @@ void ima_counts_get(struct file *file)
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
fmode_t mode = file->f_mode;
- struct ima_iint_cache *iint;
+ struct integrity_iint_cache *iint;
int rc;
if (!ima_initialized || !S_ISREG(inode->i_mode))
return;
- iint = ima_iint_find_get(inode);
+ iint = integrity_iint_find_get(inode);
if (!iint)
return;
mutex_lock(&iint->mutex);
@@ -172,8 +173,8 @@ out:
/*
* Decrement ima counts
*/
-static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
- struct file *file)
+static void ima_dec_counts(struct integrity_iint_cache *iint,
+ struct inode *inode, struct file *file)
{
mode_t mode = file->f_mode;
BUG_ON(!mutex_is_locked(&iint->mutex));
@@ -210,11 +211,11 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
void ima_file_free(struct file *file)
{
struct inode *inode = file->f_dentry->d_inode;
- struct ima_iint_cache *iint;
+ struct integrity_iint_cache *iint;
if (!ima_initialized || !S_ISREG(inode->i_mode))
return;
- iint = ima_iint_find_get(inode);
+ iint = integrity_iint_find_get(inode);
if (!iint)
return;
@@ -228,12 +229,12 @@ static int process_measurement(struct file *file, const unsigned char *filename,
int mask, int function)
{
struct inode *inode = file->f_dentry->d_inode;
- struct ima_iint_cache *iint;
+ struct integrity_iint_cache *iint;
int rc;
if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0;
- iint = ima_iint_find_get(inode);
+ iint = integrity_iint_find_get(inode);
if (!iint)
return -ENOMEM;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
new file mode 100644
index 0000000..f1013c9
--- /dev/null
+++ b/security/integrity/integrity.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009-2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zo...@us...>
+ *
+ * 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.
+ *
+ * File: integrity.h
+ */
+#include <linux/types.h>
+#include <linux/integrity.h>
+#include <crypto/sha.h>
+
+#define MAX_DIGEST_SIZE SHA1_DIGEST_SIZE
+
+/* iint cache flags */
+#define IMA_MEASURED 1
+
+/* integrity data associated with an inode */
+struct integrity_iint_cache {
+ u64 version; /* track inode changes */
+ unsigned long flags;
+ u8 digest[MAX_DIGEST_SIZE];
+ struct mutex mutex; /* protects: version, flags, digest */
+ long readcount; /* measured files readcount */
+ long writecount; /* measured files writecount */
+ long opencount; /* opens reference count */
+ struct kref refcount; /* ima_iint_cache reference count */
+ struct rcu_head rcu;
+};
+
+/* radix tree calls to lookup, insert, delete
+ * integrity data associated with an inode.
+ */
+struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
+struct integrity_iint_cache *integrity_iint_find_get(struct inode *inode);
+void iint_free(struct kref *kref);
+void iint_rcu_free(struct rcu_head *rcu);
diff --git a/security/security.c b/security/security.c
index b98334b..2f82216 100644
--- a/security/security.c
+++ b/security/security.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/ima.h>
/* Boot-time LSM user choice */
@@ -374,7 +375,7 @@ int security_inode_alloc(struct inode *inode)
ret = security_ops->inode_alloc_security(inode);
if (ret)
return ret;
- ret = ima_inode_alloc(inode);
+ ret = integrity_inode_alloc(inode);
if (ret)
security_inode_free(inode);
return ret;
@@ -382,7 +383,7 @@ int security_inode_alloc(struct inode *inode)
void security_inode_free(struct inode *inode)
{
- ima_inode_free(inode);
+ integrity_inode_free(inode);
security_ops->inode_free_security(inode);
}
--
1.6.6
|
|
From: Mimi Z. <zo...@li...> - 2010-03-24 20:44:31
|
Extended Verification Module(EVM) detects offline tampering of the security extended attributes (e.g. security.selinux, security.SMACK64, security.ima), which is the basis for LSM permission decisions and, with this set of patches, integrity appraisal decisions. To detect offline tampering of the extended attributes, EVM maintains an HMAC-sha1 across a set of security extended attributes, storing the HMAC as the extended attribute 'security.evm'. To verify the integrity of an extended attribute, EVM exports evm_verifyxattr(), which re-calculates the HMAC and compares it with the version stored in 'security.evm'. IMA currently maintains an integrity measurement list, containing the hashes of all executables, mmaped execute files, and files open for read by root (assuming the default measurement policy). The measurement list, with other information, can be used to assert the integrity of the running system to a third party. The "ima: integrity appraisal extension" patch extends IMA with local measurement appraisal. The extension stores and maintains the file integrity measurement as an extended attribute 'security.ima', which EVM can be configured to protect. DAC/MAC protect the integrity of a running system. An offline attack can bypass these protection mechanisms by mounting the disk under a different operating system and modifying the file data/metadata. If the disk is subsequently remounted under the EVM + DAC/MAC + IMA protected OS, then the hash of the file data won't match the hash stored in the IMA xattr, or the TPM-calculated HMAC of the file's metadata won't be valid. Therefore, IMA + MAC + EVM can protect system integrity online and detect offline tampering. This patch set applies to the security-testing/next tree. They prereq remove-kref-set.patch (https://patchwork.kernel.org/patch/86079). Much appreciation to Dave Hansen, Serge Hallyn, and Matt Helsley for reviewing the patches. Mimi Mimi Zohar (14): integrity: move ima inode integrity data management security: move LSM xattrnames to xattr.h xattr: define vfs_getxattr_alloc and vfs_xattr_cmp evm: re-release ima: move ima_file_free before releasing the file security: imbed evm calls in security hooks evm: inode post removexattr evm: imbed evm_inode_post_setattr evm: inode_post_init fs: add evm_inode_post_init calls ima: integrity appraisal extension ima: appraise default rules ima: inode post_setattr ima: add ima_inode_setxattr and ima_inode_removexattr |
|
From: Mimi Z. <zo...@li...> - 2010-03-15 12:43:47
|
On Mon, 2010-03-15 at 10:50 +0100, Roberto Sassu wrote: > Hello all > > i was thinking about remote attestation and the data that IMA makes available. > I see in the measurement list the complete path of measured files is not > displayed; instead only the dentry name is included. My question is about the > reason: i know that calling the d_path() function to retrieve the complete > path has impact in the performance, but maybe there are different motivations, > like the fact that from the value used to extend the PCR the verificator is > able to identify immediately the "type" of the file. For example: we suppose > that two clients with different distributions have the same version of the libc > but stored in different path; the verificator is able to immediately assure, > from the digest used to extend the pcr, that the two clients have loaded the > same file, which is a version of the libc. > Does the measurement list layout of IMA is that due to performance concerns or > there are other motivations like this mentioned in the example? > > Thanks in advance for replies. Hi Roberto! I wish the reason for not including the full pathname was for a good reason. At the time, calling d_path() was unacceptable, but many things have changed since, including support for Tomoyo, which is path based. I haven't had a chance to look at the Kconfig 'SECURITY_PATH' option. It's probably a good time to revisit this issue. Now that IMA is template based, the information included in the template data is not just a hint anymore, as it is included in the hash. So besides for a full pathname, is there anything else that would make file identification easier? Thanks! Mimi |
|
From: Roberto S. <rob...@po...> - 2010-03-15 09:50:35
|
Hello all i was thinking about remote attestation and the data that IMA makes available. I see in the measurement list the complete path of measured files is not displayed; instead only the dentry name is included. My question is about the reason: i know that calling the d_path() function to retrieve the complete path has impact in the performance, but maybe there are different motivations, like the fact that from the value used to extend the PCR the verificator is able to identify immediately the "type" of the file. For example: we suppose that two clients with different distributions have the same version of the libc but stored in different path; the verificator is able to immediately assure, from the digest used to extend the pcr, that the two clients have loaded the same file, which is a version of the libc. Does the measurement list layout of IMA is that due to performance concerns or there are other motivations like this mentioned in the example? Thanks in advance for replies. |
|
From: Mimi Z. <zo...@li...> - 2010-02-19 21:28:45
|
On Fri, 2010-02-19 at 15:42 +0100, Roberto Sassu wrote:
> > Hello all
> >
> > i'm wondering what assumptions must be made in order to assure that the domain
> > "domX" is the only subject allowed to access a file with type "typeY" in a
> > system where off-line attacks are possible and an integrity check on files and
> > labels in the overall filesystem is not applicable due to the high performance
> > penalty.
> >
> > These are the hypothesis i think are required:
> > 1) kernel with SELinux, with policy loading and enforcing mode setting
> > disabled at runtime;
> > 2) there is an integrity system stacked with SELinux which is able to
> > grant/deny access depending on the hash and the label of files (checks will be
> > performed only a subset of files, as described in the following points);
> > 3)"local_login_t" is the only domain allowed to change the process label;
> > 4) every file used by the type "local_login_t" is integrity protected (i need
> > to build a list files used by this process and to specify a valid hash)
> > 5) the regular user which plays with "domX" is mapped with the selinux user
> > "user_t" (probably i need extra assumptions to protect the mapping);
> > 6) "domX_exec_t" is the only entrypoint for "domX";
> > 7) the label "domX_exec_t" is bound to the executable and its hash (the
> > association is verified at execution time);
> > 8) the transition "user_t -> domX" has been defined when executing a file
> > labeled with "domX_exec_t";
> > 9) for now i assume that the user root is not involved in this use case;
> > 10) file labelled with "typeY" are protected and the label is bound to the
> > hash (the association will be verified at access time);
> > 11) none subject is authorized to relabelfrom "typeY";
> >
> > Then when defining the rule:
> > allow domX typeY: file { getattr open read };
> >
> > can i say that files labelled with typeY can be read only by the process
> > started from the executable labelled with "domX_exec_t"?
> >
> > Thanks in advance for replies
Assuming the protection mechanism itself (kernel and associated
policies) is protected as well as the selected file data and metadata,
then this should work. There are some subtleties, such as all
directories in path to the labeled files must be protected, to block
renaming/relocation attacks (exchanging a valid rm for a valid ls).
We're looking at doing something similar. As you mentioned, protecting
the overall system has too high a penalty, so we're looking at
protecting just the files owned by root as the default policy.
I'm adding an integrity appraisal extension to IMA, which will maintain
the hash in security.ima. To protect the extended attribute from
off-line attack, EVM will maintain an hmac across the set of security
extended attributes. (Both sets of patches coming shortly.)
The initial patches will authenticate the selected extended attributes,
and cryptographically bind them to the inode; however, additional work
will still be needed to bind other directory and inode metadata for more
complete protection.
Mimi
|
|
From: Roberto S. <rob...@po...> - 2010-02-19 14:42:15
|
|
From: Amruta G. G. <am...@cs...> - 2009-12-01 15:23:45
|
Thanks Reiner, Seiji for the reply. I might use a non-XML format, since it would suffice my purpose. Regards, Amruta On Mon, 30 Nov 2009 14:05:31 +0900 Seiji Munetoh <sei...@gm...> wrote: > On Fri, Nov 27, 2009 at 5:35 AM, Amruta G. Gokhale > <am...@cs...> wrote: > > The IBM web-page given here -- > > > http://domino.research.ibm.com/comm/research_projects.nsf/pages/ssd_ima.index.html/$FILE/response.xml > > -- illustrates a sample response sent from prover to verifier. My > > question is, do I need to use XML to exchange messages between > prover > > and verifier? (I suppose XML was used to make it language > independent > > and platform independent.. are there other benefits of using XML?) > > For your reference, > TCG has been defined several XML schema to describe these messages. > > http://www.trustedcomputinggroup.org/resources/tcg_xml_schemas/ > > They are much more complicated. > Of course, If you do not need any interoperability, you can use any > format > what you like. :-) > > We had been developed Open Platform Trust Services (OpenPTS) based on > these schema. > > regards > -- > Seiji Munetoh |
|
From: z. <zha...@qq...> - 2009-11-30 07:37:48
|
hello all,
I have a question about the part "Integrity Challenge Mechanism" in "Design and Implementation of a TCG-based Integrity Measurement Architecture"
Assuming a situation like this, an compromised system extend PCR-11 with a measurement list of another (non-compromised) system. Then the compromised system uses "Integrity Challenge Protocol" that you described, but he uses PCR-11 and the measurement list of another (non-compromised) system.
How you deal the above situation???
Thank you very much. |
|
From: Seiji M. <sei...@gm...> - 2009-11-30 05:05:42
|
On Fri, Nov 27, 2009 at 5:35 AM, Amruta G. Gokhale <am...@cs...> wrote: > The IBM web-page given here -- > http://domino.research.ibm.com/comm/research_projects.nsf/pages/ssd_ima.index.html/$FILE/response.xml > -- illustrates a sample response sent from prover to verifier. My > question is, do I need to use XML to exchange messages between prover > and verifier? (I suppose XML was used to make it language independent > and platform independent.. are there other benefits of using XML?) For your reference, TCG has been defined several XML schema to describe these messages. http://www.trustedcomputinggroup.org/resources/tcg_xml_schemas/ They are much more complicated. Of course, If you do not need any interoperability, you can use any format what you like. :-) We had been developed Open Platform Trust Services (OpenPTS) based on these schema. regards -- Seiji Munetoh |
|
From: Mimi Z. <zo...@li...> - 2009-11-29 05:44:01
|
On Thu, 2009-11-26 at 11:04 +0100, Roberto Sassu wrote: > Hello all > > i have a question about the code of the ima_path_check() function located in > the file security/integrity/ima/ima_main.c of the kernel sources, version > 2.6.31.6. > > I see at some point the functions dget, mntget are called but i've not found > the correspondent dput and mntput used to decrease the reference counts > respectively for the dentry and vfsmount structure. There is a reason for that > or these functions are missing? > > Thanks for replies On dentry_open() failure, dentry_open() decrements the counters. On success, fput, at the bottom of the function, decrements the counters. Mimi |
|
From: Amruta G. G. <am...@cs...> - 2009-11-26 21:35:50
|
Hello, I am trying to develop an application which would do remote attestation using the measurement list produced by IMA. It is a simple prover-verifier set-up where the prover will present the measurement list along with the aggregate value stored in PCR and the verifier will check whether the measurements match. The two machine would be remote and will communicate over the network. The IBM web-page given here -- http://domino.research.ibm.com/comm/research_projects.nsf/pages/ssd_ima.index.html/$FILE/response.xml -- illustrates a sample response sent from prover to verifier. My question is, do I need to use XML to exchange messages between prover and verifier? (I suppose XML was used to make it language independent and platform independent.. are there other benefits of using XML?) Thank you, in advance, for any suggestions offered. Regards, Amruta |
|
From: Roberto S. <rob...@po...> - 2009-11-26 10:05:57
|
Hello all i have a question about the code of the ima_path_check() function located in the file security/integrity/ima/ima_main.c of the kernel sources, version 2.6.31.6. I see at some point the functions dget, mntget are called but i've not found the correspondent dput and mntput used to decrease the reference counts respectively for the dentry and vfsmount structure. There is a reason for that or these functions are missing? Thanks for replies |
|
From: Mimi Z. <zo...@li...> - 2009-11-24 21:29:17
|
On Tue, 2009-11-24 at 18:56 +0000, John Lyle wrote: > Hi, > > I've used previous versions of IMA, before it was integrated into the > Linux kernel. In the past, a handy /ima/measurereq device was present > which made it easy to modify userspace applications to measure files. I > notice that this doesn't exist now. What would you suggest I use instead? > > Thanks very much for your help, > > Best regards, > > John IMA now measures files based on policy. The ima_tcb=1 command line option enables a policy, which measures all files open for read by root, all executables, and all mmapped files. This policy can be constrained, for example, by defining LSM specific rules. For details, refer to [linux-2.6.31.x]/Documentation/ABI/testing/ima_policy. Mimi |
|
From: John L. <joh...@ke...> - 2009-11-24 19:45:47
|
Hi, I've used previous versions of IMA, before it was integrated into the Linux kernel. In the past, a handy /ima/measurereq device was present which made it easy to modify userspace applications to measure files. I notice that this doesn't exist now. What would you suggest I use instead? Thanks very much for your help, Best regards, John |
|
From: Mimi Z. <zo...@li...> - 2009-11-03 11:56:29
|
On Tue, 2009-11-03 at 16:53 +0800, zhangkai wrote: > hello, > I have another question about measuring modules. Why did not you > measuring executable files just like measuring modules? > The version of IMA distributed from this website is an LSM module, meaning it uses the LSM hooks defined in include/linux/security.h. As there is no LSM hook available when loading a kernel module, IMA defined one. The call for ima_measure_module() is in kernel/module.c. As of linux-2.6.30, IMA is now supported in the kernel. For more information refer to http://linux-ima.sourceforge.net Mimi |