b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | # |
| 2 | # Minimalist mconsole exec patch |
| 3 | # |
| 4 | # 3.10 version (with bit more synchronous behavior) by fingon at iki dot fi |
| 5 | # Adaptation to kernel 3.3.8 made by David Fernández (david at dit.upm.es) for |
| 6 | # Starting point: mconsole-exec-2.6.30.patch for kernel 2.6.30 |
| 7 | # Author of original patch: Paolo Giarrusso, aka Blaisorblade |
| 8 | # (http://www.user-mode-linux.org/~blaisorblade) |
| 9 | # |
| 10 | # Known misfeatures: |
| 11 | # |
| 12 | # - If output is too long, blocks (and breaks horribly) |
| 13 | # (this misfeature from 3.10 patches, when minimalizing the patch; |
| 14 | # workaround: redirect to a shared filesystem if long output is expected) |
| 15 | # |
| 16 | # - Nothing useful is done with stdin |
| 17 | # |
| 18 | --- a/arch/um/drivers/mconsole.h |
| 19 | +++ b/arch/um/drivers/mconsole.h |
| 20 | @@ -85,6 +85,7 @@ extern void mconsole_cad(struct mc_reque |
| 21 | extern void mconsole_stop(struct mc_request *req); |
| 22 | extern void mconsole_go(struct mc_request *req); |
| 23 | extern void mconsole_log(struct mc_request *req); |
| 24 | +extern void mconsole_exec(struct mc_request *req); |
| 25 | extern void mconsole_proc(struct mc_request *req); |
| 26 | extern void mconsole_stack(struct mc_request *req); |
| 27 | |
| 28 | --- a/arch/um/drivers/mconsole_kern.c |
| 29 | +++ b/arch/um/drivers/mconsole_kern.c |
| 30 | @@ -4,6 +4,7 @@ |
| 31 | * Copyright (C) 2001 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
| 32 | */ |
| 33 | |
| 34 | +#include <linux/kmod.h> |
| 35 | #include <linux/console.h> |
| 36 | #include <linux/ctype.h> |
| 37 | #include <linux/string.h> |
| 38 | @@ -26,6 +27,7 @@ |
| 39 | #include <linux/mount.h> |
| 40 | #include <linux/file.h> |
| 41 | #include <linux/uaccess.h> |
| 42 | +#include <linux/completion.h> |
| 43 | #include <asm/switch_to.h> |
| 44 | |
| 45 | #include <init.h> |
| 46 | @@ -121,6 +123,59 @@ void mconsole_log(struct mc_request *req |
| 47 | mconsole_reply(req, "", 0, 0); |
| 48 | } |
| 49 | |
| 50 | +void mconsole_exec(struct mc_request *req) |
| 51 | +{ |
| 52 | + struct subprocess_info *sub_info; |
| 53 | + int res, len; |
| 54 | + struct file *out; |
| 55 | + char buf[MCONSOLE_MAX_DATA]; |
| 56 | + |
| 57 | + char *envp[] = { |
| 58 | + "HOME=/", "TERM=linux", |
| 59 | + "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin", |
| 60 | + NULL |
| 61 | + }; |
| 62 | + char *argv[] = { |
| 63 | + "/bin/sh", "-c", |
| 64 | + req->request.data + strlen("exec "), |
| 65 | + NULL |
| 66 | + }; |
| 67 | + |
| 68 | + sub_info = call_usermodehelper_setup("/bin/sh", argv, envp, GFP_ATOMIC, NULL, NULL, NULL); |
| 69 | + if (sub_info == NULL) { |
| 70 | + mconsole_reply(req, "call_usermodehelper_setup failed", 1, 0); |
| 71 | + return; |
| 72 | + } |
| 73 | + res = call_usermodehelper_stdoutpipe(sub_info, &out); |
| 74 | + if (res < 0) { |
| 75 | + kfree(sub_info); |
| 76 | + mconsole_reply(req, "call_usermodehelper_stdoutpipe failed", 1, 0); |
| 77 | + return; |
| 78 | + } |
| 79 | + |
| 80 | + res = call_usermodehelper_exec(sub_info, UMH_WAIT_PROC); |
| 81 | + if (res < 0) { |
| 82 | + kfree(sub_info); |
| 83 | + mconsole_reply(req, "call_usermodehelper_exec failed", 1, 0); |
| 84 | + return; |
| 85 | + } |
| 86 | + |
| 87 | + for (;;) { |
| 88 | + len = out->f_op->read(out, buf, sizeof(buf), &out->f_pos); |
| 89 | + if (len < 0) { |
| 90 | + mconsole_reply(req, "reading output failed", 1, 0); |
| 91 | + break; |
| 92 | + } |
| 93 | + if (len == 0) |
| 94 | + break; |
| 95 | + mconsole_reply_len(req, buf, len, 0, 1); |
| 96 | + } |
| 97 | + fput(out); |
| 98 | + |
| 99 | + mconsole_reply_len(req, NULL, 0, 0, 0); |
| 100 | +} |
| 101 | + |
| 102 | + |
| 103 | void mconsole_proc(struct mc_request *req) |
| 104 | { |
| 105 | struct vfsmount *mnt = task_active_pid_ns(current)->proc_mnt; |
| 106 | @@ -183,6 +238,7 @@ void mconsole_proc(struct mc_request *re |
| 107 | stop - pause the UML; it will do nothing until it receives a 'go' \n\ |
| 108 | go - continue the UML after a 'stop' \n\ |
| 109 | log <string> - make UML enter <string> into the kernel log\n\ |
| 110 | + exec <string> - pass <string> to /bin/sh -c synchronously\n\ |
| 111 | proc <file> - returns the contents of the UML's /proc/<file>\n\ |
| 112 | stack <pid> - returns the stack of the specified pid\n\ |
| 113 | " |
| 114 | --- a/arch/um/drivers/mconsole_user.c |
| 115 | +++ b/arch/um/drivers/mconsole_user.c |
| 116 | @@ -30,6 +30,7 @@ static struct mconsole_command commands[ |
| 117 | { "stop", mconsole_stop, MCONSOLE_PROC }, |
| 118 | { "go", mconsole_go, MCONSOLE_INTR }, |
| 119 | { "log", mconsole_log, MCONSOLE_INTR }, |
| 120 | + { "exec", mconsole_exec, MCONSOLE_PROC }, |
| 121 | { "proc", mconsole_proc, MCONSOLE_PROC }, |
| 122 | { "stack", mconsole_stack, MCONSOLE_INTR }, |
| 123 | }; |
| 124 | --- a/arch/um/os-Linux/file.c |
| 125 | +++ b/arch/um/os-Linux/file.c |
| 126 | @@ -557,6 +557,8 @@ int os_create_unix_socket(const char *fi |
| 127 | |
| 128 | addr.sun_family = AF_UNIX; |
| 129 | |
| 130 | + if (len > sizeof(addr.sun_path)) |
| 131 | + len = sizeof(addr.sun_path); |
| 132 | snprintf(addr.sun_path, len, "%s", file); |
| 133 | |
| 134 | err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); |
| 135 | --- a/include/linux/kmod.h |
| 136 | +++ b/include/linux/kmod.h |
| 137 | @@ -32,4 +32,6 @@ static inline int request_module_nowait( |
| 138 | #define try_then_request_module(x, mod...) (x) |
| 139 | #endif |
| 140 | |
| 141 | +int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info, struct file **filp); |
| 142 | + |
| 143 | #endif /* __LINUX_KMOD_H__ */ |
| 144 | --- a/include/linux/umh.h |
| 145 | +++ b/include/linux/umh.h |
| 146 | @@ -23,6 +23,7 @@ struct subprocess_info { |
| 147 | char **argv; |
| 148 | char **envp; |
| 149 | struct file *file; |
| 150 | + struct file *stdout; |
| 151 | int wait; |
| 152 | int retval; |
| 153 | pid_t pid; |
| 154 | --- a/kernel/umh.c |
| 155 | +++ b/kernel/umh.c |
| 156 | @@ -76,6 +76,28 @@ static int call_usermodehelper_exec_asyn |
| 157 | flush_signal_handlers(current, 1); |
| 158 | spin_unlock_irq(¤t->sighand->siglock); |
| 159 | |
| 160 | + /* Install output when needed */ |
| 161 | + if (sub_info->stdout) { |
| 162 | + struct files_struct *f = current->files; |
| 163 | + struct fdtable *fdt; |
| 164 | + |
| 165 | + sys_close(1); |
| 166 | + sys_close(2); |
| 167 | + get_file(sub_info->stdout); |
| 168 | + fd_install(1, sub_info->stdout); |
| 169 | + fd_install(2, sub_info->stdout); |
| 170 | + spin_lock(&f->file_lock); |
| 171 | + fdt = files_fdtable(f); |
| 172 | + __set_bit(1, fdt->open_fds); |
| 173 | + __clear_bit(1, fdt->close_on_exec); |
| 174 | + __set_bit(2, fdt->open_fds); |
| 175 | + __clear_bit(2, fdt->close_on_exec); |
| 176 | + spin_unlock(&f->file_lock); |
| 177 | + |
| 178 | + /* disallow core files */ |
| 179 | + current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0}; |
| 180 | + } |
| 181 | + |
| 182 | /* |
| 183 | * Initial kernel threads share ther FS with init, in order to |
| 184 | * get the init root directory. But we've now created a new |
| 185 | @@ -362,6 +384,20 @@ static void helper_unlock(void) |
| 186 | wake_up(&running_helpers_waitq); |
| 187 | } |
| 188 | |
| 189 | +int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info, |
| 190 | + struct file **filp) |
| 191 | +{ |
| 192 | + struct file *f[2]; |
| 193 | + |
| 194 | + if (create_pipe_files(f, 0) < 0) |
| 195 | + return PTR_ERR(f); |
| 196 | + |
| 197 | + sub_info->stdout = f[1]; |
| 198 | + *filp = f[0]; |
| 199 | + return 0; |
| 200 | +} |
| 201 | +EXPORT_SYMBOL(call_usermodehelper_stdoutpipe); |
| 202 | + |
| 203 | /** |
| 204 | * call_usermodehelper_setup - prepare to call a usermode helper |
| 205 | * @path: path to usermode executable |