On Sun, Sep 17, 2023 at 10:39 PM Karim Taha <kariem.taha...@gmail.com> wrote:
> From: Stacey Son <s...@freebsd.org> > > Signed-off-by: Stacey Son <s...@freebsd.org> > Signed-off-by: Karim Taha <kariem.taha...@gmail.com> > --- > bsd-user/freebsd/os-proc.c | 177 +++++++++++++++++++++++++++++++++++++ > bsd-user/main.c | 2 +- > bsd-user/qemu.h | 1 + > 3 files changed, 179 insertions(+), 1 deletion(-) > Reviewed-by: Warner Losh <i...@bsdimp.com> But see comment below. > diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c > index cb35f29f10..12d78b7fc9 100644 > --- a/bsd-user/freebsd/os-proc.c > +++ b/bsd-user/freebsd/os-proc.c > @@ -78,3 +78,180 @@ out: > return ret; > } > > +/* > + * execve/fexecve > + */ > +abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, > + abi_ulong guest_envp, int do_fexec) > +{ > + char **argp, **envp, **qargp, **qarg1, **qarg0, **qargend; > + int argc, envc; > + abi_ulong gp; > + abi_ulong addr; > + char **q; > + int total_size = 0; > + void *p; > + abi_long ret; > + > + argc = 0; > + for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { > + if (get_user_ual(addr, gp)) { > + return -TARGET_EFAULT; > + } > + if (!addr) { > + break; > + } > + argc++; > + } > + envc = 0; > + for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { > + if (get_user_ual(addr, gp)) { > + return -TARGET_EFAULT; > + } > + if (!addr) { > + break; > + } > + envc++; > + } > + > + qarg0 = argp = g_new0(char *, argc + 9); > + /* save the first agrument for the emulator */ > + *argp++ = (char *)getprogname(); > + qargp = argp; > + *argp++ = (char *)getprogname(); > + qarg1 = argp; > + envp = g_new0(char *, envc + 1); > + for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { > + if (get_user_ual(addr, gp)) { > + ret = -TARGET_EFAULT; > + goto execve_end; > + } > + if (!addr) { > + break; > + } > + *q = lock_user_string(addr); > + if (*q == NULL) { > + ret = -TARGET_EFAULT; > + goto execve_end; > + } > + total_size += strlen(*q) + 1; > + } > + *q++ = NULL; > + qargend = q; > + > + for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) { > + if (get_user_ual(addr, gp)) { > + ret = -TARGET_EFAULT; > + goto execve_end; > + } > + if (!addr) { > + break; > + } > + *q = lock_user_string(addr); > + if (*q == NULL) { > + ret = -TARGET_EFAULT; > + goto execve_end; > + } > + total_size += strlen(*q) + 1; > + } > + *q = NULL; > + > + /* > + * This case will not be caught by the host's execve() if its > + * page size is bigger than the target's. > + */ > + if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { > + ret = -TARGET_E2BIG; > + goto execve_end; > + } > + > + if (do_fexec) { > + if (((int)path_or_fd > 0 && > + is_target_elf_binary((int)path_or_fd)) == 1) { > + char execpath[PATH_MAX]; > + > + /* > + * The executable is an elf binary for the target > + * arch. execve() it using the emulator if we can > + * determine the filename path from the fd. > + */ > So we do this fd dance so we can make things like 'qemu-arm-static /armv7/bin/sh' work. Doug Rabson has some changes that means we can ditch this, I think, since the kernel will just track it and it will default to 'what is doing the current process' rather than the system default for the same binfmt entry. > + if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath, > + sizeof(execpath)) != NULL) { > + memmove(qarg1 + 2, qarg1, (qargend - qarg1) * > sizeof(*qarg1)); > + qarg1[1] = qarg1[0]; > + qarg1[0] = (char *)"-0"; > + qarg1 += 2; > + qargend += 2; > + *qarg1 = execpath; > +#ifndef DONT_INHERIT_INTERP_PREFIX > + memmove(qarg1 + 2, qarg1, (qargend - qarg1) * > sizeof(*qarg1)); > + *qarg1++ = (char *)"-L"; > + *qarg1++ = (char *)interp_prefix; > +#endif > And we do this inheritance so we can pass in a non-standard library path, maybe for testing, and have the above example also work. Warner > + ret = get_errno(execve(qemu_proc_pathname, qargp, envp)); > + } else { > + /* Getting the filename path failed. */ > + ret = -TARGET_EBADF; > + goto execve_end; > + } > + } else { > + ret = get_errno(fexecve((int)path_or_fd, argp, envp)); > + } > + } else { > + int fd; > + > + p = lock_user_string(path_or_fd); > + if (p == NULL) { > + ret = -TARGET_EFAULT; > + goto execve_end; > + } > + > + /* > + * Check the header and see if it a target elf binary. If so > + * then execute using qemu user mode emulator. > + */ > + fd = open(p, O_RDONLY | O_CLOEXEC); > + if (fd > 0 && is_target_elf_binary(fd) == 1) { > + close(fd); > + /* execve() as a target binary using emulator. */ > + memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); > + qarg1[1] = qarg1[0]; > + qarg1[0] = (char *)"-0"; > + qarg1 += 2; > + qargend += 2; > + *qarg1 = (char *)p; > +#ifndef DONT_INHERIT_INTERP_PREFIX > + memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); > + *qarg1++ = (char *)"-L"; > + *qarg1++ = (char *)interp_prefix; > +#endif > + ret = get_errno(execve(qemu_proc_pathname, qargp, envp)); > + } else { > + close(fd); > + /* Execve() as a host native binary. */ > + ret = get_errno(execve(p, argp, envp)); > + } > + unlock_user(p, path_or_fd, 0); > + } It might be nice to unify these two if statements, but I'm thinking we don't want to do it now since Doug's work will obsolete it if I understand it correctly. Warner > > +execve_end: > + for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { > + if (get_user_ual(addr, gp) || !addr) { > + break; > + } > + unlock_user(*q, addr, 0); > + } > + > + for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) { > + if (get_user_ual(addr, gp) || !addr) { > + break; > + } > + unlock_user(*q, addr, 0); > + } > + > + g_free(qarg0); > + g_free(envp); > + > + return ret; > +} > + > diff --git a/bsd-user/main.c b/bsd-user/main.c > index f913cb55a7..a12b4be80f 100644 > --- a/bsd-user/main.c > +++ b/bsd-user/main.c > @@ -88,7 +88,7 @@ unsigned long reserved_va = MAX_RESERVED_VA; > unsigned long reserved_va; > #endif > > -static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; > +const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; > const char *qemu_uname_release; > char qemu_proc_pathname[PATH_MAX]; /* full path to exeutable */ > > diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h > index 2cf96d9a15..1ed6024b5d 100644 > --- a/bsd-user/qemu.h > +++ b/bsd-user/qemu.h > @@ -111,6 +111,7 @@ typedef struct TaskState { > } __attribute__((aligned(16))) TaskState; > > void stop_all_tasks(void); > +extern const char *interp_prefix; > extern const char *qemu_uname_release; > > /* > -- > 2.42.0 > >