linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: <krzysztof.struczynski@huawei.com>
To: <linux-integrity@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<containers@lists.linux-foundation.org>,
	<linux-security-module@vger.kernel.org>
Cc: Krzysztof Struczynski <krzysztof.struczynski@huawei.com>,
	<zohar@linux.ibm.com>, <stefanb@linux.vnet.ibm.com>,
	<sunyuqiong1988@gmail.com>, <mkayaalp@cs.binghamton.edu>,
	<dmitry.kasatkin@gmail.com>, <serge@hallyn.com>,
	<jmorris@namei.org>, <christian@brauner.io>,
	<silviu.vlasceanu@huawei.com>, <roberto.sassu@huawei.com>
Subject: [RFC PATCH 02/30] ima: Add a list of the installed ima namespaces
Date: Tue, 18 Aug 2020 17:20:09 +0200	[thread overview]
Message-ID: <20200818152037.11869-3-krzysztof.struczynski@huawei.com> (raw)
In-Reply-To: <20200818152037.11869-1-krzysztof.struczynski@huawei.com>

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

Add a list of the installed ima namespaces. IMA namespace is considered
installed, if there is at least one process born in that namespace.

This list will be used to check the read-write violations and to detect
any object related changes relevant across namespaces.

Signed-off-by: Krzysztof Struczynski <krzysztof.struczynski@huawei.com>
---
 include/linux/ima.h               |   8 ++-
 security/integrity/ima/ima.h      |  11 ++++
 security/integrity/ima/ima_init.c |   5 ++
 security/integrity/ima/ima_main.c |   3 +
 security/integrity/ima/ima_ns.c   | 101 ++++++++++++++++++++++++++++--
 5 files changed, 122 insertions(+), 6 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 4a9c29d4d056..5b6235b97603 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -10,10 +10,12 @@
 #include <linux/fs.h>
 #include <linux/security.h>
 #include <linux/kexec.h>
-struct linux_binprm;
 
+struct linux_binprm;
 struct nsproxy;
 struct task_struct;
+struct list_head;
+struct llist_node;
 
 #ifdef CONFIG_IMA
 extern int ima_bprm_check(struct linux_binprm *bprm);
