@@ -13,6 +13,7 @@
#include <linux/kexec.h>
#include <crypto/hash_info.h>
struct linux_binprm;
+struct ima_ns_info;
#ifdef CONFIG_IMA
extern enum hash_algo ima_get_current_hash_algo(void);
@@ -39,7 +40,8 @@ extern int ima_measure_critical_data(const char *event_label,
const char *event_name,
const void *buf, size_t buf_len,
bool hash, u8 *digest, size_t digest_len);
-
+extern void ima_init_user_ns(struct user_namespace *ns);
+extern void ima_free_user_ns(struct user_namespace *ns);
#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
extern void ima_appraise_parse_cmdline(void);
#else
@@ -153,6 +155,16 @@ static inline int ima_measure_critical_data(const char *event_label,
return -ENOENT;
}
+static inline void ima_init_user_ns(struct user_namespace *ns)
+{
+ return;
+}
+
+static inline void ima_free_user_ns(struct user_namespace *ns)
+{
+ return;
+}
+
#endif /* CONFIG_IMA */
#ifndef CONFIG_IMA_KEXEC
@@ -2,6 +2,7 @@
#ifndef _LINUX_USER_NAMESPACE_H
#define _LINUX_USER_NAMESPACE_H
+#include <linux/ima.h>
#include <linux/kref.h>
#include <linux/nsproxy.h>
#include <linux/ns_common.h>
@@ -99,6 +100,9 @@ struct user_namespace {
#endif
struct ucounts *ucounts;
long ucount_max[UCOUNT_COUNTS];
+#ifdef CONFIG_IMA
+ struct ima_ns_info *ima_ns_info;
+#endif
} __randomize_layout;
struct ucounts {
@@ -67,6 +67,7 @@ struct user_namespace init_user_ns = {
.keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list),
.keyring_sem = __RWSEM_INITIALIZER(init_user_ns.keyring_sem),
#endif
+ /* ima_ns_info is initialized in user_namespaces_init() */
};
EXPORT_SYMBOL_GPL(init_user_ns);
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/export.h>
+#include <linux/ima.h>
#include <linux/nsproxy.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>
@@ -142,6 +143,9 @@ int create_user_ns(struct cred *new)
goto fail_keyring;
set_cred_user_ns(new, ns);
+
+ ima_init_user_ns(ns);
+
return 0;
fail_keyring:
#ifdef CONFIG_PERSISTENT_KEYRINGS
@@ -198,6 +202,7 @@ static void free_user_ns(struct work_struct *work)
}
retire_userns_sysctls(ns);
key_free_user_ns(ns);
+ ima_free_user_ns(ns);
ns_free_inum(&ns->ns);
kmem_cache_free(user_ns_cachep, ns);
dec_user_namespaces(ucounts);
@@ -1386,6 +1391,7 @@ const struct proc_ns_operations userns_operations = {
static __init int user_namespaces_init(void)
{
user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC | SLAB_ACCOUNT);
+ ima_init_user_ns(&init_user_ns);
return 0;
}
subsys_initcall(user_namespaces_init);
@@ -7,7 +7,7 @@
obj-$(CONFIG_IMA) += ima.o
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
- ima_policy.o ima_template.o ima_template_lib.o
+ ima_policy.o ima_template.o ima_template_lib.o ima_ns.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
@@ -301,6 +301,14 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
void ima_policy_stop(struct seq_file *m, void *v);
int ima_policy_show(struct seq_file *m, void *v);
+/* IMA Namespace related functions */
+struct ima_ns_info {
+ char label[40]; /* UUIDs are 37 ascii characters */
+ struct list_head entry;
+};
+const char *ima_ns_info_get_label(struct user_namespace *ns);
+int ima_ns_info_set_label(struct user_namespace *ns, const char *label);
+
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
#define IMA_APPRAISE_FIX 0x02
new file mode 100644
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * IMA Namespace Support routines
+ */
+
+#include <linux/ima.h>
+#include <linux/mutex.h>
+#include <linux/user_namespace.h>
+
+#include "ima.h"
+
+static struct kmem_cache *ima_ns_info_cache __read_mostly;
+static DEFINE_MUTEX(ns_info_list_lock);
+static LIST_HEAD(ima_ns_info_list);
+
+int ima_ns_info_set_label(struct user_namespace *ns, const char *label)
+{
+ bool found;
+ struct ima_ns_info *entry;
+
+ if (ns->ima_ns_info->label[0] != '\0')
+ /* label is already set */
+ return -EINVAL;
+
+ if (strlen(label) >= sizeof(ns->ima_ns_info->label))
+ return -E2BIG;
+
+ mutex_lock(&ns_info_list_lock);
+ list_for_each_entry(entry, &ima_ns_info_list, entry) {
+ if (strcmp(entry->label, label) == 0) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&ns_info_list_lock);
+ if (found)
+ return -EEXIST;
+
+ strcpy(ns->ima_ns_info->label, label);
+
+ return 0;
+}
+
+const char *ima_ns_info_get_label(struct user_namespace *ns)
+{
+ if (unlikely(ns->ima_ns_info->label[0] == '\0')) {
+ uuid_t uuid;
+
+ uuid_gen(&uuid);
+ sprintf(ns->ima_ns_info->label, "%pU", &uuid);
+ }
+ return ns->ima_ns_info->label;
+}
+
+void ima_init_user_ns(struct user_namespace *ns)
+{
+ struct ima_ns_info *insi;
+
+ if (unlikely(!ima_ns_info_cache))
+ ima_ns_info_cache = KMEM_CACHE(ima_ns_info, SLAB_PANIC);
+
+ insi = kmem_cache_zalloc(ima_ns_info_cache, GFP_KERNEL);
+ ns->ima_ns_info = insi;
+ INIT_LIST_HEAD(&insi->entry);
+ mutex_lock(&ns_info_list_lock);
+ list_add_tail(&insi->entry, &ima_ns_info_list);
+ mutex_unlock(&ns_info_list_lock);
+}
+
+void ima_free_user_ns(struct user_namespace *ns)
+{
+}
As a precursor to namespacing IMA a way of uniquely identifying the namespace to appear in the IMA log is needed. This log may be transported away from the running system and may be analyzed even after the system has been rebooted. Thus we need a way of identifying namespaces in the log which is unique. A label is added inside the opaque ima_ns_info structure (to make it clear this is really something which belongs to IMA) which is added to the user_namespace. The label is read with ima_ns_info_get_label() and is settable with the ima_ns_info_set_label() API. The label can only be set once and if the label isn't set before it is read, it is set to a random uuid. Before a label is accepted for set, it is checked for uniqueness against every previously used label to ensure we never get a duplicate namespace label in the log. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> --- v2: replace per user_ns uuid with ima_ns_info containing a settable label --- include/linux/ima.h | 14 ++++++- include/linux/user_namespace.h | 4 ++ kernel/user.c | 1 + kernel/user_namespace.c | 6 +++ security/integrity/ima/Makefile | 2 +- security/integrity/ima/ima.h | 8 ++++ security/integrity/ima/ima_ns.c | 73 +++++++++++++++++++++++++++++++++ 7 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 security/integrity/ima/ima_ns.c