summaryrefslogtreecommitdiffstats
path: root/security/integrity/ima/ima_fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima/ima_fs.c')
-rw-r--r--security/integrity/ima/ima_fs.c47
1 files changed, 43 insertions, 4 deletions
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 816d175da79a..3caed6de610c 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -25,6 +25,8 @@
#include "ima.h"
+static DEFINE_MUTEX(ima_write_mutex);
+
static int valid_policy = 1;
#define TMPBUFLEN 12
static ssize_t ima_show_htable_value(char __user *buf, size_t count,
@@ -261,6 +263,11 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
{
char *data = NULL;
ssize_t result;
+ int res;
+
+ res = mutex_lock_interruptible(&ima_write_mutex);
+ if (res)
+ return res;
if (datalen >= PAGE_SIZE)
datalen = PAGE_SIZE - 1;
@@ -286,6 +293,8 @@ out:
if (result < 0)
valid_policy = 0;
kfree(data);
+ mutex_unlock(&ima_write_mutex);
+
return result;
}
@@ -302,14 +311,31 @@ enum ima_fs_flags {
static unsigned long ima_fs_flags;
+#ifdef CONFIG_IMA_READ_POLICY
+static const struct seq_operations ima_policy_seqops = {
+ .start = ima_policy_start,
+ .next = ima_policy_next,
+ .stop = ima_policy_stop,
+ .show = ima_policy_show,
+};
+#endif
+
/*
* ima_open_policy: sequentialize access to the policy file
*/
static 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))
+ if (!(filp->f_flags & O_WRONLY)) {
+#ifndef CONFIG_IMA_READ_POLICY
return -EACCES;
+#else
+ if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
+ return -EACCES;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return seq_open(filp, &ima_policy_seqops);
+#endif
+ }
if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
return -EBUSY;
return 0;
@@ -326,6 +352,14 @@ static int ima_release_policy(struct inode *inode, struct file *file)
{
const char *cause = valid_policy ? "completed" : "failed";
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return 0;
+
+ if (valid_policy && ima_check_policy() < 0) {
+ cause = "failed";
+ valid_policy = 0;
+ }
+
pr_info("IMA: policy update %s\n", cause);
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
"policy_update", cause, !valid_policy, 0);
@@ -336,15 +370,21 @@ static int ima_release_policy(struct inode *inode, struct file *file)
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
return 0;
}
+
ima_update_policy();
+#ifndef CONFIG_IMA_WRITE_POLICY
securityfs_remove(ima_policy);
ima_policy = NULL;
+#else
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#endif
return 0;
}
static const struct file_operations ima_measure_policy_ops = {
.open = ima_open_policy,
.write = ima_write_policy,
+ .read = seq_read,
.release = ima_release_policy,
.llseek = generic_file_llseek,
};
@@ -382,8 +422,7 @@ int __init ima_fs_init(void)
if (IS_ERR(violations))
goto out;
- ima_policy = securityfs_create_file("policy",
- S_IWUSR,
+ ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL,
&ima_measure_policy_ops);
if (IS_ERR(ima_policy))