[RFC PATCH 3/4] kmod - add call_usermodehelper_ns() helper

From: Ian Kent
Date: Mon Nov 24 2014 - 20:07:47 EST


The call_usermodehelper() function executes all binaries in the
global "init" root context. This doesn't allow a binary to be run
within the callers namespace (aka. a container). So create a new
function call_usermodehelper_ns() to do this.

Both containerized NFS client and NFS server need the ability to
execute a binary within their container. To do this create a new
nsproxy within the callers' context so it can be used for setup
prior to calling do_execve() from the user mode helper thread
runner.

Signed-off-by: Ian Kent <ikent@xxxxxxxxxx>
Signed-off-by: Benjamin Coddington <bcodding@xxxxxxxxxx>
Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
Cc: J. Bruce Fields <bfields@xxxxxxxxxxxx>
Cc: David Howells <dhowells@xxxxxxxxxx>
Cc: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
Cc: Stanislav Kinsbursky <skinsbursky@xxxxxxxxxxxxx>
Cc: Oleg Nesterov <onestero@xxxxxxxxxx>
Cc: Eric W. Biederman <ebiederm@xxxxxxxxxxxx>
---
include/linux/kmod.h | 17 +++++++++++++++++
kernel/kmod.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+)

diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 0555cc6..fd5509a 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -69,6 +69,23 @@ struct subprocess_info {
extern int
call_usermodehelper(char *path, char **argv, char **envp, int wait);

+#if !defined(CONFIG_PROC_FS) || !defined(CONFIG_NAMESPACES)
+inline struct nsproxy *umh_open_ns(void)
+{
+ return NULL;
+}
+
+inline int
+call_usermodehelper_ns(char *path, char **argv, char **envp, int wait)
+{
+ return -ENOTSUP;
+}
+#else
+extern struct nsproxy *umh_open_ns(void);
+extern int
+call_usermodehelper_ns(char *path, char **argv, char **envp, int wait);
+#endif
+
extern struct subprocess_info *
call_usermodehelper_setup(char *path, char **argv, char **envp, gfp_t gfp_mask,
int (*init)(struct subprocess_info *info, struct cred *new),
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 80f7a6d..0ddcfbb 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -39,6 +39,7 @@
#include <linux/rwsem.h>
#include <linux/ptrace.h>
#include <linux/async.h>
+#include <linux/mount.h>
#include <asm/uaccess.h>

#include <trace/events/module.h>
@@ -642,6 +643,44 @@ int call_usermodehelper(char *path, char **argv, char **envp, int wait)
}
EXPORT_SYMBOL(call_usermodehelper);

+#if defined(CONFIG_PROC_FS) && defined(CONFIG_NAMESPACES)
+static int umh_set_ns(struct subprocess_info *info, struct cred *new)
+{
+ struct nsproxy *ns = info->data;
+
+ mntns_setfs(ns->mnt_ns);
+ switch_task_namespaces(current, ns);
+ return 0;
+}
+
+struct nsproxy *umh_open_ns(void)
+{
+ return create_new_namespaces(0, current, current_user_ns(), current->fs);
+}
+
+/* Call a usermode helper to execute within current namespace. */
+int call_usermodehelper_ns(char *path, char **argv, char **envp, int wait)
+{
+ struct subprocess_info *info;
+ struct nsproxy *ns;
+ gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
+
+ ns = umh_open_ns();
+ if (IS_ERR(ns))
+ return PTR_ERR(ns);
+
+ info = call_usermodehelper_setup(path, argv, envp,
+ gfp_mask, umh_set_ns, NULL, ns);
+ if (!info) {
+ free_nsproxy(ns);
+ return -ENOMEM;
+ }
+
+ return call_usermodehelper_exec(info, wait);
+}
+EXPORT_SYMBOL(call_usermodehelper_ns);
+#endif
+
static int proc_cap_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/