aboutsummaryrefslogtreecommitdiff
path: root/security/integrity/ima
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima')
-rw-r--r--security/integrity/ima/ima_audit.c32
-rw-r--r--security/integrity/ima/ima_crypto.c4
-rw-r--r--security/integrity/ima/ima_fs.c12
-rw-r--r--security/integrity/ima/ima_iint.c2
-rw-r--r--security/integrity/ima/ima_init.c4
-rw-r--r--security/integrity/ima/ima_main.c86
-rw-r--r--security/integrity/ima/ima_policy.c48
7 files changed, 100 insertions, 88 deletions
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c
index 1e082bb987b..ff513ff737f 100644
--- a/security/integrity/ima/ima_audit.c
+++ b/security/integrity/ima/ima_audit.c
@@ -22,18 +22,9 @@ static int ima_audit;
static int __init ima_audit_setup(char *str)
{
unsigned long audit;
- int rc, result = 0;
- char *op = "ima_audit";
- char *cause;
- rc = strict_strtoul(str, 0, &audit);
- if (rc || audit > 1)
- result = 1;
- else
- ima_audit = audit;
- cause = ima_audit ? "enabled" : "not_enabled";
- integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
- op, cause, result, 0);
+ if (!strict_strtoul(str, 0, &audit))
+ ima_audit = audit ? 1 : 0;
return 1;
}
__setup("ima_audit=", ima_audit_setup);
@@ -50,23 +41,14 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u",
- current->pid, current->cred->uid,
+ current->pid, current_cred()->uid,
audit_get_loginuid(current),
audit_get_sessionid(current));
audit_log_task_context(ab);
- switch (audit_msgno) {
- case AUDIT_INTEGRITY_DATA:
- case AUDIT_INTEGRITY_METADATA:
- case AUDIT_INTEGRITY_PCR:
- case AUDIT_INTEGRITY_STATUS:
- audit_log_format(ab, " op=%s cause=%s", op, cause);
- break;
- case AUDIT_INTEGRITY_HASH:
- audit_log_format(ab, " op=%s hash=%s", op, cause);
- break;
- default:
- audit_log_format(ab, " op=%s", op);
- }
+ audit_log_format(ab, " op=");
+ audit_log_string(ab, op);
+ audit_log_format(ab, " cause=");
+ audit_log_string(ab, cause);
audit_log_format(ab, " comm=");
audit_log_untrustedstring(ab, current->comm);
if (fname) {
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 50d572b74ca..63003a63aae 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -103,7 +103,7 @@ int ima_calc_template_hash(int template_len, void *template, char *digest)
return rc;
}
-static void ima_pcrread(int idx, u8 *pcr)
+static void __init ima_pcrread(int idx, u8 *pcr)
{
if (!ima_used_chip)
return;
@@ -115,7 +115,7 @@ static void ima_pcrread(int idx, u8 *pcr)
/*
* Calculate the boot aggregate hash
*/
-int ima_calc_boot_aggregate(char *digest)
+int __init ima_calc_boot_aggregate(char *digest)
{
struct hash_desc desc;
struct scatterlist sg;
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index ffbe259700b..6bfc7eaebfd 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -15,6 +15,7 @@
* implemenents security file system for reporting
* current measurement list and IMA statistics
*/
+#include <linux/fcntl.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/rculist.h>
@@ -84,8 +85,8 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
* against concurrent list-extension
*/
rcu_read_lock();
- qe = list_entry(rcu_dereference(qe->later.next),
- struct ima_queue_entry, later);
+ qe = list_entry_rcu(qe->later.next,
+ struct ima_queue_entry, later);
rcu_read_unlock();
(*pos)++;
@@ -283,6 +284,9 @@ static atomic_t policy_opencount = ATOMIC_INIT(1);
*/
int ima_open_policy(struct inode * inode, struct file * filp)
{
+ /* No point in being allowed to open it if you aren't going to write */
+ if (!(filp->f_flags & O_WRONLY))
+ return -EACCES;
if (atomic_dec_and_test(&policy_opencount))
return 0;
return -EBUSY;
@@ -315,7 +319,7 @@ static struct file_operations ima_measure_policy_ops = {
.release = ima_release_policy
};
-int ima_fs_init(void)
+int __init ima_fs_init(void)
{
ima_dir = securityfs_create_dir("ima", NULL);
if (IS_ERR(ima_dir))
@@ -349,7 +353,7 @@ int ima_fs_init(void)
goto out;
ima_policy = securityfs_create_file("policy",
- S_IRUSR | S_IRGRP | S_IWUSR,
+ S_IWUSR,
ima_dir, NULL,
&ima_measure_policy_ops);
if (IS_ERR(ima_policy))
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
index ec79f1ee992..b8dd693f879 100644
--- a/security/integrity/ima/ima_iint.c
+++ b/security/integrity/ima/ima_iint.c
@@ -196,7 +196,7 @@ static void init_once(void *foo)
kref_set(&iint->refcount, 1);
}
-void ima_iintcache_init(void)
+void __init ima_iintcache_init(void)
{
iint_cache =
kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 0b0bb8c978c..a40da7ae590 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -38,7 +38,7 @@ int ima_used_chip;
* a different value.) Violations add a zero entry to the measurement
* list and extend the aggregate PCR value with ff...ff's.
*/
-static void ima_add_boot_aggregate(void)
+static void __init ima_add_boot_aggregate(void)
{
struct ima_template_entry *entry;
const char *op = "add_boot_aggregate";
@@ -71,7 +71,7 @@ err_out:
audit_cause, result, 0);
}
-int ima_init(void)
+int __init ima_init(void)
{
u8 pcr_i[IMA_DIGEST_SIZE];
int rc;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index f4e7266f5ae..6f611874d10 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -29,20 +29,8 @@ int ima_initialized;
char *ima_hash = "sha1";
static int __init hash_setup(char *str)
{
- const char *op = "hash_setup";
- const char *hash = "sha1";
- int result = 0;
- int audit_info = 0;
-
- if (strncmp(str, "md5", 3) == 0) {
- hash = "md5";
- ima_hash = str;
- } else if (strncmp(str, "sha1", 4) != 0) {
- hash = "invalid_hash_type";
- result = 1;
- }
- integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash,
- result, audit_info);
+ if (strncmp(str, "md5", 3) == 0)
+ ima_hash = "md5";
return 1;
}
__setup("ima_hash=", hash_setup);
@@ -128,10 +116,6 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
{
int rc = 0;
- if (IS_ERR(file)) {
- pr_info("%s dentry_open failed\n", filename);
- return rc;
- }
iint->opencount++;
iint->readcount++;
@@ -141,6 +125,15 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
return rc;
}
+static void ima_update_counts(struct ima_iint_cache *iint, int mask)
+{
+ iint->opencount++;
+ if ((mask & MAY_WRITE) || (mask == 0))
+ iint->writecount++;
+ else if (mask & (MAY_READ | MAY_EXEC))
+ iint->readcount++;
+}
+
/**
* ima_path_check - based on policy, collect/store measurement.
* @path: contains a pointer to the path to be measured
@@ -156,10 +149,10 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
* - Opening a file for read when already open for write,
* could result in a file measurement error.
*
- * Return 0 on success, an error code on failure.
- * (Based on the results of appraise_measurement().)
+ * Always return 0 and audit dentry_open failures.
+ * (Return code will be based upon measurement appraisal.)
*/
-int ima_path_check(struct path *path, int mask)
+int ima_path_check(struct path *path, int mask, int update_counts)
{
struct inode *inode = path->dentry->d_inode;
struct ima_iint_cache *iint;
@@ -173,11 +166,8 @@ int ima_path_check(struct path *path, int mask)
return 0;
mutex_lock(&iint->mutex);
- iint->opencount++;
- if ((mask & MAY_WRITE) || (mask == 0))
- iint->writecount++;
- else if (mask & (MAY_READ | MAY_EXEC))
- iint->readcount++;
+ if (update_counts)
+ ima_update_counts(iint, mask);
rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
if (rc < 0)
@@ -196,7 +186,19 @@ int ima_path_check(struct path *path, int mask)
struct dentry *dentry = dget(path->dentry);
struct vfsmount *mnt = mntget(path->mnt);
- file = dentry_open(dentry, mnt, O_RDONLY, current->cred);
+ file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE,
+ current_cred());
+ if (IS_ERR(file)) {
+ int audit_info = 0;
+
+ integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+ dentry->d_name.name,
+ "add_measurement",
+ "dentry_open failed",
+ 1, audit_info);
+ file = NULL;
+ goto out;
+ }
rc = get_path_measurement(iint, file, dentry->d_name.name);
}
out:
@@ -206,6 +208,7 @@ out:
kref_put(&iint->refcount, iint_free);
return 0;
}
+EXPORT_SYMBOL_GPL(ima_path_check);
static int process_measurement(struct file *file, const unsigned char *filename,
int mask, int function)
@@ -234,7 +237,16 @@ out:
return rc;
}
-static void opencount_get(struct file *file)
+/*
+ * ima_opens_get - increment file counts
+ *
+ * - for IPC shm and shmat file.
+ * - for nfsd exported files.
+ *
+ * Increment the counts for these files to prevent unnecessary
+ * imbalance messages.
+ */
+void ima_counts_get(struct file *file)
{
struct inode *inode = file->f_dentry->d_inode;
struct ima_iint_cache *iint;
@@ -246,8 +258,14 @@ static void opencount_get(struct file *file)
return;
mutex_lock(&iint->mutex);
iint->opencount++;
+ if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
+ iint->readcount++;
+
+ if (file->f_mode & FMODE_WRITE)
+ iint->writecount++;
mutex_unlock(&iint->mutex);
}
+EXPORT_SYMBOL_GPL(ima_counts_get);
/**
* ima_file_mmap - based on policy, collect/store measurement.
@@ -272,18 +290,6 @@ int ima_file_mmap(struct file *file, unsigned long prot)
return 0;
}
-/*
- * ima_shm_check - IPC shm and shmat create/fput a file
- *
- * Maintain the opencount for these files to prevent unnecessary
- * imbalance messages.
- */
-void ima_shm_check(struct file *file)
-{
- opencount_get(file);
- return;
-}
-
/**
* ima_bprm_check - based on policy, collect/store measurement.
* @bprm: contains the linux_binprm structure
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index b5291ad5ef5..e1278399b34 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -45,24 +45,30 @@ struct ima_measure_rule_entry {
} lsm[MAX_LSM_RULES];
};
-/* Without LSM specific knowledge, the default policy can only be
+/*
+ * Without LSM specific knowledge, the default policy can only be
* written in terms of .action, .func, .mask, .fsmagic, and .uid
*/
+
+/*
+ * The minimum rule set to allow for full TCB coverage. Measures all files
+ * opened or mmap for exec and everything read by root. Dangerous because
+ * normal users can easily run the machine out of memory simply building
+ * and running executables.
+ */
static struct ima_measure_rule_entry default_rules[] = {
- {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,
- .flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
- {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,
- .flags = IMA_FSMAGIC},
- {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
{.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
.flags = IMA_FUNC | IMA_MASK},
{.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
.flags = IMA_FUNC | IMA_MASK},
{.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0,
- .flags = IMA_FUNC | IMA_MASK | IMA_UID}
+ .flags = IMA_FUNC | IMA_MASK | IMA_UID},
};
static LIST_HEAD(measure_default_rules);
@@ -71,6 +77,14 @@ static struct list_head *ima_measure;
static DEFINE_MUTEX(ima_measure_mutex);
+static bool ima_use_tcb __initdata;
+static int __init default_policy_setup(char *str)
+{
+ ima_use_tcb = 1;
+ return 1;
+}
+__setup("ima_tcb", default_policy_setup);
+
/**
* ima_match_rules - determine whether an inode matches the measure rule.
* @rule: a pointer to a rule
@@ -96,7 +110,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid)
return false;
for (i = 0; i < MAX_LSM_RULES; i++) {
- int rc;
+ int rc = 0;
u32 osid, sid;
if (!rule->lsm[i].rule)
@@ -109,7 +123,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
security_inode_getsecid(inode, &osid);
rc = security_filter_rule_match(osid,
rule->lsm[i].type,
- AUDIT_EQUAL,
+ Audit_equal,
rule->lsm[i].rule,
NULL);
break;
@@ -119,7 +133,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
security_task_getsecid(tsk, &sid);
rc = security_filter_rule_match(sid,
rule->lsm[i].type,
- AUDIT_EQUAL,
+ Audit_equal,
rule->lsm[i].rule,
NULL);
default:
@@ -164,11 +178,17 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask)
* ima_measure points to either the measure_default_rules or the
* the new measure_policy_rules.
*/
-void ima_init_policy(void)
+void __init ima_init_policy(void)
{
- int i;
+ int i, entries;
+
+ /* if !ima_use_tcb set entries = 0 so we load NO default rules */
+ if (ima_use_tcb)
+ entries = ARRAY_SIZE(default_rules);
+ else
+ entries = 0;
- for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+ for (i = 0; i < entries; i++)
list_add_tail(&default_rules[i].list, &measure_default_rules);
ima_measure = &measure_default_rules;
}
@@ -227,7 +247,7 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
entry->lsm[lsm_rule].type = audit_type;
result = security_filter_rule_init(entry->lsm[lsm_rule].type,
- AUDIT_EQUAL, args,
+ Audit_equal, args,
&entry->lsm[lsm_rule].rule);
return result;
}