@@ -176,6 +178,10 @@ struct ima_namespace {
 	struct ns_common ns;
 	struct ucounts *ucounts;
 	struct user_namespace *user_ns;
+	struct list_head list;
+	struct llist_node cleanup_list; /* namespaces on a death row */
+	atomic_t inactive; /* set only when ns is added to the cleanup list */
+	bool frozen;
 } __randomize_layout;
 
 extern struct ima_namespace init_ima_ns;
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 603da5b2db08..092e87190c6d 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -372,12 +372,23 @@ static inline int ima_read_xattr(struct dentry *dentry,
 
 #endif /* CONFIG_IMA_APPRAISE */
 
+extern struct list_head ima_ns_list;
+extern struct rw_semaphore ima_ns_list_lock;
+
 #ifdef CONFIG_IMA_NS
+int __init ima_init_namespace(void);
+
 static inline struct ima_namespace *get_current_ns(void)
 {
 	return current->nsproxy->ima_ns;
 }
 #else
+static inline int __init ima_init_namespace(void)
+{
+	list_add_tail(&init_ima_ns.list, &ima_ns_list);
+	return 0;
+}
+
 static inline struct ima_namespace *get_current_ns(void)
 {
 	return &init_ima_ns;
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 013bbec16849..0ba04a1a68cc 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -32,6 +32,7 @@ struct ima_namespace init_ima_ns = {
 #ifdef CONFIG_IMA_NS
 	.ns.ops = &imans_operations,
 #endif
+	.frozen = true
 };
 EXPORT_SYMBOL(init_ima_ns);
 
@@ -154,6 +155,10 @@ int __init ima_init(void)
 
 	ima_init_policy();
 
+	rc = ima_init_namespace();
+	if (rc != 0)
+		return rc;
+
 	rc = ima_fs_init();
 	if (rc != 0)
 		return rc;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 8a91711ca79b..d800e73c8b62 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -37,6 +37,9 @@ int ima_appraise;
 int ima_hash_algo = HASH_ALGO_SHA1;
 static int hash_setup_done;
 
+DECLARE_RWSEM(ima_ns_list_lock);
+LIST_HEAD(ima_ns_list);
+
 static struct notifier_block ima_lsm_policy_notifier = {
 	.notifier_call = ima_lsm_policy_change,
 };
diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c
index 8f5f301406a2..3a98cd536d05 100644
--- a/security/integrity/ima/ima_ns.c
+++ b/security/integrity/ima/ima_ns.c
@@ -21,9 +21,20 @@
 #include <linux/user_namespace.h>
 #include <linux/nsproxy.h>
 #include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/llist.h>
+#include <linux/rwsem.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
 
 #include "ima.h"
 
+static LLIST_HEAD(cleanup_list);
+static struct workqueue_struct *imans_wq;
+
+/* Protects tasks entering the same, not yet active namespace */
+static DEFINE_MUTEX(frozen_lock);
+
 static struct ucounts *inc_ima_namespaces(struct user_namespace *ns)
 {
 	return inc_ucount(ns, current_euid(), UCOUNT_IMA_NAMESPACES);
@@ -78,6 +89,7 @@ static struct ima_namespace *clone_ima_ns(struct user_namespace *user_ns,
 	ns->ns.ops = &imans_operations;
 	ns->user_ns = get_user_ns(user_ns);
 	ns->ucounts = ucounts;
+	ns->frozen = false;
 
 	return ns;
 
@@ -109,6 +121,19 @@ struct ima_namespace *copy_ima_ns(unsigned long flags,
 	return clone_ima_ns(user_ns, old_ns);
 }
 
+int __init ima_init_namespace(void)
+{
+	/* Create workqueue for cleanup */
+	imans_wq = create_singlethread_workqueue("imans");
+	if (unlikely(!imans_wq))
+		return -ENOMEM;
+
+	/* No other reader or writer at this stage */
+	list_add_tail(&init_ima_ns.list, &ima_ns_list);
+
+	return 0;
+}
+
 static void destroy_ima_ns(struct ima_namespace *ns)
 {
 	dec_ima_namespaces(ns->ucounts);
@@ -117,13 +142,46 @@ static void destroy_ima_ns(struct ima_namespace *ns)
 	kfree(ns);
 }
 
+static void cleanup_ima(struct work_struct *work)
+{
+	struct ima_namespace *ima_ns, *tmp;
+	struct llist_node *ima_kill_list;
+
+	/* Atomically snapshot the list of namespaces to cleanup */
+	ima_kill_list = llist_del_all(&cleanup_list);
+
+	/* Remove ima namespace from the namespace list */
+	down_write(&ima_ns_list_lock);
+	llist_for_each_entry(ima_ns, ima_kill_list, cleanup_list)
+		list_del(&ima_ns->list);
+	up_write(&ima_ns_list_lock);
+
+	/* After removing ima namespace from the ima_ns_list, memory can be
+	 * freed. At this stage nothing should keep a reference to the given
+	 * namespace.
+	 */
+	llist_for_each_entry_safe(ima_ns, tmp, ima_kill_list, cleanup_list)
+		destroy_ima_ns(ima_ns);
+}
+
+static DECLARE_WORK(ima_cleanup_work, cleanup_ima);
+
 void free_ima_ns(struct kref *kref)
 {
-	struct ima_namespace *ns;
+	struct ima_namespace *ima_ns;
 
-	ns = container_of(kref, struct ima_namespace, kref);
+	ima_ns = container_of(kref, struct ima_namespace, kref);
+	/* Namespace can be destroyed instantly if no process ever was born
+	 * into it - it was never added to the ima_ns_list.
+	 */
+	if (!ima_ns->frozen) {
+		destroy_ima_ns(ima_ns);
+		return;
+	}
 
-	destroy_ima_ns(ns);
+	atomic_set(&ima_ns->inactive, 1);
+	if (llist_add(&ima_ns->cleanup_list, &cleanup_list))
+		queue_work(imans_wq, &ima_cleanup_work);
 }
 
 static inline struct ima_namespace *to_ima_ns(struct ns_common *ns)
@@ -168,8 +226,32 @@ static void imans_put(struct ns_common *ns)
 	put_ima_ns(to_ima_ns(ns));
 }
 
+static int imans_activate(struct ima_namespace *ima_ns)
+{
+	if (ima_ns == &init_ima_ns)
+		return 0;
+
+	if (ima_ns->frozen)
+		return 0;
+
+	mutex_lock(&frozen_lock);
+	if (ima_ns->frozen)
+		goto out;
+
+	ima_ns->frozen = true;
+
+	down_write(&ima_ns_list_lock);
+	list_add_tail(&ima_ns->list, &ima_ns_list);
+	up_write(&ima_ns_list_lock);
+out:
+	mutex_unlock(&frozen_lock);
+
+	return 0;
+}
+
 static int imans_install(struct nsset *nsset, struct ns_common *new)
 {
+	int res;
 	struct nsproxy *nsproxy = nsset->nsproxy;
 	struct ima_namespace *ns = to_ima_ns(new);
 
@@ -180,6 +262,10 @@ static int imans_install(struct nsset *nsset, struct ns_common *new)
 	    !ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN))
 		return -EPERM;
 
+	res = imans_activate(ns);
+	if (res)
+		return res;
+
 	get_ima_ns(ns);
 	put_ima_ns(nsproxy->ima_ns);
 	nsproxy->ima_ns = ns;
@@ -188,11 +274,12 @@ static int imans_install(struct nsset *nsset, struct ns_common *new)
 	put_ima_ns(nsproxy->ima_ns_for_children);
 	nsproxy->ima_ns_for_children = ns;
 
-	return 0;
+	return res;
 }
 
 int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk)
 {
+	int res;
 	struct ns_common *nsc = &nsproxy->ima_ns_for_children->ns;
 	struct ima_namespace *ns = to_ima_ns(nsc);
 
@@ -200,11 +287,15 @@ int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk)
 	if (nsproxy->ima_ns == nsproxy->ima_ns_for_children)
 		return 0;
 
