# # Minimalist mconsole exec patch # # 3.10 version (with bit more synchronous behavior) by fingon at iki dot fi # Adaptation to kernel 3.3.8 made by David Fernández (david at dit.upm.es) for # Starting point: mconsole-exec-2.6.30.patch for kernel 2.6.30 # Author of original patch: Paolo Giarrusso, aka Blaisorblade # (http://www.user-mode-linux.org/~blaisorblade) # # Known misfeatures: # # - If output is too long, blocks (and breaks horribly) # (this misfeature from 3.10 patches, when minimalizing the patch; # workaround: redirect to a shared filesystem if long output is expected) # # - Nothing useful is done with stdin # --- a/arch/um/drivers/mconsole.h +++ b/arch/um/drivers/mconsole.h @@ -85,6 +85,7 @@ extern void mconsole_cad(struct mc_reque extern void mconsole_stop(struct mc_request *req); extern void mconsole_go(struct mc_request *req); extern void mconsole_log(struct mc_request *req); +extern void mconsole_exec(struct mc_request *req); extern void mconsole_proc(struct mc_request *req); extern void mconsole_stack(struct mc_request *req); --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -4,6 +4,7 @@ * Licensed under the GPL */ +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include @@ -122,6 +124,59 @@ void mconsole_log(struct mc_request *req mconsole_reply(req, "", 0, 0); } +void mconsole_exec(struct mc_request *req) +{ + struct subprocess_info *sub_info; + int res, len; + struct file *out; + char buf[MCONSOLE_MAX_DATA]; + + char *envp[] = { + "HOME=/", "TERM=linux", + "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin", + NULL + }; + char *argv[] = { + "/bin/sh", "-c", + req->request.data + strlen("exec "), + NULL + }; + + sub_info = call_usermodehelper_setup("/bin/sh", argv, envp, GFP_ATOMIC, NULL, NULL, NULL); + if (sub_info == NULL) { + mconsole_reply(req, "call_usermodehelper_setup failed", 1, 0); + return; + } + res = call_usermodehelper_stdoutpipe(sub_info, &out); + if (res < 0) { + kfree(sub_info); + mconsole_reply(req, "call_usermodehelper_stdoutpipe failed", 1, 0); + return; + } + + res = call_usermodehelper_exec(sub_info, UMH_WAIT_PROC); + if (res < 0) { + kfree(sub_info); + mconsole_reply(req, "call_usermodehelper_exec failed", 1, 0); + return; + } + + for (;;) { + len = out->f_op->read(out, buf, sizeof(buf), &out->f_pos); + if (len < 0) { + mconsole_reply(req, "reading output failed", 1, 0); + break; + } + if (len == 0) + break; + mconsole_reply_len(req, buf, len, 0, 1); + } + fput(out); + + mconsole_reply_len(req, NULL, 0, 0, 0); +} + + void mconsole_proc(struct mc_request *req) { struct vfsmount *mnt = task_active_pid_ns(current)->proc_mnt; @@ -183,6 +238,7 @@ void mconsole_proc(struct mc_request *re stop - pause the UML; it will do nothing until it receives a 'go' \n\ go - continue the UML after a 'stop' \n\ log - make UML enter into the kernel log\n\ + exec - pass to /bin/sh -c synchronously\n\ proc - returns the contents of the UML's /proc/\n\ stack - returns the stack of the specified pid\n\ " --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -30,6 +30,7 @@ static struct mconsole_command commands[ { "stop", mconsole_stop, MCONSOLE_PROC }, { "go", mconsole_go, MCONSOLE_INTR }, { "log", mconsole_log, MCONSOLE_INTR }, + { "exec", mconsole_exec, MCONSOLE_PROC }, { "proc", mconsole_proc, MCONSOLE_PROC }, { "stack", mconsole_stack, MCONSOLE_INTR }, }; --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -555,6 +555,8 @@ int os_create_unix_socket(const char *fi addr.sun_family = AF_UNIX; + if (len > sizeof(addr.sun_path)) + len = sizeof(addr.sun_path); snprintf(addr.sun_path, len, "%s", file); err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -45,4 +45,6 @@ static inline int request_module_nowait( #define try_then_request_module(x, mod...) (x) #endif +int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info, struct file **filp); + #endif /* __LINUX_KMOD_H__ */ --- a/include/linux/umh.h +++ b/include/linux/umh.h @@ -22,6 +22,7 @@ struct subprocess_info { const char *path; char **argv; char **envp; + struct file *stdout; int wait; int retval; int (*init)(struct subprocess_info *info, struct cred *new); --- a/kernel/umh.c +++ b/kernel/umh.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -70,6 +71,28 @@ static int call_usermodehelper_exec_asyn flush_signal_handlers(current, 1); spin_unlock_irq(¤t->sighand->siglock); + /* Install output when needed */ + if (sub_info->stdout) { + struct files_struct *f = current->files; + struct fdtable *fdt; + + sys_close(1); + sys_close(2); + get_file(sub_info->stdout); + fd_install(1, sub_info->stdout); + fd_install(2, sub_info->stdout); + spin_lock(&f->file_lock); + fdt = files_fdtable(f); + __set_bit(1, fdt->open_fds); + __clear_bit(1, fdt->close_on_exec); + __set_bit(2, fdt->open_fds); + __clear_bit(2, fdt->close_on_exec); + spin_unlock(&f->file_lock); + + /* disallow core files */ + current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0}; + } + /* * Our parent (unbound workqueue) runs with elevated scheduling * priority. Avoid propagating that into the userspace child. @@ -393,6 +416,20 @@ struct subprocess_info *call_usermodehel } EXPORT_SYMBOL(call_usermodehelper_setup); +int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info, + struct file **filp) +{ + struct file *f[2]; + + if (create_pipe_files(f, 0) < 0) + return PTR_ERR(f); + + sub_info->stdout = f[1]; + *filp = f[0]; + return 0; +} +EXPORT_SYMBOL(call_usermodehelper_stdoutpipe); + /** * call_usermodehelper_exec - start a usermode application * @sub_info: information about the subprocessa