From: Stacey Son <s...@freebsd.org> This change moves the system call handler for sysctl(2) and sysarch(2) from syscall.c to the OS and arch dependent directories. This eliminates many of the #ifdef's in syscall.c. These system call handlers are now located in the host os and target arch directories.
Signed-off-by: Sean Bruno <sbr...@freebsd.org> Signed-off-by: Stacey Son <s...@freebsd.org> --- bsd-user/Makefile.objs | 2 +- bsd-user/bsdload.c | 168 +++++++++++++------ bsd-user/elfload.c | 7 +- bsd-user/freebsd/os-strace.h | 6 - bsd-user/freebsd/os-sys.c | 285 ++++++++++++++++++++++++++++++++ bsd-user/freebsd/target_os_stack.h | 157 ++++++++++++++++++ bsd-user/i386/syscall.h | 2 + bsd-user/i386/target_arch_sigtramp.h | 11 ++ bsd-user/main.c | 2 +- bsd-user/netbsd/os-strace.h | 8 - bsd-user/netbsd/os-sys.c | 46 ++++++ bsd-user/netbsd/target_os_stack.h | 33 ++++ bsd-user/openbsd/os-strace.h | 8 - bsd-user/openbsd/os-sys.c | 46 ++++++ bsd-user/openbsd/target_os_stack.h | 33 ++++ bsd-user/qemu.h | 28 +++- bsd-user/sparc/syscall.h | 2 + bsd-user/sparc/target_arch_sigtramp.h | 11 ++ bsd-user/sparc64/syscall.h | 2 + bsd-user/sparc64/target_arch_sigtramp.h | 11 ++ bsd-user/syscall.c | 151 ++++------------- bsd-user/x86_64/syscall.h | 2 + bsd-user/x86_64/target_arch_sigtramp.h | 11 ++ 23 files changed, 827 insertions(+), 205 deletions(-) create mode 100644 bsd-user/freebsd/os-sys.c create mode 100644 bsd-user/freebsd/target_os_stack.h create mode 100644 bsd-user/i386/target_arch_sigtramp.h create mode 100644 bsd-user/netbsd/os-sys.c create mode 100644 bsd-user/netbsd/target_os_stack.h create mode 100644 bsd-user/openbsd/os-sys.c create mode 100644 bsd-user/openbsd/target_os_stack.h create mode 100644 bsd-user/sparc/target_arch_sigtramp.h create mode 100644 bsd-user/sparc64/target_arch_sigtramp.h create mode 100644 bsd-user/x86_64/target_arch_sigtramp.h diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs index 41e8dce..a4dca8e 100644 --- a/bsd-user/Makefile.objs +++ b/bsd-user/Makefile.objs @@ -1,2 +1,2 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ - uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o + uaccess.o $(HOST_VARIANT_DIR)/os-sys.o $(TARGET_ABI_DIR)/target_arch_cpu.o diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index e59b03d..45fdcf8 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -1,4 +1,19 @@ -/* Code for loading BSD executables. Mostly linux kernel code. */ +/* + * Load BSD executables. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ #include <sys/types.h> #include <sys/stat.h> @@ -26,27 +41,11 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src, return 0; } -static int in_group_p(gid_t g) -{ - /* return TRUE if we're in the specified group, FALSE otherwise */ - int ngroup; - int i; - gid_t grouplist[TARGET_NGROUPS]; - - ngroup = getgroups(TARGET_NGROUPS, grouplist); - for(i = 0; i < ngroup; i++) { - if(grouplist[i] == g) { - return 1; - } - } - return 0; -} - static int count(char ** vec) { int i; - for(i = 0; *vec; i++) { + for (i = 0; *vec; i++) { vec++; } @@ -57,7 +56,7 @@ static int prepare_binprm(struct bsd_binprm *bprm) { struct stat st; int mode; - int retval, id_change; + int retval; if(fstat(bprm->fd, &st) < 0) { return(-errno); @@ -73,14 +72,10 @@ static int prepare_binprm(struct bsd_binprm *bprm) bprm->e_uid = geteuid(); bprm->e_gid = getegid(); - id_change = 0; /* Set-uid? */ if(mode & S_ISUID) { bprm->e_uid = st.st_uid; - if(bprm->e_uid != geteuid()) { - id_change = 1; - } } /* Set-gid? */ @@ -91,9 +86,6 @@ static int prepare_binprm(struct bsd_binprm *bprm) */ if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { bprm->e_gid = st.st_gid; - if (!in_group_p(bprm->e_gid)) { - id_change = 1; - } } memset(bprm->buf, 0, sizeof(bprm->buf)); @@ -154,34 +146,116 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, return sp; } +static int is_there(const char *candidate) +{ + struct stat fin; + + /* XXX work around access(2) false positives for superuser */ + if (access(candidate, X_OK) == 0 && stat(candidate, &fin) == 0 && + S_ISREG(fin.st_mode) && (getuid() != 0 || + (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { + return 1; + } + + return 0; +} + +static int find_in_path(char *path, const char *filename, char *retpath, + size_t rpsize) +{ + const char *d; + int found; + + if (strchr(filename, '/') != NULL) { + if (is_there(filename)) { + if (!realpath(filename, retpath)) { + return -1; + } + return 0; + } else { + return -1; + } + } + + found = 0; + while ((d = strsep(&path, ":")) != NULL) { + if (*d == '\0') { + d = "."; + } + if (snprintf(retpath, rpsize, "%s/%s", d, filename) >= (int)rpsize) { + continue; + } + if (is_there((const char *)retpath)) { + found = 1; + break; + } + } + return found; +} + int loader_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop) + struct target_pt_regs *regs, struct image_info *infop, + struct bsd_binprm *bprm) { - struct bsd_binprm bprm; - int retval; - int i; + char *p, *path = NULL, fullpath[PATH_MAX]; + const char *execname = NULL; + int retval, i, found; - bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); + bprm->p = TARGET_PAGE_SIZE * MAX_ARG_PAGES; /* -sizeof(unsigned int); */ for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ - bprm.page[i] = NULL; - retval = open(filename, O_RDONLY); - if (retval < 0) + bprm->page[i] = NULL; + + /* Find target executable in path, if not already an absolute path. */ + p = getenv("PATH"); + if (p != NULL) { + path = g_strdup(p); + if (path == NULL) { + fprintf(stderr, "Out of memory\n"); + return -1; + } + execname = realpath(filename, NULL); + if (execname == NULL) { + execname = g_strdup(filename); + } + found = find_in_path(path, execname, fullpath, sizeof(fullpath)); + /* Absolute path specified but not found? */ + if (found == -1) { + return -1; + } + if (found) { + retval = open(fullpath, O_RDONLY); + bprm->fullpath = g_strdup(fullpath); + } else { + retval = open(execname, O_RDONLY); + bprm->fullpath = NULL; + } + if (execname) { + g_free((void *)execname); + } + g_free(path); + } else { + retval = open(filename, O_RDONLY); + bprm->fullpath = NULL; + } + if (retval < 0) { return retval; - bprm.fd = retval; - bprm.filename = (char *)filename; - bprm.argc = count(argv); - bprm.argv = argv; - bprm.envc = count(envp); - bprm.envp = envp; + } + + bprm->fd = retval; + bprm->filename = (char *)filename; + bprm->argc = count(argv); + bprm->argv = argv; + bprm->envc = count(envp); + bprm->envp = envp; - retval = prepare_binprm(&bprm); + retval = prepare_binprm(bprm); if(retval>=0) { - if (bprm.buf[0] == 0x7f - && bprm.buf[1] == 'E' - && bprm.buf[2] == 'L' - && bprm.buf[3] == 'F') { - retval = load_elf_binary(&bprm,regs,infop); + if (bprm->buf[0] == 0x7f + && bprm->buf[1] == 'E' + && bprm->buf[2] == 'L' + && bprm->buf[3] == 'F') { + retval = load_elf_binary(bprm, regs, infop); } else { fprintf(stderr, "Unknown binary format\n"); return -1; @@ -196,7 +270,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, /* Something went wrong, return the inode and free the argument pages*/ for (i=0 ; i<MAX_ARG_PAGES ; i++) { - g_free(bprm.page[i]); + g_free(bprm->page[i]); } return(retval); } diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index c2e2daa..68d0209 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -91,6 +91,9 @@ enum { #define ELIBBAD 80 #endif +abi_ulong target_stksiz; +abi_ulong target_stkbas; + #ifdef TARGET_I386 #define ELF_PLATFORM get_elf_platform() @@ -1147,8 +1150,8 @@ static void load_symbols(struct elfhdr *hdr, int fd) syminfos = s; } -int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info) +int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; diff --git a/bsd-user/freebsd/os-strace.h b/bsd-user/freebsd/os-strace.h index c856450..a222f09 100644 --- a/bsd-user/freebsd/os-strace.h +++ b/bsd-user/freebsd/os-strace.h @@ -27,9 +27,3 @@ static inline void do_os_print_sysarch(const struct syscallname *name, /* This is arch dependent */ do_freebsd_arch_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6); } - -/* sysarch() is architecture dependent. */ -abi_long do_bsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2) -{ - return do_freebsd_arch_sysarch(cpu_env, arg1, arg2); -} diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c new file mode 100644 index 0000000..24de6b5 --- /dev/null +++ b/bsd-user/freebsd/os-sys.c @@ -0,0 +1,285 @@ +/* + * FreeBSD sysctl() and sysarch() system call emulation + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <string.h> + +#include "qemu.h" + +#include "target_arch_sysarch.h" +#include "target_os_vmparam.h" + +/* + * XXX this uses the undocumented oidfmt interface to find the kind of + * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt() + * (compare to src/sbin/sysctl/sysctl.c) + */ +static int +oidfmt(int *oid, int len, char *fmt, uint32_t *kind) +{ + int qoid[CTL_MAXNAME+2]; + uint8_t buf[BUFSIZ]; + int i; + size_t j; + + qoid[0] = 0; + qoid[1] = 4; + memcpy(qoid + 2, oid, len * sizeof(int)); + + j = sizeof(buf); + i = sysctl(qoid, len + 2, buf, &j, 0, 0); + if (i) { + return i; + } + + if (kind) { + *kind = *(uint32_t *)buf; + } + + if (fmt) { + strcpy(fmt, (char *)(buf + sizeof(uint32_t))); + } + return 0; +} + +/* + * try and convert sysctl return data for the target. + * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT. + */ +static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind) +{ + switch (kind & CTLTYPE) { + case CTLTYPE_INT: + case CTLTYPE_UINT: + *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp); + break; + +#ifdef TARGET_ABI32 + case CTLTYPE_LONG: + case CTLTYPE_ULONG: + *(uint32_t *)holdp = tswap32(*(long *)holdp); + break; +#else + case CTLTYPE_LONG: + *(uint64_t *)holdp = tswap64(*(long *)holdp); + case CTLTYPE_ULONG: + *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp); + break; +#endif +#if !defined(__FreeBSD_version) || __FreeBSD_version < 900031 + case CTLTYPE_QUAD: +#else + case CTLTYPE_U64: + case CTLTYPE_S64: +#endif + *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp); + break; + + case CTLTYPE_STRING: + break; + + default: + /* XXX unhandled */ + return -1; + } + return 0; +} + +/* + * Convert the undocmented name2oid sysctl data for the target. + */ +static inline void sysctl_name2oid(uint32_t *holdp, size_t holdlen) +{ + size_t i; + + for (i = 0; i < holdlen; i++) { + holdp[i] = tswap32(holdp[i]); + } +} + +static inline void sysctl_oidfmt(uint32_t *holdp) +{ + /* byte swap the kind */ + holdp[0] = tswap32(holdp[0]); +} + +abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen, + abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) +{ + abi_long ret; + void *hnamep, *holdp = NULL, *hnewp = NULL; + size_t holdlen; + abi_ulong oldlen = 0; + int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i; + uint32_t kind = 0; + CPUState *cpu = ENV_GET_CPU(env); + TaskState *ts = (TaskState *)cpu->opaque; + + if (oldlenp) { + if (get_user_ual(oldlen, oldlenp)) { + return -TARGET_EFAULT; + } + } + hnamep = lock_user(VERIFY_READ, namep, namelen, 1); + if (hnamep == NULL) { + return -TARGET_EFAULT; + } + if (newp) { + hnewp = lock_user(VERIFY_READ, newp, newlen, 1); + if (hnewp == NULL) { + return -TARGET_EFAULT; + } + } + if (oldp) { + holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0); + if (holdp == NULL) { + return -TARGET_EFAULT; + } + } + holdlen = oldlen; + for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) { + *q++ = tswap32(*p); + } + oidfmt(snamep, namelen, NULL, &kind); + + /* Handle some arch/emulator dependent sysctl()'s here. */ + switch (snamep[0]) { + case CTL_KERN: + switch (snamep[1]) { + case KERN_USRSTACK: +#if TARGET_USRSTACK != 0 + (*(abi_ulong *)holdp) = tswapal(TARGET_USRSTACK); + holdlen = sizeof(abi_ulong); + ret = 0; +#else + ret = -TARGET_ENOENT; +#endif + goto out; + + case KERN_PS_STRINGS: +#if defined(TARGET_PS_STRINGS) + (*(abi_ulong *)holdp) = tswapal(TARGET_PS_STRINGS); + holdlen = sizeof(abi_ulong); + ret = 0; +#else + ret = -TARGET_ENOENT; +#endif + goto out; + + case KERN_PROC: + switch (snamep[2]) { + case KERN_PROC_PATHNAME: + holdlen = strlen(ts->bprm->fullpath) + 1; + if (holdp) { + if (oldlen < holdlen) { + ret = -TARGET_EINVAL; + goto out; + } + strlcpy(holdp, ts->bprm->fullpath, oldlen); + } + ret = 0; + goto out; + + default: + break; + } + break; + + default: + break; + } + break; + + case CTL_HW: + switch (snamep[1]) { + case HW_MACHINE: + strlcpy(holdp, TARGET_HW_MACHINE, oldlen); + ret = 0; + goto out; + + case HW_MACHINE_ARCH: + strlcpy(holdp, TARGET_HW_MACHINE_ARCH, oldlen); + ret = 0; + goto out; + + case 851: /* hw.availpages */ + { + long lvalue; + size_t len = sizeof(lvalue); + + if (sysctlbyname("hw.availpages", &lvalue, &len, NULL, 0) + == -1) { + ret = -1; + } else { + (*(abi_ulong *)holdp) = tswapal((abi_ulong)lvalue); + holdlen = sizeof(abi_ulong); + ret = 0; + } + } + goto out; + + default: + break; + } + default: + break; + } + + ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen)); + if (!ret && (holdp != 0 && holdlen != 0)) { + if (0 == snamep[0] && (3 == snamep[1] || 4 == snamep[1])) { + if (3 == snamep[1]) { + /* Handle the undocumented name2oid special case. */ + sysctl_name2oid(holdp, holdlen); + } else { + /* Handle oidfmt */ + sysctl_oidfmt(holdp); + } + } else { + sysctl_oldcvt(holdp, holdlen, kind); + } + } +#ifdef DEBUG + else { + printf("sysctl(mib[0]=%d, mib[1]=%d, mib[3]=%d...) returned %d\n", + snamep[0], snamep[1], snamep[2], (int)ret); + } +#endif + +out: + if (oldlenp) { + put_user_ual(holdlen, oldlenp); + } + unlock_user(hnamep, namep, 0); + unlock_user(holdp, oldp, holdlen); + if (hnewp) { + unlock_user(hnewp, newp, 0); + } + g_free(snamep); + return ret; +} + +/* sysarch() is architecture dependent. */ +abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2) +{ + + return do_freebsd_arch_sysarch(cpu_env, arg1, arg2); +} diff --git a/bsd-user/freebsd/target_os_stack.h b/bsd-user/freebsd/target_os_stack.h new file mode 100644 index 0000000..c84b69e --- /dev/null +++ b/bsd-user/freebsd/target_os_stack.h @@ -0,0 +1,157 @@ +#ifndef _TARGET_OS_STACK_H_ +#define _TARGET_OS_STACK_H_ + +#include <sys/param.h> +#include "target_arch_sigtramp.h" + +/* + * The inital FreeBSD stack is as follows: + * (see kern/kern_exec.c exec_copyout_strings() ) + * + * Hi Address -> char **ps_argvstr (struct ps_strings for ps, w, etc.) + * unsigned ps_nargvstr + * char **ps_envstr + * PS_STRINGS -> unsigned ps_nenvstr + * + * machine dependent sigcode (sv_sigcode of size + * sv_szsigcode) + * + * execpath (absolute image path for rtld) + * + * SSP Canary (sizeof(long) * 8) + * + * page sizes array (usually sizeof(u_long) ) + * + * "destp" -> argv, env strings (up to 262144 bytes) + */ +static inline int setup_initial_stack(struct bsd_binprm *bprm, + abi_ulong *ret_addr) +{ + int i; + abi_ulong stack_hi_addr; + size_t execpath_len, stringspace; + abi_ulong destp, argvp, envp, p; + struct target_ps_strings ps_strs; + char canary[sizeof(abi_long) * 8]; + + stack_hi_addr = p = target_stkbas + target_stksiz; + + /* Save some space for ps_strings. */ + p -= sizeof(struct target_ps_strings); + +#ifdef TARGET_SZSIGCODE + /* Add machine depedent sigcode. */ + p -= TARGET_SZSIGCODE; + if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc), + TARGET_FREEBSD_NR_sigreturn)) { + errno = EFAULT; + return -1; + } +#endif + if (bprm->fullpath) { + execpath_len = strlen(bprm->fullpath) + 1; + p -= roundup(execpath_len, sizeof(abi_ulong)); + if (memcpy_to_target(p, bprm->fullpath, execpath_len)) { + errno = EFAULT; + return -1; + } + } + /* Add canary for SSP. */ + arc4random_buf(canary, sizeof(canary)); + p -= roundup(sizeof(canary), sizeof(abi_ulong)); + if (memcpy_to_target(p, canary, sizeof(canary))) { + errno = EFAULT; + return -1; + } + /* Add page sizes array. */ + /* p -= sizeof(int); */ + p -= sizeof(abi_ulong); + /* if (put_user_u32(TARGET_PAGE_SIZE, p)) { */ + if (put_user_ual(TARGET_PAGE_SIZE, p)) { + errno = EFAULT; + return -1; + } + /* Calculate the string space needed */ + stringspace = 0; + for (i = 0; i < bprm->argc; ++i) { + stringspace += strlen(bprm->argv[i]) + 1; + } + for (i = 0; i < bprm->envc; ++i) { + stringspace += strlen(bprm->envp[i]) + 1; + } + if (stringspace > TARGET_ARG_MAX) { + errno = ENOMEM; + return -1; + } + + /* Make room for the argv and envp strings */ + /* p = destp = roundup(p - TARGET_SPACE_USRSPACE - (TARGET_ARG_MAX - stringspace), sizeof(abi_ulong)); */ + argvp = p - TARGET_SPACE_USRSPACE; + p = destp = roundup(p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX, sizeof(abi_ulong)); + + /* + * Add argv strings. Note that the argv[] vectors are added by + * loader_build_argptr() + */ + /* XXX need to make room for auxargs */ + /* argvp = destp - ((bprm->argc + bprm->envc + 2) * sizeof(abi_ulong)); */ + /* envp = argvp + (bprm->argc + 2) * sizeof(abi_ulong); */ + envp = argvp + (bprm->argc + 1) * sizeof(abi_ulong); + ps_strs.ps_argvstr = tswapl(argvp); + ps_strs.ps_nargvstr = tswap32(bprm->argc); + for (i = 0; i < bprm->argc; ++i) { + size_t len = strlen(bprm->argv[i]) + 1; + + if (memcpy_to_target(destp, bprm->argv[i], len)) { + errno = EFAULT; + return -1; + } + if (put_user_ual(destp, argvp)) { + errno = EFAULT; + return -1; + } + argvp += sizeof(abi_ulong); + destp += len; + } + if (put_user_ual(0, argvp)) { + errno = EFAULT; + return -1; + } + /* + * Add env strings. Note that the envp[] vectors are added by + * loader_build_argptr(). + */ + ps_strs.ps_envstr = tswapl(envp); + ps_strs.ps_nenvstr = tswap32(bprm->envc); + for (i = 0; i < bprm->envc; ++i) { + size_t len = strlen(bprm->envp[i]) + 1; + + if (memcpy_to_target(destp, bprm->envp[i], len)) { + errno = EFAULT; + return -1; + } + if (put_user_ual(destp, envp)) { + errno = EFAULT; + return -1; + } + envp += sizeof(abi_ulong); + destp += len; + } + if (put_user_ual(0, envp)) { + errno = EFAULT; + return -1; + } + if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs, + sizeof(ps_strs))) { + errno = EFAULT; + return -1; + } + + if (ret_addr) { + *ret_addr = p; + } + + return 0; + } + +#endif /* !_TARGET_OS_STACK_H_ */ diff --git a/bsd-user/i386/syscall.h b/bsd-user/i386/syscall.h index 8028fc8..52de302 100644 --- a/bsd-user/i386/syscall.h +++ b/bsd-user/i386/syscall.h @@ -178,5 +178,7 @@ struct target_vm86plus_struct { #define UNAME_MACHINE "i386" +#define TARGET_HW_MACHINE UNAME_MACHINE +#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE #endif /* ! _I386_SYSCALL_H_ */ diff --git a/bsd-user/i386/target_arch_sigtramp.h b/bsd-user/i386/target_arch_sigtramp.h new file mode 100644 index 0000000..f0f36d1 --- /dev/null +++ b/bsd-user/i386/target_arch_sigtramp.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + + return -TARGET_EOPNOTSUPP; +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ diff --git a/bsd-user/main.c b/bsd-user/main.c index 0ba5955..e11f524 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -541,7 +541,7 @@ int main(int argc, char **argv) } #endif /* CONFIG_USE_GUEST_BASE */ - if (loader_exec(filename, argv+optind, target_environ, regs, info)) { + if (loader_exec(filename, argv+optind, target_environ, regs, info, &bprm)) { printf("Error loading %s\n", filename); _exit(1); } diff --git a/bsd-user/netbsd/os-strace.h b/bsd-user/netbsd/os-strace.h index ead15db..442af7f 100644 --- a/bsd-user/netbsd/os-strace.h +++ b/bsd-user/netbsd/os-strace.h @@ -27,11 +27,3 @@ static inline void do_os_print_sysarch(const struct syscallname *name, qemu_log("qemu: Unsupported syscall %s\n", __func__); return; } - -/* sysarch() is architecture dependent. */ -abi_long do_bsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2) -{ - qemu_log("qemu: Unsupported syscall sysarch()\n"); - return -TARGET_ENOSYS; -} - diff --git a/bsd-user/netbsd/os-sys.c b/bsd-user/netbsd/os-sys.c new file mode 100644 index 0000000..68ea0e1 --- /dev/null +++ b/bsd-user/netbsd/os-sys.c @@ -0,0 +1,46 @@ +/* + * NetBSD sysctl() and sysarch() system call emulation + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <string.h> + +#include "qemu.h" + +#include "target_arch_sysarch.h" +#include "target_os_vmparam.h" + + +/* This must be emulated to support FreeBSD target binaries on NetBSD host. */ + +abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen, + abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) +{ + + qemu_log("qemu: Unsupported syscall __sysctl()\n"); + return -TARGET_ENOSYS; +} + +/* sysarch() is architecture dependent. */ +abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall sysarch()\n"); + return -TARGET_ENOSYS; +} diff --git a/bsd-user/netbsd/target_os_stack.h b/bsd-user/netbsd/target_os_stack.h new file mode 100644 index 0000000..1a26c3f --- /dev/null +++ b/bsd-user/netbsd/target_os_stack.h @@ -0,0 +1,33 @@ +#ifndef _TARGET_OS_STACK_H_ +#define _TARGET_OS_STACK_H_ + +#include "target_arch_sigtramp.h" + +static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p) +{ + int i; + abi_ulong stack_base; + + stack_base = (target_stkbas + target_stksiz) - + MAX_ARG_PAGES * TARGET_PAGE_SIZE; + if (p) { + *p = stack_base; + } + + for (i = 0; i < MAX_ARG_PAGES; i++) { + if (bprm->page[i]) { + info->rss++; + if (!memcpy_to_target(stack_base, bprm->page[i], + TARGET_PAGE_SIZE)) { + errno = EFAULT; + return -1; + } + g_free(bprm->page[i]); + } + stack_base += TARGET_PAGE_SIZE; + } + + return 0; +} + +#endif /* !_TARGET_OS_STACK_H_ */ diff --git a/bsd-user/openbsd/os-strace.h b/bsd-user/openbsd/os-strace.h index 88907b4..d8dc83b 100644 --- a/bsd-user/openbsd/os-strace.h +++ b/bsd-user/openbsd/os-strace.h @@ -27,11 +27,3 @@ static inline void do_os_print_sysarch(const struct syscallname *name, qemu_log("qemu: Unsupported syscall %s\n", __func__); return; } - -/* sysarch() is architecture dependent. */ -abi_long do_bsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2) -{ - - qemu_log("qemu: Unsupported syscall sysarch()\n"); - return -TARGET_ENOSYS; -} diff --git a/bsd-user/openbsd/os-sys.c b/bsd-user/openbsd/os-sys.c new file mode 100644 index 0000000..30df472 --- /dev/null +++ b/bsd-user/openbsd/os-sys.c @@ -0,0 +1,46 @@ +/* + * OpenBSD sysctl() and sysarch() system call emulation + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <string.h> + +#include "qemu.h" + +#include "target_arch_sysarch.h" +#include "target_os_vmparam.h" + + +/* This must be emulated to support FreeBSD target binaries on NetBSD host. */ + +abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen, + abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) +{ + + qemu_log("qemu: Unsupported syscall __sysctl()\n"); + return -TARGET_ENOSYS; +} + +/* sysarch() is architecture dependent. */ +abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall sysarch()\n"); + return -TARGET_ENOSYS; +} diff --git a/bsd-user/openbsd/target_os_stack.h b/bsd-user/openbsd/target_os_stack.h new file mode 100644 index 0000000..1a26c3f --- /dev/null +++ b/bsd-user/openbsd/target_os_stack.h @@ -0,0 +1,33 @@ +#ifndef _TARGET_OS_STACK_H_ +#define _TARGET_OS_STACK_H_ + +#include "target_arch_sigtramp.h" + +static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p) +{ + int i; + abi_ulong stack_base; + + stack_base = (target_stkbas + target_stksiz) - + MAX_ARG_PAGES * TARGET_PAGE_SIZE; + if (p) { + *p = stack_base; + } + + for (i = 0; i < MAX_ARG_PAGES; i++) { + if (bprm->page[i]) { + info->rss++; + if (!memcpy_to_target(stack_base, bprm->page[i], + TARGET_PAGE_SIZE)) { + errno = EFAULT; + return -1; + } + g_free(bprm->page[i]); + } + stack_base += TARGET_PAGE_SIZE; + } + + return 0; +} + +#endif /* !_TARGET_OS_STACK_H_ */ diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index c70602e..eda6f29 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -129,19 +129,23 @@ struct bsd_binprm { int argc, envc; char **argv; char **envp; - char * filename; /* Name of binary */ + char *filename; /* (Given) Name of binary */ + char *fullpath; /* Full path of binary */ + int (*core_dump)(int, const CPUArchState *); }; void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, abi_ulong stringp, int push_ptr); -int loader_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop); +int loader_exec(const char *filename, char **argv, char **envp, + struct target_pt_regs *regs, struct image_info *infop, + struct bsd_binprm *bprm); -int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info); -int load_flt_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info); +int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info); +int load_flt_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info); +int is_target_elf_binary(int fd); abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len); @@ -238,8 +242,14 @@ void end_exclusive(void); void cpu_exec_start(CPUState *cpu); void cpu_exec_end(CPUState *cpu); -/* os-strace.h */ -abi_long do_bsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2); +/* syscall.c */ +abi_long get_errno(abi_long ret); +int is_error(abi_long ret); + +/* os-sys.c */ +abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen, + abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen); +abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2); /* user access */ diff --git a/bsd-user/sparc/syscall.h b/bsd-user/sparc/syscall.h index 7ed2152..3a5b1e2 100644 --- a/bsd-user/sparc/syscall.h +++ b/bsd-user/sparc/syscall.h @@ -27,6 +27,8 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4" +#define TARGET_HW_MACHINE "sparc" +#define TARGET_HW_MACHINE_ARCH "sparc" #define TARGET_SPARC_UTRAP_INSTALL 1 #define TARGET_SPARC_SIGTRAMP_INSTALL 2 diff --git a/bsd-user/sparc/target_arch_sigtramp.h b/bsd-user/sparc/target_arch_sigtramp.h new file mode 100644 index 0000000..f0f36d1 --- /dev/null +++ b/bsd-user/sparc/target_arch_sigtramp.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + + return -TARGET_EOPNOTSUPP; +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ diff --git a/bsd-user/sparc64/syscall.h b/bsd-user/sparc64/syscall.h index 8571092..58cc38d 100644 --- a/bsd-user/sparc64/syscall.h +++ b/bsd-user/sparc64/syscall.h @@ -27,6 +27,8 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4u" +#define TARGET_HW_MACHINE "sparc" +#define TARGET_HW_MACHINE_ARCH "sparc64" #define TARGET_SPARC_UTRAP_INSTALL 1 #define TARGET_SPARC_SIGTRAMP_INSTALL 2 diff --git a/bsd-user/sparc64/target_arch_sigtramp.h b/bsd-user/sparc64/target_arch_sigtramp.h new file mode 100644 index 0000000..f0f36d1 --- /dev/null +++ b/bsd-user/sparc64/target_arch_sigtramp.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + + return -TARGET_EOPNOTSUPP; +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index b3efc3c..dbc212d 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -2,6 +2,7 @@ * BSD syscalls * * Copyright (c) 2003 - 2008 Fabrice Bellard + * Copyright (c) 2013 Stacey D. Son * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,12 +37,17 @@ #include "qemu.h" #include "qemu-common.h" -//#define DEBUG +#define target_to_host_bitmask(x, tbl) (x) + +/* #define DEBUG */ static abi_ulong target_brk; static abi_ulong target_original_brk; -static inline abi_long get_errno(abi_long ret) +/* + * errno conversion. + */ +abi_long get_errno(abi_long ret) { if (ret == -1) /* XXX need to translate host -> target errnos here */ @@ -50,9 +56,7 @@ static inline abi_long get_errno(abi_long ret) return ret; } -#define target_to_host_bitmask(x, tbl) (x) - -static inline int is_error(abi_long ret) +int is_error(abi_long ret) { return (abi_ulong)ret >= (abi_ulong)(-4096); } @@ -96,114 +100,6 @@ static abi_long do_obreak(abi_ulong new_brk) return 0; } -#ifdef __FreeBSD__ -/* - * XXX this uses the undocumented oidfmt interface to find the kind of - * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt() - * (this is mostly copied from src/sbin/sysctl/sysctl.c) - */ -static int -oidfmt(int *oid, int len, char *fmt, uint32_t *kind) -{ - int qoid[CTL_MAXNAME+2]; - uint8_t buf[BUFSIZ]; - int i; - size_t j; - - qoid[0] = 0; - qoid[1] = 4; - memcpy(qoid + 2, oid, len * sizeof(int)); - - j = sizeof(buf); - i = sysctl(qoid, len + 2, buf, &j, 0, 0); - if (i) - return i; - - if (kind) - *kind = *(uint32_t *)buf; - - if (fmt) - strcpy(fmt, (char *)(buf + sizeof(uint32_t))); - return (0); -} - -/* - * try and convert sysctl return data for the target. - * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT. - */ -static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind) -{ - switch (kind & CTLTYPE) { - case CTLTYPE_INT: - case CTLTYPE_UINT: - *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp); - break; -#ifdef TARGET_ABI32 - case CTLTYPE_LONG: - case CTLTYPE_ULONG: - *(uint32_t *)holdp = tswap32(*(long *)holdp); - break; -#else - case CTLTYPE_LONG: - *(uint64_t *)holdp = tswap64(*(long *)holdp); - case CTLTYPE_ULONG: - *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp); - break; -#endif -#ifdef CTLTYPE_U64 - case CTLTYPE_S64: - case CTLTYPE_U64: -#else - case CTLTYPE_QUAD: -#endif - *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp); - break; - case CTLTYPE_STRING: - break; - default: - /* XXX unhandled */ - return -1; - } - return 0; -} - -/* XXX this needs to be emulated on non-FreeBSD hosts... */ -static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp, - abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) -{ - abi_long ret; - void *hnamep, *holdp, *hnewp = NULL; - size_t holdlen; - abi_ulong oldlen = 0; - int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i; - uint32_t kind = 0; - - if (oldlenp) - get_user_ual(oldlen, oldlenp); - if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1))) - return -TARGET_EFAULT; - if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1))) - return -TARGET_EFAULT; - if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0))) - return -TARGET_EFAULT; - holdlen = oldlen; - for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) - *q++ = tswap32(*p); - oidfmt(snamep, namelen, NULL, &kind); - /* XXX swap hnewp */ - ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen)); - if (!ret) - sysctl_oldcvt(holdp, holdlen, kind); - put_user_ual(holdlen, oldlenp); - unlock_user(hnamep, namep, 0); - unlock_user(holdp, oldp, holdlen); - if (hnewp) - unlock_user(hnewp, newp, 0); - g_free(snamep); - return ret; -} -#endif - /* FIXME * lock_iovec()/unlock_iovec() have a return code of 0 for success where * other lock functions have a return code of 0 for failure. @@ -326,20 +222,27 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_FREEBSD_NR_break: ret = do_obreak(arg1); break; -#ifdef __FreeBSD__ - case TARGET_FREEBSD_NR___sysctl: - ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6); + + /* + * sys{ctl, arch, call} + */ + case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */ + ret = do_freebsd_sysctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); break; -#endif - case TARGET_FREEBSD_NR_sysarch: - ret = do_bsd_sysarch(cpu_env, arg1, arg2); + + case TARGET_FREEBSD_NR_sysarch: /* sysarch(2) */ + ret = do_freebsd_sysarch(cpu_env, arg1, arg2); break; - case TARGET_FREEBSD_NR_syscall: - case TARGET_FREEBSD_NR___syscall: - ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0); + + case TARGET_FREEBSD_NR_syscall: /* syscall(2) */ + case TARGET_FREEBSD_NR___syscall: /* __syscall(2) */ + ret = do_freebsd_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, + arg5, arg6, arg7, arg8, 0); break; + default: - ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); + ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, + arg8)); break; } fail: @@ -406,6 +309,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NETBSD_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); break; + case TARGET_NETBSD_NR_syscall: case TARGET_NETBSD_NR___syscall: ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); @@ -478,6 +382,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_OPENBSD_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); break; + case TARGET_OPENBSD_NR_syscall: case TARGET_OPENBSD_NR___syscall: ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); diff --git a/bsd-user/x86_64/syscall.h b/bsd-user/x86_64/syscall.h index 4e77235..4fff6a5 100644 --- a/bsd-user/x86_64/syscall.h +++ b/bsd-user/x86_64/syscall.h @@ -129,6 +129,8 @@ struct target_msqid64_ds { #define UNAME_MACHINE "x86_64" +#define TARGET_HW_MACHINE "amd64" +#define TARGET_HW_MACHINE_ARCH "amd64" #define TARGET_ARCH_SET_GS 0x1001 #define TARGET_ARCH_SET_FS 0x1002 diff --git a/bsd-user/x86_64/target_arch_sigtramp.h b/bsd-user/x86_64/target_arch_sigtramp.h new file mode 100644 index 0000000..f0f36d1 --- /dev/null +++ b/bsd-user/x86_64/target_arch_sigtramp.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + + return -TARGET_EOPNOTSUPP; +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ -- 2.0.0