On 10/30/24 14:10, Noah Goldstein wrote:
The new option '-qemu-children' makes it so that on `execve` the child
process will be launch by the same `qemu` executable that is currently
running along with its current commandline arguments.
The motivation for the change is to make it so that plugins running
through `qemu` can continue to run on children. Why not just
`binfmt`?: Plugins can be desirable regardless of system/architecture
emulation, and can sometimes be useful for elf files that can run
natively. Enabling `binfmt` for all natively runnable elf files may
not be desirable.
Signed-off-by: Noah Goldstein <goldstein....@gmail.com>
---
linux-user/main.c | 21 ++++++
linux-user/syscall.c | 21 ++++--
linux-user/user-internals.h | 4 ++
tests/tcg/multiarch/Makefile.target | 8 +++
.../linux/linux-execve-qemu-children.c | 68 +++++++++++++++++++
5 files changed, 117 insertions(+), 5 deletions(-)
create mode 100644 tests/tcg/multiarch/linux/linux-execve-qemu-children.c
diff --git a/linux-user/main.c b/linux-user/main.c
index 8143a0d4b0..5e3d41dc2b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -81,6 +81,10 @@ unsigned long mmap_min_addr;
uintptr_t guest_base;
bool have_guest_base;
+bool qemu_dup_for_children;
+int qemu_argc;
+char **qemu_argv;
+
/*
* Used to implement backwards-compatibility for the `-strace`, and
* QEMU_STRACE options. Without this, the QEMU_LOG can be overwritten by
@@ -451,6 +455,11 @@ static void handle_arg_jitdump(const char *arg)
perf_enable_jitdump();
}
+static void handle_arg_qemu_children(const char *arg)
+{
+ qemu_dup_for_children = true;
+}
+
static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
#ifdef CONFIG_PLUGIN
@@ -526,6 +535,10 @@ static const struct qemu_argument arg_table[] = {
"", "Generate a /tmp/perf-${pid}.map file for perf"},
{"jitdump", "QEMU_JITDUMP", false, handle_arg_jitdump,
"", "Generate a jit-${pid}.dump file for perf"},
+ {"qemu-children",
+ "QEMU_CHILDREN", false, handle_arg_qemu_children,
+ "", "Run child processes (created with execve) with qemu "
+ "(as instantiated for the parent)"},
{NULL, NULL, false, NULL, NULL, NULL}
};
@@ -729,6 +742,14 @@ int main(int argc, char **argv, char **envp)
optind = parse_args(argc, argv);
+ if (qemu_dup_for_children) {
+ qemu_argc = optind;
+ qemu_argv = g_new0(char *, qemu_argc);
+ for (i = 0; i < optind; ++i) {
+ qemu_argv[i] = strdup(argv[i]);
g_strdup.
+ bool through_qemu = dirfd == AT_FDCWD && qemu_dup_for_children;
Why is this limited to AT_FDCWD? Why not for execvat too?
@@ -8628,9 +8631,16 @@ static int do_execv(CPUArchState *cpu_env, int dirfd,
}
const char *exe = p;
- if (is_proc_myself(p, "exe")) {
+ if (through_qemu) {
+ int i;
+ for (i = 0; i < argp_offset; ++i) {
+ argp[i] = qemu_argv[i];
+ }
+ exe = qemu_argv[0];
+ } else if (is_proc_myself(p, "exe")) {
exe = exec_path;
}
+
You still need to handle is_proc_myself, for the guest binary.
I wonder if those two cases are related. Do we need to also add an argument so that we
can pass the executable to the next qemu via file descriptor? I.e. execvat becomes
f = openat()
execv(qemu, "-execfd", f)
and is_proc_myself uses execfd, which we already have open.
r~