+	res = imans_activate(ns);
+	if (res)
+		return res;
+
 	get_ima_ns(ns);
 	put_ima_ns(nsproxy->ima_ns);
 	nsproxy->ima_ns = ns;
 
-	return 0;
+	return res;
 }
 
 static struct user_namespace *imans_owner(struct ns_common *ns)
-- 
2.20.1


  parent reply	other threads:[~2020-08-18 15:27 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <N>
2012-11-22 11:54 ` [PATCH 1/2] fs/buffer.c: do not inline exported function Yan Hong
2012-11-22 11:54   ` [PATCH 2/2] fs/buffer.c: remove redundant initialization in alloc_page_buffers() Yan Hong
2014-02-12 10:06 ` [PATCH v2] NFSv4.1: new layout stateid can not be overwrite by one out of date shaobingqing
2014-02-12 12:34   ` Trond Myklebust
2014-02-17  7:08 ` [PATCH v3] " shaobingqing
2014-02-17 16:46   ` Trond Myklebust
2014-11-04  1:47 ` [PATCH usb v4 0/2] fixes on resource check varkabhadram
2014-11-04  1:47   ` [PATCH usb v4 1/2] host: uhci-platform: fix NULL pointer dereference on resource varkabhadram
2014-11-04  1:47   ` [PATCH usb v4 2/2] host: ehci-sead3: " varkabhadram
2020-08-18 15:20 ` [RFC PATCH 00/30] ima: Introduce IMA namespace krzysztof.struczynski
2020-08-18 15:20   ` [RFC PATCH 01/30] ima: Introduce ima namespace krzysztof.struczynski
2020-08-18 15:20   ` krzysztof.struczynski [this message]
2020-08-18 15:20   ` [RFC PATCH 03/30] ima: Bind ima namespace to the file descriptor krzysztof.struczynski
2020-08-18 15:20   ` [RFC PATCH 04/30] ima: Add ima policy related data to the ima namespace krzysztof.struczynski
2020-08-18 15:20   ` [RFC PATCH 05/30] ima: Add methods for parsing ima policy configuration string krzysztof.struczynski
2020-08-18 15:20   ` [RFC PATCH 06/30] ima: Add ima namespace to the ima subsystem APIs krzysztof.struczynski
2020-08-18 15:20   ` [RFC PATCH 07/30] ima: Extend the APIs in the integrity subsystem krzysztof.struczynski
2020-08-18 15:20   ` [RFC PATCH 08/30] ima: Add integrity inode related data to the ima namespace krzysztof.struczynski
2020-08-18 15:20   ` [RFC PATCH 09/30] ima: Enable per ima namespace policy settings krzysztof.struczynski
2020-08-18 15:53   ` [RFC PATCH 00/30] ima: Introduce IMA namespace Christian Brauner
2020-08-21 15:18     ` Krzysztof Struczynski
2020-08-18 16:19   ` James Bottomley
2020-08-21 15:13     ` Krzysztof Struczynski
2020-09-02 18:53       ` Mimi Zohar
2020-09-04 14:06         ` Dr. Greg
2020-09-14 12:05         ` Krzysztof Struczynski
2020-08-18 16:49   ` Christian Brauner
2020-08-21 15:37     ` Krzysztof Struczynski
2020-09-02 19:54     ` Mimi Zohar
2020-09-06 17:14       ` Dr. Greg
     [not found]         ` <CAKrSGQR3Pw=Rad2RgUuCHqr0r2Nc6x2nLoo2cVAkD+_8Vbmd7A@mail.gmail.com>
2020-09-08 14:03           ` Mimi Zohar
2020-09-14 12:07             ` Krzysztof Struczynski
2020-10-19  9:30             ` Krzysztof Struczynski
2020-10-25 15:00               ` Dr. Greg
2020-09-09 10:11           ` Dr. Greg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200818152037.11869-3-krzysztof.struczynski@huawei.com \
    --to=krzysztof.struczynski@huawei.com \
    --cc=christian@brauner.io \
    --cc=containers@lists.linux-foundation.org \
    --cc=dmitry.kasatkin@gmail.com \
    --cc=jmorris@namei.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mkayaalp@cs.binghamton.edu \
    --cc=roberto.sassu@huawei.com \
    --cc=serge@hallyn.com \
    --cc=silviu.vlasceanu@huawei.com \
    --cc=stefanb@linux.vnet.ibm.com \
    --cc=sunyuqiong1988@gmail.com \
    --cc=zohar@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).