Re: [RFC] ima: export the measurement list when needed

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Attached a variant of the patch from that time that only does the
element free and relies on the userspace reading the data.

The reason why I stopped working on this at the time was that below
was sufficient for my needs. However, after a discussion between Mimi
and myself (based on a suggestion by Amir Goldstein) we realized that
we could do something considerably more elegant through vfs_tmpfile.
It's also much more work.

The way this could probably work the best is if we would implement a
new allocator that would pull pages from a vmarea tied to a
vfs_tmpfile and the file could be opened by the kernel itself during
the ima init. Now if all the measurement list data blobs would be
allocated through this allocator the pages would never be permanently
resident in the kernel, they would only visit the memory for a while
when someone reads the data. If done this way the allocator probably
does not even need a 'free' and the mm code would do all the real work
pushing the data out.

The benefits would be that no-one would ever have to poll from
userspace (kernel does not depend on the userspace to work) and we
would never OOM because of IMA as long as the filesystem is writable.
Also we would never lose any data as long as the file system is
functioning.

Thoughts?


--
Janne

On Wed, Aug 26, 2020 at 11:14 AM Janne Karhunen
<janne.karhunen@xxxxxxxxx> wrote:
>
> Hi Raphael,
>
> Sorry I missed the reply. I'm not working on this right now, feel free
> to grab. Please copy me with the results, thank you.
>
>
> --
> Janne
>
> On Tue, Aug 18, 2020 at 12:30 AM Raphael Gianotti
> <raphgi@xxxxxxxxxxxxxxxxxxx> wrote:
> >
> >
> > Hi Janne,
> >
> > Subject: Re: [RFC] ima: export the measurement list when needed
> > > Date: Wed, 18 Dec 2019 17:11:22 +0200
> > > From: Janne Karhunen <janne.karhunen@xxxxxxxxx>
> > > To: linux-integrity@xxxxxxxxxxxxxxx, Mimi Zohar <zohar@xxxxxxxxxxxxx>
> > > CC: Ken Goldman <kgold@xxxxxxxxxxxxx>, david.safford@xxxxxxxxx,
> > > monty.wiseman@xxxxxx
> > >
> > > Hi,
> > >
> > > Have in mind that below is the first trial draft that booted and
> > > seemingly accomplished the task once, it was not really tested at all
> > > yet. I will make a polished and tested version if people like the
> > > concept.
> > >
> > > Note that the code (almost) supports pushing and pulling of the
> > > entries. This variant is a simple pull given that the list size is
> > > above the defined limits. Pushing can be put in place if the recursion
> > > with the list extend_list_mutex is cleared, maybe this could be done
> > > via another patch later on when we have a workqueue for the export
> > > task? The workqueue might be the best context for the export job since
> > > clearing the list is a heavy operation (and it's not entirely correct
> > > here AFAIK, there is no rcu sync before the template free).
> > >
> > >
> > > -- Janne
> > >
> > > On Wed, Dec 18, 2019 at 2:53 PM Janne Karhunen
> > > <janne.karhunen@xxxxxxxxx> wrote:
> > >>
> > >> Some systems can end up carrying lots of entries in the ima
> > >> measurement list. Since every entry is using a bit of kernel
> > >> memory, add a new Kconfig variable to allow the sysadmin to
> > >> define the maximum measurement list size and the location
> > >> of the exported list.
> > >>
> > >> The list is written out in append mode, so the system will
> > >> keep writing new entries as long as it stays running or runs
> > >> out of space. File is also automatically truncated on startup.
> > >>
> > >> Signed-off-by: Janne Karhunen <janne.karhunen@xxxxxxxxx>
> > >> ---
> > >>  security/integrity/ima/Kconfig     |  10 ++
> > >>  security/integrity/ima/ima.h       |   7 +-
> > >>  security/integrity/ima/ima_fs.c    | 178 +++++++++++++++++++++++++++++
> > >>  security/integrity/ima/ima_queue.c |   2 +-
> > >>  4 files changed, 192 insertions(+), 5 deletions(-)
> >
> > I've been looking into a solution to this same issue you started some
> > work on. I was wondering if you are still working on it. I was
> > considering taking your initial prototyping on this and extending it
> > into a final solution, but I wanted to reply here first and check if you
> > are currently working on this.
> >
From be120a15c8d81655bf112334e3279b19415c2ca2 Mon Sep 17 00:00:00 2001
From: Janne Karhunen <janne.karhunen@xxxxxxxxx>
Date: Mon, 16 Dec 2019 12:59:30 +0200
Subject: [PATCH v3] ima: allow the measurement list flush

Some systems can end up carrying lots of entries in the ima
measurement list. Since every entry is using a bit of kernel
memory, allow the sysadmin to free any amount of entries and
handle the list export manually.

