diff options
Diffstat (limited to 'debian/patches/linux-user-binfmt-P.diff')
-rw-r--r-- | debian/patches/linux-user-binfmt-P.diff | 90 |
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)); |