From: Krzysztof Struczynski <krzysztof.struczyn...@huawei.com>

Modify ima securityfs interface, so that only measurement list entries
that belong to the given ima namespace are visible/counted. The initial
ima namespace is an exception, its processes have access to all
measurement list entries.

Signed-off-by: Krzysztof Struczynski <krzysztof.struczyn...@huawei.com>
---
 include/linux/ima.h                |  1 +
 security/integrity/ima/ima_fs.c    | 57 ++++++++++++++++++++++++++----
 security/integrity/ima/ima_init.c  |  1 +
 security/integrity/ima/ima_ns.c    |  1 +
 security/integrity/ima/ima_queue.c |  8 +++++
 5 files changed, 61 insertions(+), 7 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index df22143ffe30..d59ed38a4305 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -203,6 +203,7 @@ struct ima_namespace {
        struct ima_policy_data *policy_data;
        struct integrity_iint_tree *iint_tree;
        struct list_head *measurements;
+       atomic_long_t ml_len; /* number of stored measurements in the list */
 } __randomize_layout;
 
 extern struct ima_namespace init_ima_ns;
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 4758e14c4a7b..e2893f0b0f31 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -63,7 +63,9 @@ static ssize_t ima_show_measurements_count(struct file *filp,
                                           char __user *buf,
                                           size_t count, loff_t *ppos)
 {
-       return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
+       struct ima_namespace *ima_ns = get_current_ns();
+
+       return ima_show_htable_value(buf, count, ppos, &ima_ns->ml_len);
 
 }
 
@@ -77,10 +79,36 @@ static void *ima_measurements_start(struct seq_file *m, 
loff_t *pos)
 {
        loff_t l = *pos;
        struct ima_queue_entry *qe;
+       struct ima_namespace *ima_ns = get_current_ns();
+       unsigned int ns_id = get_ns_id(ima_ns);
+
+       if (ima_ns == &init_ima_ns) {
+               /* we need a lock since pos could point beyond last element */
+               rcu_read_lock();
+               list_for_each_entry_rcu(qe, &ima_measurements, later) {
+                       if (!l--) {
+                               rcu_read_unlock();
+                               return qe;
+                       }
+               }
+               rcu_read_unlock();
+               return NULL;
+       }
 
-       /* we need a lock since pos could point beyond last element */
        rcu_read_lock();
-       list_for_each_entry_rcu(qe, &ima_measurements, later) {
+       qe = list_next_or_null_rcu(&ima_measurements,
+                                  ima_ns->measurements,
+                                  struct ima_queue_entry,
+                                  later);
+       if (!qe) {
+               rcu_read_unlock();
+               return NULL;
+       }
+
+       list_for_each_entry_from_rcu(qe, &ima_measurements, later) {
+               if (ns_id != qe->entry->ns_id)
+                       continue;
+
                if (!l--) {
                        rcu_read_unlock();
                        return qe;
@@ -93,12 +121,27 @@ static void *ima_measurements_start(struct seq_file *m, 
loff_t *pos)
 static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
 {
        struct ima_queue_entry *qe = v;
+       struct ima_namespace *ima_ns = get_current_ns();
+       unsigned int ns_id = get_ns_id(ima_ns);
+
+       if (ima_ns == &init_ima_ns) {
+               /* lock protects when reading beyond last element
+                * against concurrent list-extension
+                */
+               rcu_read_lock();
+               qe = list_entry_rcu(qe->later.next, struct ima_queue_entry,
+                                   later);
+               rcu_read_unlock();
+               (*pos)++;
+
+               return (&qe->later == &ima_measurements) ? NULL : qe;
+       }
 
-       /* lock protects when reading beyond last element
-        * against concurrent list-extension
-        */
        rcu_read_lock();
-       qe = list_entry_rcu(qe->later.next, struct ima_queue_entry, later);
+       list_for_each_entry_continue_rcu(qe, &ima_measurements, later) {
+               if (ns_id == qe->entry->ns_id)
+                       break;
+       }
        rcu_read_unlock();
        (*pos)++;
 
diff --git a/security/integrity/ima/ima_init.c 
b/security/integrity/ima/ima_init.c
index 2100ee341dfc..ac9509d8c0f0 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -36,6 +36,7 @@ struct ima_namespace init_ima_ns = {
        .policy_data = &init_policy_data,
        .iint_tree = &init_iint_tree,
        .measurements = &ima_measurements,
+       .ml_len = ATOMIC_LONG_INIT(0),
 };
 EXPORT_SYMBOL(init_ima_ns);
 
diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c
index f331187a4d3c..81de492baa99 100644
--- a/security/integrity/ima/ima_ns.c
+++ b/security/integrity/ima/ima_ns.c
@@ -126,6 +126,7 @@ static struct ima_namespace *clone_ima_ns(struct 
user_namespace *user_ns,
        ns->user_ns = get_user_ns(user_ns);
        ns->ucounts = ucounts;
        ns->frozen = false;
+       atomic_long_set(&ns->ml_len, 0);
 
        rwlock_init(&ns->iint_tree->lock);
        ns->iint_tree->root = RB_ROOT;
diff --git a/security/integrity/ima/ima_queue.c 
b/security/integrity/ima/ima_queue.c
index bd890778c5be..ec5b3ca3ef92 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -227,6 +227,14 @@ int ima_add_template_entry(struct ima_template_entry 
*entry, int violation,
                goto out;
        }
 
+       /* Initial ima namespace has access to all measurement list entries,
+        * therefore always increment its measurement list length. Other
+        * namespaces can see only their own entries.
+        */
+       if (ima_ns != &init_ima_ns)
+               atomic_long_inc(&ima_ns->ml_len);
+       atomic_long_inc(&init_ima_ns.ml_len);
+
        if (violation)          /* invalidate pcr */
                digests_arg = digests;
 
-- 
2.20.1

Reply via email to