Changelog:
v3:
- Depend on the userspace doing the file export, only allow
  the list flush.

Signed-off-by: Janne Karhunen <janne.karhunen@xxxxxxxxx>
---
 security/integrity/ima/ima.h       |  6 +--
 security/integrity/ima/ima_fs.c    | 65 ++++++++++++++++++++++++++++++
 security/integrity/ima/ima_queue.c |  2 +-
 3 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 64317d95363e..821a0f1d832f 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -153,6 +153,7 @@ int template_desc_init_fields(const char *template_fmt,
 struct ima_template_desc *ima_template_desc_current(void);
 struct ima_template_desc *lookup_template_desc(const char *name);
 bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
+void ima_free_template_entry(struct ima_template_entry *entry);
 int ima_restore_measurement_entry(struct ima_template_entry *entry);
 int ima_restore_measurement_list(loff_t bufsize, void *buf);
 int ima_measurements_show(struct seq_file *m, void *v);
@@ -163,10 +164,7 @@ int __init ima_init_digests(void);
 int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
 			  void *lsm_data);
 
-/*
- * used to protect h_table and sha_table
- */
-extern spinlock_t ima_queue_lock;
+extern struct mutex ima_extend_list_mutex;
 
 struct ima_h_table {
 	atomic_long_t len;	/* number of stored measurements in the list */
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index a71e822a6e92..104f828b9444 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -360,6 +360,7 @@ static struct dentry *ascii_runtime_measurements;
 static struct dentry *runtime_measurements_count;
 static struct dentry *violations;
 static struct dentry *ima_policy;
+static struct dentry *ima_flush_measurements;
 
 enum ima_fs_flags {
 	IMA_FS_BUSY,
@@ -447,6 +448,62 @@ static const struct file_operations ima_measure_policy_ops = {
 	.llseek = generic_file_llseek,
 };
 
+static long ima_free_entries(long ec)
+{
+	struct ima_queue_entry *qe, *e;
+	long c;
+
+	c = atomic_long_read(&ima_htable.len);
+	if (ec > c)
+		return -EINVAL;
+
+	c = 0;
+	mutex_lock(&ima_extend_list_mutex);
+	list_for_each_entry_safe(qe, e, &ima_measurements, later) {
+		if (c++ > ec)
+			break;
+
+		hlist_del_rcu(&qe->hnext);
+		atomic_long_dec(&ima_htable.len);
+
+		list_del_rcu(&qe->later);
+		ima_free_template_entry(qe->entry);
+		kfree(qe);
+	}
+	mutex_unlock(&ima_extend_list_mutex);
+	return c;
+}
+
+static ssize_t ima_flush_write(struct file *filp,
+			       const char __user *buf,
+			       size_t count, loff_t *ppos)
+{
+	char anum[32];
+	long num;
+	int err;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!count || (count >= 32))
+		return -EINVAL;
+	memset(anum, 0, 32);
+
+	err = copy_from_user(anum, buf, count);
+	if (err)
+		return err;
+	if (anum[count-1] == '\n')
+		anum[count-1] = 0;
+	err = kstrtol(anum, 0, &num);
+	if (err)
+		return err;
+
+	return ima_free_entries(num);
+}
+
+static const struct file_operations ima_flush_ops = {
+	.write = ima_flush_write,
+};
+
 int __init ima_fs_init(void)
 {
 	ima_dir = securityfs_create_dir("ima", integrity_dir);
@@ -491,6 +548,12 @@ int __init ima_fs_init(void)
 	if (IS_ERR(ima_policy))
 		goto out;
 
+	ima_flush_measurements =
+	    securityfs_create_file("flush_measurements", 0200, ima_dir,
+				   NULL, &ima_flush_ops);
+	if (IS_ERR(ima_flush_measurements))
+		goto out;
+
 	return 0;
 out:
 	securityfs_remove(violations);
@@ -500,5 +563,7 @@ int __init ima_fs_init(void)
 	securityfs_remove(ima_symlink);
 	securityfs_remove(ima_dir);
 	securityfs_remove(ima_policy);
+	securityfs_remove(ima_flush_measurements);
+
 	return -1;
 }
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 8753212ddb18..4eee0bbf2647 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -42,7 +42,7 @@ struct ima_h_table ima_htable = {
  * and extending the TPM PCR aggregate. Since tpm_extend can take
  * long (and the tpm driver uses a mutex), we can't use the spinlock.
  */
-static DEFINE_MUTEX(ima_extend_list_mutex);
+DEFINE_MUTEX(ima_extend_list_mutex);
 
 /* lookup up the digest value in the hash table, and return the entry */
 static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
-- 
2.17.1


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux