1
0
Fork 0
qemu/debian/patches/linux-user-binfmt-P.diff
Daniel Baumann 665688c177
Adding debian version 1:10.0.2+ds-1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 14:27:18 +02:00

92 lines
3.5 KiB
Diff

Subject: [PATCH, HACK]: linux-user: handle binfmt-misc P flag as a separate exe name
From: Michael Tokarev <mjt@tls.msk.ru>
Date: Sat, 13 Feb 2021 13:57:52 +0300
Updated: Wed, 31 Aug 2022 12:30:17 +0300
Forwarded: https://patchwork.ozlabs.org/project/qemu-devel/patch/27dfe8eb-adce-8db4-f28b-c42858b086db@msgid.tls.msk.ru/
Upstream-Status: rejected this simple userspace solution in favour of more complex in-kernel one
A hackish way to distinguish the case when qemu-user binary is executed
using in-kernel binfmt-misc subsystem with P flag (preserve argv).
We register binfmt interpreter under name /usr/libexec/qemu-binfmt/qemu-foo-binfmt-P
(which is just a symlink to ../../bin/qemu-foo), and if run like that,
qemu-user binary will "know" it should interpret argv[1] & argv[2]
in a special way.
diff --git a/linux-user/main.c b/linux-user/main.c
index 9277df2e9d..bd323f70bc 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -600,7 +600,7 @@ static void usage(int exitcode)
exit(exitcode);
}
-static int parse_args(int argc, char **argv)
+static int parse_args(int argc, char **argv, bool *preserve_argv0)
{
const char *r;
int optind;
@@ -617,6 +617,28 @@ static int parse_args(int argc, char **argv)
}
}
+ /* HACK alert.
+ * when run as an interpreter using kernel's binfmt-misc mechanism,
+ * we have to know where are we (our own binary), where's the binary being run,
+ * and what it's argv[0] element.
+ * Only with the P interpreter flag kernel passes all 3 elements as first 3 argv[],
+ * but we can't distinguish if we were run with or without this P flag.
+ * So we register a special name with binfmt-misc system, a name which ends up
+ * in "-binfmt-P", and if our argv[0] ends up with that, we assume we were run
+ * from kernel's binfmt with P flag and our first 3 args are from kernel.
+ */
+ if (strlen(argv[0]) > sizeof("binfmt-P") &&
+ strcmp(argv[0] + strlen(argv[0]) - sizeof("binfmt-P"), "-binfmt-P") == 0) {
+ if (argc < 3) {
+ (void) fprintf(stderr, "qemu: %s has to be run using kernel binfmt-misc subsystem\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ exec_path = argv[1];
+ handle_arg_argv0(argv[2]);
+ *preserve_argv0 = true;
+ return 2;
+ }
+
optind = 1;
for (;;) {
if (optind >= argc) {
@@ -687,7 +709,7 @@ int main(int argc, char **argv, char **envp)
int execfd;
int host_page_size;
unsigned long max_reserved_va;
- bool preserve_argv0;
+ bool preserve_argv0 = 0;
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
@@ -726,7 +748,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_trace_opts);
qemu_plugin_add_opts();
- optind = parse_args(argc, argv);
+ optind = parse_args(argc, argv, &preserve_argv0);
qemu_set_log_filename_flags(last_log_filename,
last_log_mask | (enable_strace * LOG_STRACE),
@@ -770,7 +792,9 @@ int main(int argc, char **argv, char **envp)
/*
* get binfmt_misc flags
+ * but only if not already done by parse_args() above
*/
+ if (!preserve_argv0) {
preserve_argv0 = !!(qemu_getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
/*
@@ -781,6 +805,7 @@ int main(int argc, char **argv, char **envp)
if (optind + 1 < argc && preserve_argv0) {
optind++;
}
+ }
if (cpu_model == NULL) {
cpu_model = cpu_get_model(get_elf_eflags(execfd));