# # 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 "linux/kmod.h" #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include @@ -121,6 +123,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; @@ -187,6 +242,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 @@ -534,6 +534,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 @@ -62,6 +62,7 @@ struct subprocess_info { int wait; int retval; int (*init)(struct subprocess_info *info, struct cred *new); + struct file *stdout; void (*cleanup)(struct subprocess_info *info); void *data; }; @@ -104,4 +105,6 @@ extern int usermodehelper_read_trylock(v extern long usermodehelper_read_lock_wait(long timeout); extern void usermodehelper_read_unlock(void); +int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info, struct file **filp); + #endif /* __LINUX_KMOD_H__ */ --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -223,6 +224,28 @@ static int ____call_usermodehelper(void 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}; + } + /* We can run anywhere, unlike our parent keventd(). */ set_cpus_allowed_ptr(current, cpu_all_mask); @@ -522,6 +545,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