blob: ca4f27b53fab4c37b34b73fec1d95c756db878ff [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#
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(&current->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