summaryrefslogtreecommitdiffstats
path: root/debian/patches/linux-user-binfmt-P.diff
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/linux-user-binfmt-P.diff')
-rw-r--r--debian/patches/linux-user-binfmt-P.diff90
1 files changed, 90 insertions, 0 deletions
diff --git a/debian/patches/linux-user-binfmt-P.diff b/debian/patches/linux-user-binfmt-P.diff
new file mode 100644
index 00000000..dd680235
--- /dev/null
+++ b/debian/patches/linux-user-binfmt-P.diff
@@ -0,0 +1,90 @@
+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
+
+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 e44bdb17b8..587bd02db2 100644
+--- a/linux-user/main.c
++++ b/linux-user/main.c
+@@ -562,7 +562,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;
+@@ -579,6 +579,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) {
+@@ -648,7 +670,7 @@ int main(int argc, char **argv, char **envp)
+ int ret;
+ int execfd;
+ unsigned long max_reserved_va;
+- bool preserve_argv0;
++ bool preserve_argv0 = 0;
+
+ error_init(argv[0]);
+ module_call_init(MODULE_INIT_TRACE);
+@@ -678,7 +700,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),
+@@ -717,7 +739,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);
+
+ /*
+@@ -728,6 +752,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));