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
>
>

Reply via email to