From: Ian Kent <raven@themaw.net>
To: Kernel Mailing List <linux-kernel@vger.kernel.org>
Cc: David Howells <dhowells@redhat.com>,
Oleg Nesterov <onestero@redhat.com>,
Trond Myklebust <trond.myklebust@primarydata.com>,
"J. Bruce Fields" <bfields@fieldses.org>,
Benjamin Coddington <bcodding@redhat.com>,
Al Viro <viro@ZenIV.linux.org.uk>,
Jeff Layton <jeff.layton@primarydata.com>,
"Eric W. Biederman" <ebiederm@xmission.com>
Subject: [RFC PATCH v4 06/12] kmod - add namespace info store
Date: Tue, 17 Mar 2015 10:45:29 +0800 [thread overview]
Message-ID: <20150317024528.24592.53388.stgit@pluto.fritz.box> (raw)
In-Reply-To: <20150317022308.24592.35785.stgit@pluto.fritz.box>
From: Ian Kent <ikent@redhat.com>
Persistent use of namespace information is needed where contained
execution is needed in a namespace other than the current namespace.
Use a simple random token as a key to store namespace information
in a hashed list for later usermode helper execution.
Signed-off-by: Ian Kent <ikent@redhat.com>
Cc: Benjamin Coddington <bcodding@redhat.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: J. Bruce Fields <bfields@fieldses.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Trond Myklebust <trond.myklebust@primarydata.com>
Cc: Oleg Nesterov <onestero@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Jeff Layton <jeff.layton@primarydata.com>
---
include/linux/kmod.h | 14 ++++
kernel/kmod.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 193 insertions(+), 6 deletions(-)
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 64c81c9..77f41ce 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -78,6 +78,20 @@ struct subprocess_info {
#endif
};
+#ifndef CONFIG_NAMESPACES
+static inline long umh_ns_get_token(long token)
+{
+ return -ENOTSUP;
+}
+
+static inline void umh_ns_put_token(long token)
+{
+}
+#else
+extern long umh_ns_get_token(long token);
+extern void umh_ns_put_token(long token);
+#endif
+
extern int
call_usermodehelper(char *path, char **argv, char **envp, unsigned int flags);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index d6ee21a..ddd41f1 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -41,6 +41,9 @@
#include <linux/async.h>
#include <linux/proc_ns.h>
#include <asm/uaccess.h>
+#include <linux/hash.h>
+#include <linux/list.h>
+#include <linux/random.h>
#include <trace/events/module.h>
@@ -48,6 +51,21 @@ extern int max_threads;
static struct workqueue_struct *khelper_wq;
+#ifdef CONFIG_NAMESPACES
+#define UMH_HASH_SHIFT 6
+#define UMH_HASH_SIZE 1 << UMH_HASH_SHIFT
+
+struct umh_ns_entry {
+ long token;
+ unsigned int count;
+ struct umh_ns_info nsinfo;
+ struct hlist_node umh_ns_hlist;
+};
+
+static DEFINE_SPINLOCK(umh_ns_hash_lock);
+static struct hlist_head umh_ns_hash[UMH_HASH_SIZE];
+#endif
+
#define CAP_BSET (void *)1
#define CAP_PI (void *)2
@@ -577,10 +595,13 @@ static int umh_get_nsproxy(struct subprocess_info *sub_info)
static void umh_put_nsproxy(struct subprocess_info *sub_info)
{
}
+
+static void umh_ns_hash_init(void)
+{
+}
#else
-static int umh_get_nsproxy(struct subprocess_info *sub_info)
+static int _umh_get_nsproxy(struct umh_ns_info *nsinfo)
{
- struct umh_ns_info *nsinfo = &sub_info->nsinfo;
struct task_struct *tsk;
struct user_namespace *user_ns;
struct nsproxy *new;
@@ -614,14 +635,165 @@ out:
return err;
}
+static int umh_get_nsproxy(struct subprocess_info *sub_info)
+{
+ return _umh_get_nsproxy(&sub_info->nsinfo);
+}
+
+static void _umh_put_nsproxy(struct umh_ns_info *nsinfo)
+{
+ if (nsinfo->nsproxy) {
+ put_nsproxy(nsinfo->nsproxy);
+ put_user_ns(nsinfo->user_ns);
+ }
+}
+
static void umh_put_nsproxy(struct subprocess_info *sub_info)
{
- if (sub_info->nsinfo.nsproxy) {
- put_nsproxy(sub_info->nsinfo.nsproxy);
- put_user_ns(sub_info->nsinfo.user_ns);
+ return _umh_put_nsproxy(&sub_info->nsinfo);
+}
+
+static void umh_ns_hash_init(void)
+{
+ int i;
+
+ for (i = 0; i < UMH_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&umh_ns_hash[i]);
+}
+
+static struct umh_ns_entry *__umh_ns_find_entry(long token)
+{
+ struct umh_ns_entry *this, *entry;
+ struct hlist_head *bucket;
+ unsigned int hash;
+
+ hash = hash_64((unsigned long) token, UMH_HASH_SHIFT);
+ bucket = &umh_ns_hash[hash];
+
+ entry = ERR_PTR(-ENOENT);
+ if (hlist_empty(bucket))
+ goto out;
+
+ hlist_for_each_entry(this, bucket, umh_ns_hlist) {
+ if (this->token == token) {
+ entry = this;
+ break;
+ }
}
+out:
+ return entry;
}
-#endif
+
+static struct umh_ns_entry *umh_ns_find_entry(long token, unsigned int nowait)
+{
+ struct umh_ns_entry *entry;
+ unsigned long flags;
+
+ if (nowait)
+ spin_lock_irqsave(&umh_ns_hash_lock, flags);
+ else
+ spin_lock(&umh_ns_hash_lock);
+ entry = __umh_ns_find_entry(token);
+ if (nowait)
+ spin_unlock_irqrestore(&umh_ns_hash_lock, flags);
+ else
+ spin_unlock(&umh_ns_hash_lock);
+
+ return entry;
+}
+
+/**
+ * umh_ns_get_token - allocate and store namespace information of the
+ * init process of the caller
+ * @token: token of stored namspace information or zero for a new
+ * token.
+ *
+ * Returns a token used to locate the namespace information for calls to
+ * call_usermode_helper_ns() calls. On failure returns a negative errno.
+ */
+long umh_ns_get_token(long token)
+{
+ struct umh_ns_entry *entry;
+ struct hlist_head *bucket;
+ unsigned int hash;
+ unsigned int new_token;
+ int err;
+
+ if (token) {
+ spin_lock(&umh_ns_hash_lock);
+ entry = __umh_ns_find_entry(token);
+ if (entry) {
+ entry->count++;
+ spin_unlock(&umh_ns_hash_lock);
+ return token;
+ }
+ spin_unlock(&umh_ns_hash_lock);
+ }
+
+ entry = kzalloc(sizeof(struct umh_ns_entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ err = _umh_get_nsproxy(&entry->nsinfo);
+ if (err) {
+ kfree(entry);
+ return err;
+ }
+
+ do {
+ new_token = get_random_int();
+ if (!token)
+ continue;
+ spin_lock(&umh_ns_hash_lock);
+ entry = __umh_ns_find_entry(new_token);
+ if (likely(IS_ERR(entry))) {
+ hash = hash_32(new_token, UMH_HASH_SHIFT);
+ bucket = &umh_ns_hash[hash];
+ hlist_add_head(&entry->umh_ns_hlist, bucket);
+ entry->token = (long) new_token;
+ spin_unlock(&umh_ns_hash_lock);
+ break;
+ }
+ spin_unlock(&umh_ns_hash_lock);
+ } while (1);
+
+ return (long) new_token;
+}
+EXPORT_SYMBOL(umh_ns_get_token);
+
+/**
+ * umh_ns_put_token - remove and free a stored namespace corresponding to
+ * passed token
+ * @token: token of the stored namspace information.
+ *
+ * Returns 0 if the token is not longer in use or the token if it is in
+ * use.
+ */
+void umh_ns_put_token(long token)
+{
+ struct umh_ns_entry *entry;
+
+ if (!token)
+ return;
+
+ spin_lock(&umh_ns_hash_lock);
+ entry = __umh_ns_find_entry(token);
+ if (unlikely(IS_ERR(entry)))
+ spin_unlock(&umh_ns_hash_lock);
+ else {
+ if (--entry->count)
+ spin_unlock(&umh_ns_hash_lock);
+ else {
+ hlist_del(&entry->umh_ns_hlist);
+ spin_unlock(&umh_ns_hash_lock);
+ _umh_put_nsproxy(&entry->nsinfo);
+ kfree(entry);
+ }
+ }
+ return;
+}
+EXPORT_SYMBOL(umh_ns_put_token);
+#endif /* CONFIG_NAMESPACES */
/**
* call_usermodehelper_setup - prepare to call a usermode helper
@@ -849,4 +1021,5 @@ void __init usermodehelper_init(void)
{
khelper_wq = create_singlethread_workqueue("khelper");
BUG_ON(!khelper_wq);
+ umh_ns_hash_init();
}
next prev parent reply other threads:[~2015-03-17 2:45 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-17 2:44 [RFC PATCH v4 00/12] Second attempt at contained helper execution Ian Kent
2015-03-17 2:44 ` [RFC PATCH v4 01/12] nsproxy - make create_new_namespaces() non-static Ian Kent
2015-03-17 2:45 ` [RFC PATCH v4 02/12] kmod - rename call_usermodehelper() flags parameter Ian Kent
2015-03-17 2:45 ` [RFC PATCH v4 03/12] vfs - move mnt_namespace definition to linux/mount.h Ian Kent
2015-03-19 19:47 ` Al Viro
2015-03-20 0:57 ` Ian Kent
2015-03-20 1:14 ` Eric W. Biederman
2015-03-20 2:11 ` Ian Kent
2015-03-20 2:47 ` Al Viro
2015-03-17 2:45 ` [RFC PATCH v4 04/12] kmod - add namespace aware thread runner Ian Kent
2015-03-17 2:45 ` [RFC PATCH v4 05/12] kmod - teach call_usermodehelper() to use a namespace Ian Kent
2015-03-17 2:45 ` Ian Kent [this message]
2015-03-17 2:45 ` [RFC PATCH v4 07/12] kmod - add call_usermodehelper_ns() Ian Kent
2015-03-17 2:45 ` [RFC PATCH v4 08/12] nfsd - use namespace if not executing in init namespace Ian Kent
2015-03-17 2:45 ` [RFC PATCH v4 09/12] nfs - cache_lib " Ian Kent
2015-03-17 2:45 ` [RFC PATCH v4 10/12] nfs - objlayout " Ian Kent
2015-03-17 2:46 ` [RFC PATCH v4 11/12] KEYS - use correct memory allocation flag in call_usermodehelper_keys() Ian Kent
2015-03-17 2:46 ` [RFC PATCH v4 12/12] KEYS: exec request-key within the requesting task's init namespace Ian Kent
2015-03-18 17:41 ` [RFC PATCH v4 00/12] Second attempt at contained helper execution J. Bruce Fields
2015-03-19 21:38 ` Eric W. Biederman
2015-03-20 2:10 ` Ian Kent
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=20150317024528.24592.53388.stgit@pluto.fritz.box \
--to=raven@themaw.net \
--cc=bcodding@redhat.com \
--cc=bfields@fieldses.org \
--cc=dhowells@redhat.com \
--cc=ebiederm@xmission.com \
--cc=jeff.layton@primarydata.com \
--cc=linux-kernel@vger.kernel.org \
--cc=onestero@redhat.com \
--cc=trond.myklebust@primarydata.com \
--cc=viro@ZenIV.linux.org.uk \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.