From: Krzysztof Struczynski krzysztof.struczynski@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49KW1 CVE: NA
--------------------------------
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.struczynski@huawei.com Reviewed-by: Zhang Tianxing zhangtianxing3@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- include/linux/ima.h | 1 + security/integrity/ima/ima.h | 4 ++- security/integrity/ima/ima_fs.c | 52 ++++++++++++++++++++++-------- security/integrity/ima/ima_init.c | 1 + security/integrity/ima/ima_ns.c | 1 + security/integrity/ima/ima_queue.c | 3 ++ 6 files changed, 48 insertions(+), 14 deletions(-)
diff --git a/include/linux/ima.h b/include/linux/ima.h index 0ab1dbf34c47..12738e37f714 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -233,6 +233,7 @@ struct ima_namespace { struct ima_policy_data *policy_data; struct integrity_iint_tree *iint_tree; struct list_head ns_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.h b/security/integrity/ima/ima.h index f757aedea66f..0e864ef80874 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -190,12 +190,14 @@ extern spinlock_t ima_queue_lock; extern spinlock_t ima_htable_lock;
struct ima_h_table { - atomic_long_t len; /* number of stored measurements in the list */ + atomic_long_t len; /* number of stored measurements in the list */ atomic_long_t violations; struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; }; extern struct ima_h_table ima_htable;
+extern atomic_long_t ima_ml_len; + static inline unsigned int ima_hash_key(u8 *digest) { /* there is no point in taking a hash of part of a digest */ diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 2ae4adfbaa82..f8a19751c80d 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -58,11 +58,12 @@ static ssize_t ima_show_htable_value(struct file *filp, char __user *buf, atomic_long_t *val = NULL; char tmpbuf[32]; /* greater than largest 'long' string value */ ssize_t len; + struct ima_namespace *ima_ns = get_current_ns();
if (filp->f_path.dentry == violations) val = &ima_htable.violations; else if (filp->f_path.dentry == runtime_measurements_count) - val = &ima_htable.len; + val = (ima_ns == &init_ima_ns) ? &ima_ml_len : &ima_ns->ml_len; #ifdef CONFIG_IMA_DIGEST_LIST else if (filp->f_path.dentry == digests_count) val = &ima_digests_htable.len; @@ -82,32 +83,57 @@ 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();
- /* 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; + 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(); + } else { + rcu_read_lock(); + list_for_each_entry_rcu(qe, &ima_ns->ns_measurements, ns_later) { + if (!l--) { + rcu_read_unlock(); + return qe; + } } + rcu_read_unlock(); } - rcu_read_unlock(); + return NULL; }
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();
/* 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)++; + if (ima_ns == &init_ima_ns) { + 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; + } else { + rcu_read_lock(); + qe = list_entry_rcu(qe->ns_later.next, struct ima_queue_entry, + ns_later); + rcu_read_unlock(); + (*pos)++;
- return (&qe->later == &ima_measurements) ? NULL : qe; + return (&qe->ns_later == &ima_ns->ns_measurements) ? NULL : qe; + } }
static void ima_measurements_stop(struct seq_file *m, void *v) diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 00c8dfea6ba8..99b9643e6763 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, .ns_measurements = LIST_HEAD_INIT(init_ima_ns.ns_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 885f12043cb3..2a4b7a23f9a7 100644 --- a/security/integrity/ima/ima_ns.c +++ b/security/integrity/ima/ima_ns.c @@ -127,6 +127,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 3aeff7b5e036..89b9c3734890 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -25,6 +25,7 @@ /* pre-allocated array of tpm_digest structures to extend a PCR */ static struct tpm_digest *digests;
+atomic_long_t ima_ml_len = ATOMIC_LONG_INIT(0); /* number of stored measurements in the list */ LIST_HEAD(ima_measurements); /* list of all measurements */ #ifdef CONFIG_IMA_KEXEC static unsigned long binary_runtime_size; @@ -113,6 +114,8 @@ static int ima_add_digest_entry(struct ima_template_entry *entry, list_add_tail_rcu(&qe->ns_later, &ima_ns->ns_measurements);
atomic_long_inc(&ima_htable.len); + atomic_long_inc(&ima_ml_len); + atomic_long_inc(&ima_ns->ml_len); if (update_htable) { key = ima_hash_key(entry->digests[ima_hash_algo_idx].digest); spin_lock(&ima_htable_lock);