From 579a97f7ff4c0f958a5d8adcba717a205bb58567 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 14:26:47 +0000 Subject: [PATCH] Linux user memory access API change (initial patch by Thayne Harbaugh) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3583 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- arm-semi.c | 52 ++- exec.c | 10 +- linux-user/elfload.c | 3 +- linux-user/flatload.c | 2 +- linux-user/linuxload.c | 9 +- linux-user/qemu.h | 121 +++-- linux-user/signal.c | 238 +++++----- linux-user/strace.c | 33 +- linux-user/syscall.c | 983 ++++++++++++++++++++++++----------------- linux-user/uaccess.c | 51 +++ linux-user/vm86.c | 7 +- m68k-semi.c | 84 +++- softmmu-semi.h | 2 +- 14 files changed, 973 insertions(+), 624 deletions(-) create mode 100644 linux-user/uaccess.c diff --git a/Makefile.target b/Makefile.target index 33cf23bec1..18938e8796 100644 --- a/Makefile.target +++ b/Makefile.target @@ -260,7 +260,7 @@ endif ifdef CONFIG_LINUX_USER OBJS= main.o syscall.o strace.o mmap.o signal.o path.o osdep.o thunk.o \ - elfload.o linuxload.o + elfload.o linuxload.o uaccess.o LIBS+= $(AIOLIBS) ifdef TARGET_HAS_BFLT OBJS+= flatload.o diff --git a/arm-semi.c b/arm-semi.c index ff7a343bc5..d5fb9a55a7 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -184,9 +184,11 @@ uint32_t do_arm_semihosting(CPUState *env) args = env->regs[1]; switch (nr) { case SYS_OPEN: - s = lock_user_string(ARG(0)); + if (!(s = lock_user_string(ARG(0)))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; if (ARG(1) >= 12) - return (uint32_t)-1; + return (uint32_t)-1; if (strcmp(s, ":tt") == 0) { if (ARG(1) < 4) return STDIN_FILENO; @@ -221,7 +223,9 @@ uint32_t do_arm_semihosting(CPUState *env) } } case SYS_WRITE0: - s = lock_user_string(args); + if (!(s = lock_user_string(args))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; len = strlen(s); if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len); @@ -238,7 +242,9 @@ uint32_t do_arm_semihosting(CPUState *env) gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len); return env->regs[0]; } else { - s = lock_user(ARG(1), len, 1); + if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; ret = set_swi_errno(ts, write(ARG(0), s, len)); unlock_user(s, ARG(1), 0); if (ret == (uint32_t)-1) @@ -252,7 +258,9 @@ uint32_t do_arm_semihosting(CPUState *env) gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len); return env->regs[0]; } else { - s = lock_user(ARG(1), len, 0); + if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; do ret = set_swi_errno(ts, read(ARG(0), s, len)); while (ret == -1 && errno == EINTR); @@ -301,7 +309,9 @@ uint32_t do_arm_semihosting(CPUState *env) gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1); ret = env->regs[0]; } else { - s = lock_user_string(ARG(0)); + if (!(s = lock_user_string(ARG(0)))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; ret = set_swi_errno(ts, remove(s)); unlock_user(s, ARG(0), 0); } @@ -315,9 +325,15 @@ uint32_t do_arm_semihosting(CPUState *env) char *s2; s = lock_user_string(ARG(0)); s2 = lock_user_string(ARG(2)); - ret = set_swi_errno(ts, rename(s, s2)); - unlock_user(s2, ARG(2), 0); - unlock_user(s, ARG(0), 0); + if (!s || !s2) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + ret = (uint32_t)-1; + else + ret = set_swi_errno(ts, rename(s, s2)); + if (s2) + unlock_user(s2, ARG(2), 0); + if (s) + unlock_user(s, ARG(0), 0); return ret; } case SYS_CLOCK: @@ -329,7 +345,9 @@ uint32_t do_arm_semihosting(CPUState *env) gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1); return env->regs[0]; } else { - s = lock_user_string(ARG(0)); + if (!(s = lock_user_string(ARG(0)))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; ret = set_swi_errno(ts, system(s)); unlock_user(s, ARG(0), 0); } @@ -346,7 +364,11 @@ uint32_t do_arm_semihosting(CPUState *env) char **arg = ts->info->host_argv; int len = ARG(1); /* lock the buffer on the ARM side */ - char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0); + char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0); + + if (!cmdline_buffer) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; s = cmdline_buffer; while (*arg && len > 2) { @@ -402,7 +424,9 @@ uint32_t do_arm_semihosting(CPUState *env) ts->heap_limit = limit; } - ptr = lock_user(ARG(0), 16, 0); + if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; ptr[0] = tswap32(ts->heap_base); ptr[1] = tswap32(ts->heap_limit); ptr[2] = tswap32(ts->stack_base); @@ -410,7 +434,9 @@ uint32_t do_arm_semihosting(CPUState *env) unlock_user(ptr, ARG(0), 16); #else limit = ram_size; - ptr = lock_user(ARG(0), 16, 0); + if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; /* TODO: Make this use the limit of the loaded application. */ ptr[0] = tswap32(limit / 2); ptr[1] = tswap32(limit); diff --git a/exec.c b/exec.c index 7987803634..e817a4e5e2 100644 --- a/exec.c +++ b/exec.c @@ -2510,13 +2510,19 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, if (is_write) { if (!(flags & PAGE_WRITE)) return; - p = lock_user(addr, len, 0); + /* XXX: this code should not depend on lock_user */ + if (!(p = lock_user(VERIFY_WRITE, addr, len, 0))) + /* FIXME - should this return an error rather than just fail? */ + return; memcpy(p, buf, len); unlock_user(p, addr, len); } else { if (!(flags & PAGE_READ)) return; - p = lock_user(addr, len, 1); + /* XXX: this code should not depend on lock_user */ + if (!(p = lock_user(VERIFY_READ, addr, len, 1))) + /* FIXME - should this return an error rather than just fail? */ + return; memcpy(buf, p, len); unlock_user(p, addr, 0); } diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 2d758de204..14c6417aee 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -677,7 +677,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { info->rss++; - + /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); free(bprm->page[i]); } @@ -760,6 +760,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, size_t len = strlen(k_platform) + 1; sp -= (len + n - 1) & ~(n - 1); u_platform = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(sp, k_platform, len); } /* diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 86b77f9889..7a76c0fcda 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -108,7 +108,7 @@ int target_pread(int fd, abi_ulong ptr, abi_ulong len, void *buf; int ret; - buf = lock_user(ptr, len, 0); + buf = lock_user(VERIFY_WRITE, ptr, len, 0); ret = pread(fd, buf, len, offset); unlock_user(buf, ptr, len); return ret; diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 42a02d206d..684ec06ce3 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -13,14 +13,17 @@ #define NGROUPS 32 /* ??? This should really be somewhere else. */ -void memcpy_to_target(abi_ulong dest, const void *src, - unsigned long len) +abi_long memcpy_to_target(abi_ulong dest, const void *src, + unsigned long len) { void *host_ptr; - host_ptr = lock_user(dest, len, 0); + host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); + if (!host_ptr) + return -TARGET_EFAULT; memcpy(host_ptr, src, len); unlock_user(host_ptr, dest, 1); + return 0; } static int in_group_p(gid_t g) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 6fc0bbffcb..68ce12a62d 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -146,8 +146,8 @@ int load_elf_binary_multi(struct linux_binprm *bprm, struct image_info *info); #endif -void memcpy_to_target(abi_ulong dest, const void *src, - unsigned long len); +abi_long memcpy_to_target(abi_ulong dest, const void *src, + unsigned long len); void target_set_brk(abi_ulong new_brk); abi_long do_brk(abi_ulong new_brk); void syscall_init(void); @@ -179,9 +179,7 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); long do_sigreturn(CPUState *env); long do_rt_sigreturn(CPUState *env); -int do_sigaltstack(const struct target_sigaltstack *uss, - struct target_sigaltstack *uoss, - abi_ulong sp); +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); #ifdef TARGET_I386 /* vm86.c */ @@ -207,12 +205,15 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); /* user access */ #define VERIFY_READ 0 -#define VERIFY_WRITE 1 +#define VERIFY_WRITE 1 /* implies read access */ #define access_ok(type,addr,size) \ (page_check_range((target_ulong)addr,size,(type==VERIFY_READ)?PAGE_READ:PAGE_WRITE)==0) /* NOTE __get_user and __put_user use host pointers and don't check access. */ +/* These are usually used to access struct data members once the + * struct has been locked - usually with lock_user_struct(). + */ #define __put_user(x, hptr)\ ({\ int size = sizeof(*hptr);\ @@ -257,26 +258,44 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); 0;\ }) -#define put_user(x,ptr)\ -({\ - int __ret;\ - if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\ - __ret = __put_user(x, ptr);\ - else\ - __ret = -EFAULT;\ - __ret;\ +/* put_user()/get_user() take a guest address and check access */ +/* These are usually used to access an atomic data type, such as an int, + * that has been passed by address. These internally perform locking + * and unlocking on the data type. + */ +#define put_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type *__hptr; \ + abi_long __ret; \ + if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \ + __ret = __put_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, sizeof(target_type)); \ + } else \ + __ret = -TARGET_EFAULT; \ + __ret; \ }) -#define get_user(x,ptr)\ -({\ - int __ret;\ - if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\ - __ret = __get_user(x, ptr);\ - else\ - __ret = -EFAULT;\ - __ret;\ +#define get_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type *__hptr; \ + abi_long __ret; \ + if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ + __ret = __get_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, 0); \ + } else \ + __ret = -TARGET_EFAULT; \ + __ret; \ }) +/* copy_from_user() and copy_to_user() are usually used to copy data + * buffers between the target and host. These internally perform + * locking/unlocking of the memory. + */ +abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len); +abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); + /* Functions for accessing guest memory. The tget and tput functions read/write single values, byteswapping as neccessary. The lock_user gets a pointer to a contiguous area of guest memory, but does not perform @@ -285,53 +304,61 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); /* Lock an area of guest memory into the host. If copy is true then the host area will have the same contents as the guest. */ -static inline void *lock_user(abi_ulong guest_addr, long len, int copy) +static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) { + if (!access_ok(type, guest_addr, len)) + return NULL; #ifdef DEBUG_REMAP - void *addr; - addr = malloc(len); - if (copy) - memcpy(addr, g2h(guest_addr), len); - else - memset(addr, 0, len); - return addr; + { + void *addr; + addr = malloc(len); + if (copy) + memcpy(addr, g2h(guest_addr), len); + else + memset(addr, 0, len); + return addr; + } #else return g2h(guest_addr); #endif } -/* Unlock an area of guest memory. The first LEN bytes must be flushed back - to guest memory. */ -static inline void unlock_user(void *host_addr, abi_ulong guest_addr, +/* Unlock an area of guest memory. The first LEN bytes must be + flushed back to guest memory. host_ptr = NULL is explicitely + allowed and does nothing. */ +static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len) { + #ifdef DEBUG_REMAP - if (host_addr == g2h(guest_addr)) + if (!host_ptr) + return; + if (host_ptr == g2h(guest_addr)) return; if (len > 0) - memcpy(g2h(guest_addr), host_addr, len); - free(host_addr); + memcpy(g2h(guest_ptr), host_ptr, len); + free(host_ptr); #endif } -/* Return the length of a string in target memory. */ -static inline int target_strlen(abi_ulong ptr) -{ - return strlen(g2h(ptr)); -} +/* Return the length of a string in target memory or -TARGET_EFAULT if + access error. */ +abi_long target_strlen(abi_ulong gaddr); /* Like lock_user but for null terminated strings. */ static inline void *lock_user_string(abi_ulong guest_addr) { - long len; - len = target_strlen(guest_addr) + 1; - return lock_user(guest_addr, len, 1); + abi_long len; + len = target_strlen(guest_addr); + if (len < 0) + return NULL; + return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1); } /* Helper macros for locking/ulocking a target struct. */ -#define lock_user_struct(host_ptr, guest_addr, copy) \ - host_ptr = lock_user(guest_addr, sizeof(*host_ptr), copy) -#define unlock_user_struct(host_ptr, guest_addr, copy) \ +#define lock_user_struct(type, host_ptr, guest_addr, copy) \ + (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy)) +#define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) #define tget8(addr) ldub(addr) diff --git a/linux-user/signal.c b/linux-user/signal.c index a0f1511022..e9da0971f9 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -435,31 +435,32 @@ static void host_signal_handler(int host_signum, siginfo_t *info, } /* do_sigaltstack() returns target values and errnos. */ -int do_sigaltstack(const struct target_sigaltstack *uss, - struct target_sigaltstack *uoss, - abi_ulong sp) +/* compare linux/kernel/signal.c:do_sigaltstack() */ +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) { int ret; struct target_sigaltstack oss; /* XXX: test errors */ - if(uoss) + if(uoss_addr) { __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp); __put_user(target_sigaltstack_used.ss_size, &oss.ss_size); __put_user(sas_ss_flags(sp), &oss.ss_flags); } - if(uss) + if(uss_addr) { - struct target_sigaltstack ss; + struct target_sigaltstack *uss; + struct target_sigaltstack ss; ret = -TARGET_EFAULT; - if (!access_ok(VERIFY_READ, uss, sizeof(*uss)) + if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) || __get_user(ss.ss_sp, &uss->ss_sp) || __get_user(ss.ss_size, &uss->ss_size) || __get_user(ss.ss_flags, &uss->ss_flags)) goto out; + unlock_user_struct(uss, uss_addr, 0); ret = -TARGET_EPERM; if (on_sig_stack(sp)) @@ -484,11 +485,10 @@ int do_sigaltstack(const struct target_sigaltstack *uss, target_sigaltstack_used.ss_size = ss.ss_size; } - if (uoss) { + if (uoss_addr) { ret = -TARGET_EFAULT; - if (!access_ok(VERIFY_WRITE, uoss, sizeof(oss))) + if (copy_to_user(uoss_addr, &oss, sizeof(oss))) goto out; - memcpy(uoss, &oss, sizeof(oss)); } ret = 0; @@ -671,6 +671,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, { int err = 0; + /* already locked in setup_frame() */ err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs); err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs); err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es); @@ -706,7 +707,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, * Determine which stack to use.. */ -static inline void * +static inline abi_ulong get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) { unsigned long esp; @@ -726,19 +727,22 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) ka->sa.sa_restorer) { esp = (unsigned long) ka->sa.sa_restorer; } - return g2h((esp - frame_size) & -8ul); + return (esp - frame_size) & -8ul; } +/* compare linux/arch/i386/kernel/signal.c:setup_frame() */ static void setup_frame(int sig, struct emulated_sigaction *ka, target_sigset_t *set, CPUX86State *env) { + abi_ulong frame_addr; struct sigframe *frame; int i, err = 0; - frame = get_sigframe(ka, env, sizeof(*frame)); + frame_addr = get_sigframe(ka, env, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; + err |= __put_user((/*current->exec_domain && current->exec_domain->signal_invmap && sig < 32 @@ -786,24 +790,29 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, cpu_x86_load_seg(env, R_CS, __USER_CS); env->eflags &= ~TF_MASK; + unlock_user_struct(frame, frame_addr, 1); + return; give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); if (sig == TARGET_SIGSEGV) ka->sa._sa_handler = TARGET_SIG_DFL; force_sig(TARGET_SIGSEGV /* , current */); } +/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUX86State *env) { + abi_ulong frame_addr; struct rt_sigframe *frame; int i, err = 0; - frame = get_sigframe(ka, env, sizeof(*frame)); + frame_addr = get_sigframe(ka, env, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; err |= __put_user((/*current->exec_domain @@ -859,9 +868,12 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, cpu_x86_load_seg(env, R_CS, __USER_CS); env->eflags &= ~TF_MASK; + unlock_user_struct(frame, frame_addr, 1); + return; give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); if (sig == TARGET_SIGSEGV) ka->sa._sa_handler = TARGET_SIG_DFL; force_sig(TARGET_SIGSEGV /* , current */); @@ -918,7 +930,8 @@ badframe: long do_sigreturn(CPUX86State *env) { - struct sigframe *frame = (struct sigframe *)g2h(env->regs[R_ESP] - 8); + struct sigframe *frame; + abi_ulong frame_addr = env->regs[R_ESP] - 8; target_sigset_t target_set; sigset_t set; int eax, i; @@ -926,6 +939,8 @@ long do_sigreturn(CPUX86State *env) #if defined(DEBUG_SIGNAL) fprintf(stderr, "do_sigreturn\n"); #endif + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; /* set blocked signals */ if (__get_user(target_set.sig[0], &frame->sc.oldmask)) goto badframe; @@ -940,9 +955,11 @@ long do_sigreturn(CPUX86State *env) /* restore registers */ if (restore_sigcontext(env, &frame->sc, &eax)) goto badframe; + unlock_user_struct(frame, frame_addr, 0); return eax; badframe: + unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); return 0; } @@ -963,7 +980,7 @@ long do_rt_sigreturn(CPUX86State *env) if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) goto badframe; - if (do_sigaltstack(&frame->uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(h2g(&frame->uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; return eax; @@ -1086,7 +1103,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ return err; } -static inline void * +static inline abi_ulong get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) { unsigned long sp = regs->regs[13]; @@ -1099,7 +1116,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) /* * ATPCS B01 mandates 8-byte alignment */ - return g2h((sp - framesize) & ~7); + return (sp - framesize) & ~7; } static int @@ -1167,33 +1184,43 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, return 0; } +/* compare linux/arch/arm/kernel/signal.c:setup_frame() */ static void setup_frame(int usig, struct emulated_sigaction *ka, target_sigset_t *set, CPUState *regs) { - struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); + struct sigframe *frame; + abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); int i, err = 0; + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + return; + err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); for(i = 1; i < TARGET_NSIG_WORDS; i++) { if (__put_user(set->sig[i], &frame->extramask[i - 1])) - return; + goto end; } if (err == 0) err = setup_return(regs, ka, &frame->retcode, frame, usig); + +end: + unlock_user_struct(frame, frame_addr, 1); // return err; } +/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { - struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame)); + struct rt_sigframe *frame; + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); struct target_sigaltstack stack; int i, err = 0; - if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) return /* 1 */; __put_user_error(&frame->info, (abi_ulong *)&frame->pinfo, err); @@ -1207,16 +1234,13 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); - if (!access_ok(VERIFY_WRITE, &frame->uc.tuc_stack, sizeof(stack))) - err = 1; - else - memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); + err |= copy_to_user(&frame->uc.tuc_stack, &stack, sizeof(stack)); err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ env, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) - return; + goto end; } if (err == 0) @@ -1232,6 +1256,9 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, env->regs[2] = (abi_ulong)frame->puc; } +end: + unlock_user_struct(frame, frame_addr, 1); + // return err; } @@ -1338,7 +1365,7 @@ long do_rt_sigreturn(CPUState *env) if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) goto badframe; - if (do_sigaltstack(&frame->uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(h2g(&frame->uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; #if 0 @@ -1788,8 +1815,8 @@ void sparc64_set_context(CPUSPARCState *env) abi_ulong *src, *dst; grp = &ucp->uc_mcontext.mc_gregs; - err = get_user(pc, &((*grp)[MC_PC])); - err |= get_user(npc, &((*grp)[MC_NPC])); + err = __get_user(pc, &((*grp)[MC_PC])); + err |= __get_user(npc, &((*grp)[MC_NPC])); if (err || ((pc | npc) & 3)) goto do_sigsegv; if (env->regwptr[UREG_I1]) { @@ -1797,14 +1824,14 @@ void sparc64_set_context(CPUSPARCState *env) sigset_t set; if (TARGET_NSIG_WORDS == 1) { - if (get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0])) + if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0])) goto do_sigsegv; } else { src = &ucp->uc_sigmask; dst = &target_set; for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong); i++, dst++, src++) - err |= get_user(dst, src); + err |= __get_user(dst, src); if (err) goto do_sigsegv; } @@ -1813,44 +1840,44 @@ void sparc64_set_context(CPUSPARCState *env) } env->pc = pc; env->npc = npc; - err |= get_user(env->y, &((*grp)[MC_Y])); - err |= get_user(tstate, &((*grp)[MC_TSTATE])); + err |= __get_user(env->y, &((*grp)[MC_Y])); + err |= __get_user(tstate, &((*grp)[MC_TSTATE])); env->asi = (tstate >> 24) & 0xff; PUT_CCR(env, tstate >> 32); PUT_CWP64(env, tstate & 0x1f); - err |= get_user(env->gregs[1], (&(*grp)[MC_G1])); - err |= get_user(env->gregs[2], (&(*grp)[MC_G2])); - err |= get_user(env->gregs[3], (&(*grp)[MC_G3])); - err |= get_user(env->gregs[4], (&(*grp)[MC_G4])); - err |= get_user(env->gregs[5], (&(*grp)[MC_G5])); - err |= get_user(env->gregs[6], (&(*grp)[MC_G6])); - err |= get_user(env->gregs[7], (&(*grp)[MC_G7])); - err |= get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0])); - err |= get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1])); - err |= get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2])); - err |= get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3])); - err |= get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4])); - err |= get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5])); - err |= get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6])); - err |= get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7])); + err |= __get_user(env->gregs[1], (&(*grp)[MC_G1])); + err |= __get_user(env->gregs[2], (&(*grp)[MC_G2])); + err |= __get_user(env->gregs[3], (&(*grp)[MC_G3])); + err |= __get_user(env->gregs[4], (&(*grp)[MC_G4])); + err |= __get_user(env->gregs[5], (&(*grp)[MC_G5])); + err |= __get_user(env->gregs[6], (&(*grp)[MC_G6])); + err |= __get_user(env->gregs[7], (&(*grp)[MC_G7])); + err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0])); + err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1])); + err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2])); + err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3])); + err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4])); + err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5])); + err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6])); + err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7])); - err |= get_user(fp, &(ucp->uc_mcontext.mc_fp)); - err |= get_user(i7, &(ucp->uc_mcontext.mc_i7)); - err |= put_user(fp, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); - err |= put_user(i7, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); + err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp)); + err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7)); + err |= __put_user(fp, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); + err |= __put_user(i7, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); - err |= get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); - err |= get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); + err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); + err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); src = &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs); dst = &env->fpr; for (i = 0; i < 64; i++, dst++, src++) - err |= get_user(dst, src); - err |= get_user(env->fsr, - &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); - err |= get_user(env->gsr, - &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); + err |= __get_user(dst, src); + err |= __get_user(env->fsr, + &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); + err |= __get_user(env->gsr, + &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); if (err) goto do_sigsegv; @@ -1884,52 +1911,52 @@ void sparc64_get_context(CPUSPARCState *env) sigprocmask(0, NULL, &set); host_to_target_sigset_internal(&target_set, &set); if (TARGET_NSIG_WORDS == 1) - err |= put_user(target_set.sig[0], - (abi_ulong *)&ucp->uc_sigmask); + err |= __put_user(target_set.sig[0], + (abi_ulong *)&ucp->uc_sigmask); else { src = &target_set; dst = &ucp->uc_sigmask; for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong); i++, dst++, src++) - err |= put_user(src, dst); + err |= __put_user(src, dst); if (err) goto do_sigsegv; } - err |= put_user(env->tstate, &((*grp)[MC_TSTATE])); - err |= put_user(env->pc, &((*grp)[MC_PC])); - err |= put_user(env->npc, &((*grp)[MC_NPC])); - err |= put_user(env->y, &((*grp)[MC_Y])); - err |= put_user(env->gregs[1], &((*grp)[MC_G1])); - err |= put_user(env->gregs[2], &((*grp)[MC_G2])); - err |= put_user(env->gregs[3], &((*grp)[MC_G3])); - err |= put_user(env->gregs[4], &((*grp)[MC_G4])); - err |= put_user(env->gregs[5], &((*grp)[MC_G5])); - err |= put_user(env->gregs[6], &((*grp)[MC_G6])); - err |= put_user(env->gregs[7], &((*grp)[MC_G7])); - err |= put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0])); - err |= put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1])); - err |= put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2])); - err |= put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3])); - err |= put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4])); - err |= put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5])); - err |= put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6])); - err |= put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7])); + err |= __put_user(env->tstate, &((*grp)[MC_TSTATE])); + err |= __put_user(env->pc, &((*grp)[MC_PC])); + err |= __put_user(env->npc, &((*grp)[MC_NPC])); + err |= __put_user(env->y, &((*grp)[MC_Y])); + err |= __put_user(env->gregs[1], &((*grp)[MC_G1])); + err |= __put_user(env->gregs[2], &((*grp)[MC_G2])); + err |= __put_user(env->gregs[3], &((*grp)[MC_G3])); + err |= __put_user(env->gregs[4], &((*grp)[MC_G4])); + err |= __put_user(env->gregs[5], &((*grp)[MC_G5])); + err |= __put_user(env->gregs[6], &((*grp)[MC_G6])); + err |= __put_user(env->gregs[7], &((*grp)[MC_G7])); + err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0])); + err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1])); + err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2])); + err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3])); + err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4])); + err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5])); + err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6])); + err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7])); - err |= get_user(fp, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); - err |= get_user(i7, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); - err |= put_user(fp, &(mcp->mc_fp)); - err |= put_user(i7, &(mcp->mc_i7)); + err |= __get_user(fp, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); + err |= __get_user(i7, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); + err |= __put_user(fp, &(mcp->mc_fp)); + err |= __put_user(i7, &(mcp->mc_i7)); src = &env->fpr; dst = &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs); for (i = 0; i < 64; i++, dst++, src++) - err |= put_user(src, dst); - err |= put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr)); - err |= put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr)); - err |= put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs)); + err |= __put_user(src, dst); + err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr)); + err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr)); + err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs)); if (err) goto do_sigsegv; @@ -2191,7 +2218,7 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) /* * Determine which stack to use.. */ -static inline void * +static inline abi_ulong get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) { unsigned long sp; @@ -2211,17 +2238,19 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; } - return g2h((sp - frame_size) & ~7); + return (sp - frame_size) & ~7; } +/* compare linux/arch/mips/kernel/signal.c:setup_frame() */ static void setup_frame(int sig, struct emulated_sigaction * ka, - target_sigset_t *set, CPUState *regs) + target_sigset_t *set, CPUState *regs) { struct sigframe *frame; + abi_ulong frame_addr; int i; - frame = get_sigframe(ka, regs, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); @@ -2253,9 +2282,11 @@ static void setup_frame(int sig, struct emulated_sigaction * ka, * since it returns to userland using eret * we cannot do this here, and we must set PC directly */ regs->PC[regs->current_tc] = regs->gpr[25][regs->current_tc] = ka->sa._sa_handler; + unlock_user_struct(frame, frame_addr, 1); return; give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); force_sig(TARGET_SIGSEGV/*, current*/); return; } @@ -2263,6 +2294,7 @@ give_sigsegv: long do_sigreturn(CPUState *regs) { struct sigframe *frame; + abi_ulong frame_addr; sigset_t blocked; target_sigset_t target_set; int i; @@ -2270,8 +2302,8 @@ long do_sigreturn(CPUState *regs) #if defined(DEBUG_SIGNAL) fprintf(stderr, "do_sigreturn\n"); #endif - frame = (struct sigframe *) regs->gpr[29][regs->current_tc]; - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + frame_addr = regs->gpr[29][regs->current_tc]; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; for(i = 0; i < TARGET_NSIG_WORDS; i++) { diff --git a/linux-user/strace.c b/linux-user/strace.c index c645ddfca0..315ae5c312 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -81,14 +81,18 @@ print_fdset(int n, target_ulong target_fds_addr) gemu_log("["); if( target_fds_addr ) { - target_long *target_fds; + abi_long *target_fds; - if (!access_ok(VERIFY_READ, target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1))) + target_fds = lock_user(VERIFY_READ, + target_fds_addr, + sizeof(*target_fds)*(n / TARGET_ABI_BITS + 1), + 1); + + if (!target_fds) return; - target_fds = lock_user(target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1), 1); for (i=n; i>=0; i--) { - if ((tswapl(target_fds[i / TARGET_LONG_BITS]) >> (i & (TARGET_LONG_BITS - 1))) & 1) + if ((tswapl(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1) gemu_log("%d,", i ); } unlock_user(target_fds, target_fds_addr, 0); @@ -102,10 +106,9 @@ print_timeval(target_ulong tv_addr) if( tv_addr ) { struct target_timeval *tv; - if (!access_ok(VERIFY_READ, tv_addr, sizeof(*tv))) + tv = lock_user(VERIFY_READ, tv_addr, sizeof(*tv), 1); + if (!tv) return; - - tv = lock_user(tv_addr, sizeof(*tv), 1); gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}", tv->tv_sec, tv->tv_usec); unlock_user(tv, tv_addr, 0); @@ -165,27 +168,25 @@ print_execve(struct syscallname *name, target_ulong arg_ptr_addr; char *s; - if (!access_ok(VERIFY_READ, arg1, 1)) + if (!(s = lock_user_string(arg1))) return; - - s = lock_user_string(arg1); gemu_log("%s(\"%s\",{", name->name, s); unlock_user(s, arg1, 0); for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(target_ulong)) { target_ulong *arg_ptr, arg_addr, s_addr; - if (!access_ok(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong))) + arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong), 1); + if (!arg_ptr) return; - - arg_ptr = lock_user(arg_ptr_addr, sizeof(target_ulong), 1); arg_addr = tswapl(*arg_ptr); unlock_user(arg_ptr, arg_ptr_addr, 0); if (!arg_addr) break; - s = lock_user_string(arg_addr); - gemu_log("\"%s\",", s); - unlock_user(s, s_addr, 0); + if ((s = lock_user_string(arg_addr))) { + gemu_log("\"%s\",", s); + unlock_user(s, s_addr, 0); + } } gemu_log("NULL})"); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 07e84d9632..656f78ee4a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -504,12 +504,13 @@ static inline abi_long host_to_target_clock_t(long ticks) #endif } -static inline void host_to_target_rusage(abi_ulong target_addr, - const struct rusage *rusage) +static inline abi_long host_to_target_rusage(abi_ulong target_addr, + const struct rusage *rusage) { struct target_rusage *target_rusage; - lock_user_struct(target_rusage, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) + return -TARGET_EFAULT; target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec); target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec); target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec); @@ -529,28 +530,36 @@ static inline void host_to_target_rusage(abi_ulong target_addr, target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw); target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw); unlock_user_struct(target_rusage, target_addr, 1); + + return 0; } -static inline void target_to_host_timeval(struct timeval *tv, - abi_ulong target_addr) +static inline abi_long target_to_host_timeval(struct timeval *tv, + abi_ulong target_addr) { struct target_timeval *target_tv; - lock_user_struct(target_tv, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_tv, target_addr, 1)) + return -TARGET_EFAULT; tv->tv_sec = tswapl(target_tv->tv_sec); tv->tv_usec = tswapl(target_tv->tv_usec); unlock_user_struct(target_tv, target_addr, 0); + + return 0; } -static inline void host_to_target_timeval(abi_ulong target_addr, - const struct timeval *tv) +static inline abi_long host_to_target_timeval(abi_ulong target_addr, + const struct timeval *tv) { struct target_timeval *target_tv; - lock_user_struct(target_tv, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_tv, target_addr, 0)) + return -TARGET_EFAULT; target_tv->tv_sec = tswapl(tv->tv_sec); target_tv->tv_usec = tswapl(tv->tv_usec); unlock_user_struct(target_tv, target_addr, 1); + + return 0; } @@ -567,21 +576,33 @@ static abi_long do_select(int n, int ok; if (rfd_p) { - target_rfds = lock_user(rfd_p, sizeof(abi_long) * n, 1); + target_rfds = lock_user(VERIFY_WRITE, rfd_p, sizeof(abi_long) * n, 1); + if (!target_rfds) { + ret = -TARGET_EFAULT; + goto end; + } rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); } else { target_rfds = NULL; rfds_ptr = NULL; } if (wfd_p) { - target_wfds = lock_user(wfd_p, sizeof(abi_long) * n, 1); + target_wfds = lock_user(VERIFY_WRITE, wfd_p, sizeof(abi_long) * n, 1); + if (!target_wfds) { + ret = -TARGET_EFAULT; + goto end; + } wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); } else { target_wfds = NULL; wfds_ptr = NULL; } if (efd_p) { - target_efds = lock_user(efd_p, sizeof(abi_long) * n, 1); + target_efds = lock_user(VERIFY_WRITE, efd_p, sizeof(abi_long) * n, 1); + if (!target_efds) { + ret = -TARGET_EFAULT; + goto end; + } efds_ptr = target_to_host_fds(&efds, target_efds, n); } else { target_efds = NULL; @@ -606,38 +627,45 @@ static abi_long do_select(int n, host_to_target_timeval(target_tv, &tv); } } - if (target_rfds) - unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); - if (target_wfds) - unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); - if (target_efds) - unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); + +end: + unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); + unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); + unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); return ret; } -static inline void target_to_host_sockaddr(struct sockaddr *addr, - abi_ulong target_addr, - socklen_t len) +static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, + abi_ulong target_addr, + socklen_t len) { struct target_sockaddr *target_saddr; - target_saddr = lock_user(target_addr, len, 1); + target_saddr = lock_user(VERIFY_READ, target_addr, len, 1); + if (!target_saddr) + return -TARGET_EFAULT; memcpy(addr, target_saddr, len); addr->sa_family = tswap16(target_saddr->sa_family); unlock_user(target_saddr, target_addr, 0); + + return 0; } -static inline void host_to_target_sockaddr(abi_ulong target_addr, - struct sockaddr *addr, - socklen_t len) +static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, + struct sockaddr *addr, + socklen_t len) { struct target_sockaddr *target_saddr; - target_saddr = lock_user(target_addr, len, 0); + target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0); + if (!target_saddr) + return -TARGET_EFAULT; memcpy(target_saddr, addr, len); target_saddr->sa_family = tswap16(addr->sa_family); unlock_user(target_saddr, target_addr, len); + + return 0; } /* ??? Should this also swap msgh->name? */ @@ -941,35 +969,56 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, return ret; } -static void lock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) +/* 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. + */ +static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, + int count, int copy) { struct target_iovec *target_vec; abi_ulong base; - int i; + int i, j; - target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); + if (!target_vec) + return -TARGET_EFAULT; for(i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); vec[i].iov_len = tswapl(target_vec[i].iov_len); - vec[i].iov_base = lock_user(base, vec[i].iov_len, copy); + vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); + if (!vec[i].iov_base) + goto fail; } unlock_user (target_vec, target_addr, 0); + return 0; + fail: + /* failure - unwind locks */ + for (j = 0; j < i; j++) { + base = tswapl(target_vec[j].iov_base); + unlock_user(vec[j].iov_base, base, 0); + } + unlock_user (target_vec, target_addr, 0); + return -TARGET_EFAULT; } -static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) +static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, + int count, int copy) { struct target_iovec *target_vec; abi_ulong base; int i; - target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); + if (!target_vec) + return -TARGET_EFAULT; for(i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); } unlock_user (target_vec, target_addr, 0); + + return 0; } /* do_socket() Must return target values and target errnos. */ @@ -1033,7 +1082,12 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, struct iovec *vec; abi_ulong target_vec; - lock_user_struct(msgp, target_msg, 1); + /* FIXME */ + if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, + msgp, + target_msg, + send ? 1 : 0)) + return -TARGET_EFAULT; if (msgp->msg_name) { msg.msg_namelen = tswap32(msgp->msg_namelen); msg.msg_name = alloca(msg.msg_namelen); @@ -1050,7 +1104,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, count = tswapl(msgp->msg_iovlen); vec = alloca(count * sizeof(struct iovec)); target_vec = tswapl(msgp->msg_iov); - lock_iovec(vec, target_vec, count, send); + lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send); msg.msg_iovlen = count; msg.msg_iov = vec; @@ -1063,6 +1117,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, host_to_target_cmsg(msgp, &msg); } unlock_iovec(vec, target_vec, count, !send); + unlock_user_struct(msgp, target_msg, send ? 0 : 1); return ret; } @@ -1137,7 +1192,9 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, void *host_msg; abi_long ret; - host_msg = lock_user(msg, len, 1); + host_msg = lock_user(VERIFY_READ, msg, len, 1); + if (!host_msg) + return -TARGET_EFAULT; if (target_addr) { addr = alloca(addrlen); target_to_host_sockaddr(addr, target_addr, addrlen); @@ -1159,7 +1216,9 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, void *host_msg; abi_long ret; - host_msg = lock_user(msg, len, 0); + host_msg = lock_user(VERIFY_WRITE, msg, len, 0); + if (!host_msg) + return -TARGET_EFAULT; if (target_addr) { addrlen = tget32(target_addrlen); addr = alloca(addrlen); @@ -1381,13 +1440,14 @@ struct target_semid_ds abi_ulong __unused4; }; -static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, - abi_ulong target_addr) +static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, + abi_ulong target_addr) { struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return -TARGET_EFAULT; target_ip=&(target_sd->sem_perm); host_ip->__key = tswapl(target_ip->__key); host_ip->uid = tswapl(target_ip->uid); @@ -1396,15 +1456,17 @@ static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, host_ip->cgid = tswapl(target_ip->cgid); host_ip->mode = tswapl(target_ip->mode); unlock_user_struct(target_sd, target_addr, 0); + return 0; } -static inline void host_to_target_ipc_perm(abi_ulong target_addr, - struct ipc_perm *host_ip) +static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr, + struct ipc_perm *host_ip) { struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return -TARGET_EFAULT; target_ip = &(target_sd->sem_perm); target_ip->__key = tswapl(host_ip->__key); target_ip->uid = tswapl(host_ip->uid); @@ -1413,32 +1475,37 @@ static inline void host_to_target_ipc_perm(abi_ulong target_addr, target_ip->cgid = tswapl(host_ip->cgid); target_ip->mode = tswapl(host_ip->mode); unlock_user_struct(target_sd, target_addr, 1); + return 0; } -static inline void target_to_host_semid_ds(struct semid_ds *host_sd, - abi_ulong target_addr) +static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, + abi_ulong target_addr) { struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr); host_sd->sem_nsems = tswapl(target_sd->sem_nsems); host_sd->sem_otime = tswapl(target_sd->sem_otime); host_sd->sem_ctime = tswapl(target_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 0); + return 0; } -static inline void host_to_target_semid_ds(abi_ulong target_addr, - struct semid_ds *host_sd) +static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, + struct semid_ds *host_sd) { struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)); target_sd->sem_nsems = tswapl(host_sd->sem_nsems); target_sd->sem_otime = tswapl(host_sd->sem_otime); target_sd->sem_ctime = tswapl(host_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 1); + return 0; } union semun { @@ -1453,67 +1520,75 @@ union target_semun { unsigned short int *array; }; -static inline void target_to_host_semun(int cmd, - union semun *host_su, - abi_ulong target_addr, - struct semid_ds *ds) +static inline abi_long target_to_host_semun(int cmd, + union semun *host_su, + abi_ulong target_addr, + struct semid_ds *ds) { union target_semun *target_su; switch( cmd ) { case IPC_STAT: case IPC_SET: - lock_user_struct(target_su, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_semid_ds(ds,target_su->buf); host_su->buf = ds; unlock_user_struct(target_su, target_addr, 0); break; case GETVAL: case SETVAL: - lock_user_struct(target_su, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; host_su->val = tswapl(target_su->val); unlock_user_struct(target_su, target_addr, 0); break; case GETALL: case SETALL: - lock_user_struct(target_su, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; *host_su->array = tswap16(*target_su->array); unlock_user_struct(target_su, target_addr, 0); break; default: gemu_log("semun operation not fully supported: %d\n", (int)cmd); } + return 0; } -static inline void host_to_target_semun(int cmd, - abi_ulong target_addr, - union semun *host_su, - struct semid_ds *ds) +static inline abi_long host_to_target_semun(int cmd, + abi_ulong target_addr, + union semun *host_su, + struct semid_ds *ds) { union target_semun *target_su; switch( cmd ) { case IPC_STAT: case IPC_SET: - lock_user_struct(target_su, target_addr, 0); + if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_semid_ds(target_su->buf,ds); unlock_user_struct(target_su, target_addr, 1); break; case GETVAL: case SETVAL: - lock_user_struct(target_su, target_addr, 0); + if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; target_su->val = tswapl(host_su->val); unlock_user_struct(target_su, target_addr, 1); break; case GETALL: case SETALL: - lock_user_struct(target_su, target_addr, 0); + if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; *target_su->array = tswap16(*host_su->array); unlock_user_struct(target_su, target_addr, 1); break; default: gemu_log("semun operation not fully supported: %d\n", (int)cmd); } + return 0; } static inline abi_long do_semctl(int first, int second, int third, @@ -1580,12 +1655,13 @@ struct target_msqid_ds abi_ulong __unused5; }; -static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, - abi_ulong target_addr) +static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, + abi_ulong target_addr) { struct target_msqid_ds *target_md; - lock_user_struct(target_md, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_ipc_perm(&(host_md->msg_perm),target_addr); host_md->msg_stime = tswapl(target_md->msg_stime); host_md->msg_rtime = tswapl(target_md->msg_rtime); @@ -1596,14 +1672,16 @@ static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, host_md->msg_lspid = tswapl(target_md->msg_lspid); host_md->msg_lrpid = tswapl(target_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 0); + return 0; } -static inline void host_to_target_msqid_ds(abi_ulong target_addr, - struct msqid_ds *host_md) +static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr, + struct msqid_ds *host_md) { struct target_msqid_ds *target_md; - lock_user_struct(target_md, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)); target_md->msg_stime = tswapl(host_md->msg_stime); target_md->msg_rtime = tswapl(host_md->msg_rtime); @@ -1614,6 +1692,7 @@ static inline void host_to_target_msqid_ds(abi_ulong target_addr, target_md->msg_lspid = tswapl(host_md->msg_lspid); target_md->msg_lrpid = tswapl(host_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 1); + return 0; } static inline abi_long do_msgctl(int first, int second, abi_long ptr) @@ -1645,7 +1724,8 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, struct msgbuf *host_mb; abi_long ret = 0; - lock_user_struct(target_mb,msgp,0); + if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) + return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); host_mb->mtype = tswapl(target_mb->mtype); memcpy(host_mb->mtext,target_mb->mtext,msgsz); @@ -1661,18 +1741,30 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, int msgflg) { struct target_msgbuf *target_mb; + char *target_mtext; struct msgbuf *host_mb; abi_long ret = 0; - lock_user_struct(target_mb, msgp, 0); + if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) + return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg)); - if (ret > 0) + if (ret > 0) { + abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); + target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0); + if (!target_mtext) { + ret = -TARGET_EFAULT; + goto end; + } memcpy(target_mb->mtext, host_mb->mtext, ret); + unlock_user(target_mtext, target_mtext_addr, ret); + } target_mb->mtype = tswapl(host_mb->mtype); free(host_mb); - unlock_user_struct(target_mb, msgp, 0); +end: + if (target_mb) + unlock_user_struct(target_mb, msgp, 1); return ret; } @@ -1693,7 +1785,7 @@ static abi_long do_ipc(unsigned int call, int first, switch (call) { case IPCOP_semop: - ret = get_errno(semop(first,(struct sembuf *) ptr, second)); + ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second)); break; case IPCOP_semget: @@ -1723,13 +1815,14 @@ static abi_long do_ipc(unsigned int call, int first, case IPCOP_msgrcv: { + /* XXX: this code is not correct */ struct ipc_kludge { void *__unbounded msgp; long int msgtyp; }; - struct ipc_kludge *foo = (struct ipc_kludge *) ptr; + struct ipc_kludge *foo = (struct ipc_kludge *)g2h(ptr); struct msgbuf *msgp = (struct msgbuf *) foo->msgp; ret = do_msgrcv(first, (long)msgp, second, 0, third); @@ -1761,7 +1854,7 @@ static abi_long do_ipc(unsigned int call, int first, break; } } - if (put_user(raddr, (abi_ulong *)third)) + if (put_user(raddr, third, abi_ulong)) return -TARGET_EFAULT; ret = 0; break; @@ -1883,25 +1976,33 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) case IOC_R: ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { - argptr = lock_user(arg, target_size, 0); + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } break; case IOC_W: - argptr = lock_user(arg, target_size, 1); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); break; default: case IOC_RW: - argptr = lock_user(arg, target_size, 1); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { - argptr = lock_user(arg, target_size, 0); + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } @@ -2138,8 +2239,10 @@ static int read_ldt(abi_ulong ptr, unsigned long bytecount) size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; - p = lock_user(ptr, size, 0); - /* ??? Shoudl this by byteswapped? */ + p = lock_user(VERIFY_WRITE, ptr, size, 0); + if (!p) + return -EFAULT; + /* ??? Should this by byteswapped? */ memcpy(p, ldt_table, size); unlock_user(p, ptr, size); return size; @@ -2158,7 +2261,8 @@ static int write_ldt(CPUX86State *env, if (bytecount != sizeof(ldt_info)) return -EINVAL; - lock_user_struct(target_ldt_info, ptr, 1); + if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1)) + return -EFAULT; ldt_info.entry_number = tswap32(target_ldt_info->entry_number); ldt_info.base_addr = tswapl(target_ldt_info->base_addr); ldt_info.limit = tswap32(target_ldt_info->limit); @@ -2365,7 +2469,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) switch(cmd) { case TARGET_F_GETLK: - lock_user_struct(target_fl, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) + return -TARGET_EFAULT; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -2374,7 +2479,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) unlock_user_struct(target_fl, arg, 0); ret = fcntl(fd, cmd, &fl); if (ret == 0) { - lock_user_struct(target_fl, arg, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0)) + return -TARGET_EFAULT; target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswapl(fl.l_start); @@ -2386,7 +2492,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) case TARGET_F_SETLK: case TARGET_F_SETLKW: - lock_user_struct(target_fl, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) + return -TARGET_EFAULT; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -2397,7 +2504,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) break; case TARGET_F_GETLK64: - lock_user_struct(target_fl64, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) + return -TARGET_EFAULT; fl64.l_type = tswap16(target_fl64->l_type) >> 1; fl64.l_whence = tswap16(target_fl64->l_whence); fl64.l_start = tswapl(target_fl64->l_start); @@ -2406,7 +2514,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) unlock_user_struct(target_fl64, arg, 0); ret = fcntl(fd, cmd >> 1, &fl64); if (ret == 0) { - lock_user_struct(target_fl64, arg, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0)) + return -TARGET_EFAULT; target_fl64->l_type = tswap16(fl64.l_type) >> 1; target_fl64->l_whence = tswap16(fl64.l_whence); target_fl64->l_start = tswapl(fl64.l_start); @@ -2417,14 +2526,15 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) break; case TARGET_F_SETLK64: case TARGET_F_SETLKW64: - lock_user_struct(target_fl64, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) + return -TARGET_EFAULT; fl64.l_type = tswap16(target_fl64->l_type) >> 1; fl64.l_whence = tswap16(target_fl64->l_whence); fl64.l_start = tswapl(target_fl64->l_start); fl64.l_len = tswapl(target_fl64->l_len); fl64.l_pid = tswap16(target_fl64->l_pid); unlock_user_struct(target_fl64, arg, 0); - ret = fcntl(fd, cmd >> 1, &fl64); + ret = fcntl(fd, cmd >> 1, &fl64); break; case F_GETFL: @@ -2577,23 +2687,25 @@ static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, } #endif -static inline void target_to_host_timespec(struct timespec *host_ts, - abi_ulong target_addr) +static inline abi_long target_to_host_timespec(struct timespec *host_ts, + abi_ulong target_addr) { struct target_timespec *target_ts; - lock_user_struct(target_ts, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) + return -TARGET_EFAULT; host_ts->tv_sec = tswapl(target_ts->tv_sec); host_ts->tv_nsec = tswapl(target_ts->tv_nsec); unlock_user_struct(target_ts, target_addr, 0); } -static inline void host_to_target_timespec(abi_ulong target_addr, - struct timespec *host_ts) +static inline abi_long host_to_target_timespec(abi_ulong target_addr, + struct timespec *host_ts) { struct target_timespec *target_ts; - lock_user_struct(target_ts, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) + return -TARGET_EFAULT; target_ts->tv_sec = tswapl(host_ts->tv_sec); target_ts->tv_nsec = tswapl(host_ts->tv_nsec); unlock_user_struct(target_ts, target_addr, 1); @@ -2629,17 +2741,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NR_read: page_unprotect_range(arg2, arg3); - p = lock_user(arg2, arg3, 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; ret = get_errno(read(arg1, p, arg3)); unlock_user(p, arg2, ret); break; case TARGET_NR_write: - p = lock_user(arg2, arg3, 1); + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; ret = get_errno(write(arg1, p, arg3)); unlock_user(p, arg2, 0); break; case TARGET_NR_open: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) { + return -TARGET_EFAULT; + goto fail; + } ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3)); @@ -2647,21 +2764,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_openat) && defined(__NR_openat) case TARGET_NR_openat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_openat(arg1, - path(p), - target_to_host_bitmask(arg3, fcntl_flags_tbl), - arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_openat(arg1, + path(p), + target_to_host_bitmask(arg3, fcntl_flags_tbl), + arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_close: @@ -2685,7 +2794,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_creat /* not on alpha */ case TARGET_NR_creat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(creat(p, arg2)); unlock_user(p, arg1, 0); break; @@ -2695,54 +2805,43 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void * p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(link(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(link(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_linkat) && defined(__NR_linkat) case TARGET_NR_linkat: - if (!arg2 || !arg4) { - ret = -TARGET_EFAULT; - goto fail; - } { void * p2 = NULL; + if (!arg2 || !arg4) + goto efault; p = lock_user_string(arg2); p2 = lock_user_string(arg4); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5)); - if (p2) - unlock_user(p, arg2, 0); - if (p) - unlock_user(p2, arg4, 0); + unlock_user(p, arg2, 0); + unlock_user(p2, arg4, 0); } break; #endif case TARGET_NR_unlink: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(unlink(p)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) case TARGET_NR_unlinkat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_unlinkat(arg1, p, arg3)); - if (p) - unlock_user(p, arg2, 0); - break; + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_unlinkat(arg1, p, arg3)); + unlock_user(p, arg2, 0); #endif case TARGET_NR_execve: { @@ -2771,7 +2870,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, addr = tgetl(gp); if (!addr) break; - *q = lock_user_string(addr); + if (!(*q = lock_user_string(addr))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } } *q = NULL; @@ -2780,14 +2882,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, addr = tgetl(gp); if (!addr) break; - *q = lock_user_string(addr); + if (!(*q = lock_user_string(addr))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } } *q = NULL; - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } ret = get_errno(execve(p, argp, envp)); unlock_user(p, arg1, 0); + execve_fail: for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { addr = tgetl(gp); @@ -2801,7 +2910,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; case TARGET_NR_chdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chdir(p)); unlock_user(p, arg1, 0); break; @@ -2816,28 +2926,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_mknod: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(mknod(p, arg2, arg3)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) case TARGET_NR_mknodat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_chmod: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chmod(p, arg2)); unlock_user(p, arg1, 0); break; @@ -2866,15 +2970,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, p = lock_user_string(arg1); p2 = lock_user_string(arg2); p3 = lock_user_string(arg3); - ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, (const void *)arg5)); - unlock_user(p, arg1, 0); - unlock_user(p2, arg2, 0); - unlock_user(p3, arg3, 0); + if (!p || !p2 || !p3) + ret = -TARGET_EFAULT; + else + /* FIXME - arg5 should be locked, but it isn't clear how to + * do that since it's not guaranteed to be a NULL-terminated + * string. + */ + ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5))); + unlock_user(p, arg1, 0); + unlock_user(p2, arg2, 0); + unlock_user(p3, arg3, 0); break; } #ifdef TARGET_NR_umount case TARGET_NR_umount: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(umount(p)); unlock_user(p, arg1, 0); break; @@ -2910,7 +3022,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct utimbuf tbuf, *host_tbuf; struct target_utimbuf *target_tbuf; if (arg2) { - lock_user_struct(target_tbuf, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1)) + goto efault; tbuf.actime = tswapl(target_tbuf->actime); tbuf.modtime = tswapl(target_tbuf->modtime); unlock_user_struct(target_tbuf, arg2, 0); @@ -2918,7 +3031,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else { host_tbuf = NULL; } - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(utime(p, host_tbuf)); unlock_user(p, arg1, 0); } @@ -2935,7 +3049,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else { tvp = NULL; } - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(utimes(p, tvp)); unlock_user(p, arg1, 0); } @@ -2949,24 +3064,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_access: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(access(p, arg2)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) case TARGET_NR_faccessat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif #ifdef TARGET_NR_nice /* not on alpha */ @@ -2990,57 +3098,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(rename(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(rename(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_renameat) && defined(__NR_renameat) case TARGET_NR_renameat: - if (!arg2 || !arg4) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg2); p2 = lock_user_string(arg4); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_renameat(arg1, p, arg3, p2)); - if (p2) - unlock_user(p2, arg4, 0); - if (p) - unlock_user(p, arg2, 0); + unlock_user(p2, arg4, 0); + unlock_user(p, arg2, 0); } break; #endif case TARGET_NR_mkdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(mkdir(p, arg2)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) case TARGET_NR_mkdirat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_mkdirat(arg1, p, arg3)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_mkdirat(arg1, p, arg3)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_rmdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(rmdir(p)); unlock_user(p, arg1, 0); break; @@ -3069,7 +3166,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct tms tms; ret = get_errno(times(&tms)); if (arg1) { - tmsp = lock_user(arg1, sizeof(struct target_tms), 0); + tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0); + if (!tmsp) + goto efault; tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime)); tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime)); tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime)); @@ -3088,13 +3187,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_acct: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(acct(path(p))); unlock_user(p, arg1, 0); break; #ifdef TARGET_NR_umount2 /* not on alpha */ case TARGET_NR_umount2: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(umount2(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3128,7 +3229,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(umask(arg1)); break; case TARGET_NR_chroot: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chroot(p)); unlock_user(p, arg1, 0); break; @@ -3155,7 +3257,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; if (arg2) { - lock_user_struct(old_act, arg2, 1); + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) + goto efault; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask); act.sa_flags = old_act->sa_flags; @@ -3167,7 +3270,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { - lock_user_struct(old_act, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) + goto efault; old_act->_sa_handler = oact._sa_handler; old_act->sa_mask = oact.sa_mask.sig[0]; old_act->sa_flags = oact.sa_flags; @@ -3178,7 +3282,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_sigaction act, oact, *pact, *old_act; if (arg2) { - lock_user_struct(old_act, arg2, 1); + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) + goto efault; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]); act.sa_flags = old_act->sa_flags; @@ -3191,7 +3296,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { - lock_user_struct(old_act, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) + goto efault; old_act->_sa_handler = oact._sa_handler; old_act->sa_flags = oact.sa_flags; old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; @@ -3209,18 +3315,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_sigaction *act; struct target_sigaction *oact; - if (arg2) - lock_user_struct(act, arg2, 1); - else + if (arg2) { + if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) + goto efault; + } else act = NULL; - if (arg3) - lock_user_struct(oact, arg3, 0); - else + if (arg3) { + if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) { + ret = -TARGET_EFAULT; + goto rt_sigaction_fail; + } + } else oact = NULL; ret = get_errno(do_sigaction(arg1, act, oact)); - if (arg2) + rt_sigaction_fail: + if (act) unlock_user_struct(act, arg2, 0); - if (arg3) + if (oact) unlock_user_struct(oact, arg3, 1); } break; @@ -3270,7 +3381,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_EINVAL; goto fail; } - p = lock_user(arg2, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_old_sigset(&set, p); unlock_user(p, arg2, 0); set_ptr = &set; @@ -3280,7 +3392,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); if (!is_error(ret) && arg3) { - p = lock_user(arg3, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_old_sigset(p, &oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } @@ -3307,7 +3420,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_EINVAL; goto fail; } - p = lock_user(arg2, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg2, 0); set_ptr = &set; @@ -3317,7 +3431,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigprocmask(how, set_ptr, &oldset)); if (!is_error(ret) && arg3) { - p = lock_user(arg3, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_sigset(p, &oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } @@ -3329,7 +3444,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - p = lock_user(arg1, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_old_sigset(p, &set); unlock_user(p, arg1, sizeof(target_sigset_t)); } @@ -3341,7 +3457,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - p = lock_user(arg1, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_sigset(p, &set); unlock_user(p, arg1, sizeof(target_sigset_t)); } @@ -3351,7 +3468,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sigsuspend: { sigset_t set; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_old_sigset(&set, p); unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); @@ -3361,7 +3479,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigsuspend: { sigset_t set; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); @@ -3373,7 +3492,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct timespec uts, *puts; siginfo_t uinfo; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); if (arg3) { @@ -3384,7 +3504,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigtimedwait(&set, &uinfo, puts)); if (!is_error(ret) && arg2) { - p = lock_user(arg2, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_siginfo(p, &uinfo); unlock_user(p, arg2, sizeof(target_sigset_t)); } @@ -3393,7 +3514,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigqueueinfo: { siginfo_t uinfo; - p = lock_user(arg3, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_siginfo(&uinfo, p); unlock_user(p, arg1, 0); ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); @@ -3410,7 +3532,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_rt_sigreturn(cpu_env); break; case TARGET_NR_sethostname: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(sethostname(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3420,7 +3543,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int resource = arg1; struct target_rlimit *target_rlim; struct rlimit rlim; - lock_user_struct(target_rlim, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) + goto efault; rlim.rlim_cur = tswapl(target_rlim->rlim_cur); rlim.rlim_max = tswapl(target_rlim->rlim_max); unlock_user_struct(target_rlim, arg2, 0); @@ -3436,7 +3560,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(getrlimit(resource, &rlim)); if (!is_error(ret)) { - lock_user_struct(target_rlim, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) + goto efault; rlim.rlim_cur = tswapl(target_rlim->rlim_cur); rlim.rlim_max = tswapl(target_rlim->rlim_max); unlock_user_struct(target_rlim, arg2, 1); @@ -3475,7 +3600,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_ulong inp, outp, exp, tvp; long nsel; - lock_user_struct(sel, arg1, 1); + if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) + goto efault; nsel = tswapl(sel->n); inp = tswapl(sel->inp); outp = tswapl(sel->outp); @@ -3491,31 +3617,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(symlink(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(symlink(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) case TARGET_NR_symlinkat: - if (!arg1 || !arg3) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg3); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_symlinkat(p, arg2, p2)); - if (p2) - unlock_user(p2, arg3, 0); - if (p) - unlock_user(p, arg1, 0); + unlock_user(p2, arg3, 0); + unlock_user(p, arg1, 0); } break; #endif @@ -3527,32 +3648,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { void *p2; p = lock_user_string(arg1); - p2 = lock_user(arg2, arg3, 0); - ret = get_errno(readlink(path(p), p2, arg3)); + p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(readlink(path(p), p2, arg3)); unlock_user(p2, arg2, ret); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) case TARGET_NR_readlinkat: - if (!arg2 || !arg3) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg2); - p2 = lock_user(arg3, arg4, 0); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4)); - if (p2) - unlock_user(p2, arg3, ret); - if (p) - unlock_user(p, arg2, 0); + unlock_user(p2, arg3, ret); + unlock_user(p, arg2, 0); } break; #endif @@ -3562,7 +3678,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_swapon case TARGET_NR_swapon: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(swapon(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3579,7 +3696,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { abi_ulong *v; abi_ulong v1, v2, v3, v4, v5, v6; - v = lock_user(arg1, 6 * sizeof(abi_ulong), 1); + if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1))) + goto efault; v1 = tswapl(v[0]); v2 = tswapl(v[1]); v3 = tswapl(v[2]); @@ -3650,7 +3768,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_truncate: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(truncate(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3662,18 +3781,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) case TARGET_NR_fchmodat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_getpriority: @@ -3690,25 +3801,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_statfs: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(statfs(path(p), &stfs)); unlock_user(p, arg1, 0); convert_statfs: if (!is_error(ret)) { struct target_statfs *target_stfs; - lock_user_struct(target_stfs, arg2, 0); - /* ??? put_user is probably wrong. */ - put_user(stfs.f_type, &target_stfs->f_type); - put_user(stfs.f_bsize, &target_stfs->f_bsize); - put_user(stfs.f_blocks, &target_stfs->f_blocks); - put_user(stfs.f_bfree, &target_stfs->f_bfree); - put_user(stfs.f_bavail, &target_stfs->f_bavail); - put_user(stfs.f_files, &target_stfs->f_files); - put_user(stfs.f_ffree, &target_stfs->f_ffree); - put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); - put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); - put_user(stfs.f_namelen, &target_stfs->f_namelen); + if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0)) + goto efault; + __put_user(stfs.f_type, &target_stfs->f_type); + __put_user(stfs.f_bsize, &target_stfs->f_bsize); + __put_user(stfs.f_blocks, &target_stfs->f_blocks); + __put_user(stfs.f_bfree, &target_stfs->f_bfree); + __put_user(stfs.f_bavail, &target_stfs->f_bavail); + __put_user(stfs.f_files, &target_stfs->f_files); + __put_user(stfs.f_ffree, &target_stfs->f_ffree); + __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); + __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); + __put_user(stfs.f_namelen, &target_stfs->f_namelen); unlock_user_struct(target_stfs, arg2, 1); } break; @@ -3717,26 +3829,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto convert_statfs; #ifdef TARGET_NR_statfs64 case TARGET_NR_statfs64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(statfs(path(p), &stfs)); unlock_user(p, arg1, 0); convert_statfs64: if (!is_error(ret)) { struct target_statfs64 *target_stfs; - lock_user_struct(target_stfs, arg3, 0); - /* ??? put_user is probably wrong. */ - put_user(stfs.f_type, &target_stfs->f_type); - put_user(stfs.f_bsize, &target_stfs->f_bsize); - put_user(stfs.f_blocks, &target_stfs->f_blocks); - put_user(stfs.f_bfree, &target_stfs->f_bfree); - put_user(stfs.f_bavail, &target_stfs->f_bavail); - put_user(stfs.f_files, &target_stfs->f_files); - put_user(stfs.f_ffree, &target_stfs->f_ffree); - put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); - put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); - put_user(stfs.f_namelen, &target_stfs->f_namelen); - unlock_user_struct(target_stfs, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0)) + goto efault; + __put_user(stfs.f_type, &target_stfs->f_type); + __put_user(stfs.f_bsize, &target_stfs->f_bsize); + __put_user(stfs.f_blocks, &target_stfs->f_blocks); + __put_user(stfs.f_bfree, &target_stfs->f_bfree); + __put_user(stfs.f_bavail, &target_stfs->f_bavail); + __put_user(stfs.f_files, &target_stfs->f_files); + __put_user(stfs.f_ffree, &target_stfs->f_ffree); + __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); + __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); + __put_user(stfs.f_namelen, &target_stfs->f_namelen); + unlock_user_struct(target_stfs, arg3, 1); } break; case TARGET_NR_fstatfs64: @@ -3839,7 +3952,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif case TARGET_NR_syslog: - p = lock_user_string(arg2); + if (!(p = lock_user_string(arg2))) + goto efault; ret = get_errno(sys_syslog((int)arg1, p, (int)arg3)); unlock_user(p, arg2, 0); break; @@ -3880,12 +3994,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; case TARGET_NR_stat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(stat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat; case TARGET_NR_lstat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lstat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat; @@ -3896,7 +4012,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { struct target_stat *target_st; - lock_user_struct(target_st, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; #if defined(TARGET_MIPS) || (defined(TARGET_SPARC64) && !defined(TARGET_ABI32)) target_st->st_dev = tswap32(st.st_dev); #else @@ -3979,7 +4096,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_NR_swapoff case TARGET_NR_swapoff: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(swapoff(p)); unlock_user(p, arg1, 0); break; @@ -3991,8 +4109,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(sysinfo(&value)); if (!is_error(ret) && arg1) { - /* ??? __put_user is probably wrong. */ - lock_user_struct(target_value, arg1, 0); + if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0)) + goto efault; __put_user(value.uptime, &target_value->uptime); __put_user(value.loads[0], &target_value->loads[0]); __put_user(value.loads[1], &target_value->loads[1]); @@ -4030,7 +4148,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_setdomainname: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(setdomainname(p, arg2)); unlock_user(p, arg1, 0); break; @@ -4039,7 +4158,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct new_utsname * buf; - lock_user_struct(buf, arg1, 0); + if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0)) + goto efault; ret = get_errno(sys_uname(buf)); if (!is_error(ret)) { /* Overrite the native machine name with whatever is being @@ -4124,7 +4244,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, dirp = malloc(count); if (!dirp) { - ret = -TARGET_EFAULT; + ret = -TARGET_ENOMEM; goto fail; } @@ -4138,7 +4258,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, count1 = 0; de = dirp; - target_dirp = lock_user(arg2, count, 0); + if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; tde = target_dirp; while (len > 0) { reclen = de->d_reclen; @@ -4157,8 +4278,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, count1 += treclen; } ret = count1; + unlock_user(target_dirp, arg2, ret); } - unlock_user(target_dirp, arg2, ret); free(dirp); } #else @@ -4166,7 +4287,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct dirent *dirp; abi_long count = arg3; - dirp = lock_user(arg2, count, 0); + if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { struct dirent *de; @@ -4193,7 +4315,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct dirent64 *dirp; abi_long count = arg3; - dirp = lock_user(arg2, count, 0); + if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; ret = get_errno(sys_getdents64(arg1, dirp, count)); if (!is_error(ret)) { struct dirent64 *de; @@ -4229,7 +4352,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct pollfd *pfd; unsigned int i; - target_pfd = lock_user(arg1, sizeof(struct target_pollfd) * nfds, 1); + target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1); + if (!target_pfd) + goto efault; pfd = alloca(sizeof(struct pollfd) * nfds); for(i = 0; i < nfds; i++) { pfd[i].fd = tswap32(target_pfd[i].fd); @@ -4258,7 +4383,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); - lock_iovec(vec, arg2, count, 0); + lock_iovec(VERIFY_WRITE, vec, arg2, count, 0); ret = get_errno(readv(arg1, vec, count)); unlock_iovec(vec, arg2, count, 1); } @@ -4269,7 +4394,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); - lock_iovec(vec, arg2, count, 1); + lock_iovec(VERIFY_READ, vec, arg2, count, 1); ret = get_errno(writev(arg1, vec, count)); unlock_iovec(vec, arg2, count, 0); } @@ -4292,7 +4417,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct sched_param *target_schp; struct sched_param schp; - lock_user_struct(target_schp, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1)) + goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); unlock_user_struct(target_schp, arg2, 0); ret = get_errno(sched_setparam(arg1, &schp)); @@ -4304,7 +4430,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct sched_param schp; ret = get_errno(sched_getparam(arg1, &schp)); if (!is_error(ret)) { - lock_user_struct(target_schp, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0)) + goto efault; target_schp->sched_priority = tswap32(schp.sched_priority); unlock_user_struct(target_schp, arg2, 1); } @@ -4314,7 +4441,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct sched_param *target_schp; struct sched_param schp; - lock_user_struct(target_schp, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1)) + goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); unlock_user_struct(target_schp, arg3, 0); ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); @@ -4378,18 +4506,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_pread case TARGET_NR_pread: page_unprotect_range(arg2, arg3); - p = lock_user(arg2, arg3, 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; ret = get_errno(pread(arg1, p, arg3, arg4)); unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite: - p = lock_user(arg2, arg3, 1); + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; ret = get_errno(pwrite(arg1, p, arg3, arg4)); unlock_user(p, arg2, 0); break; #endif case TARGET_NR_getcwd: - p = lock_user(arg1, arg2, 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0))) + goto efault; ret = get_errno(sys_getcwd1(p, arg2)); unlock_user(p, arg1, ret); break; @@ -4400,9 +4531,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sigaltstack: #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \ defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) - ret = do_sigaltstack((struct target_sigaltstack *)arg1, - (struct target_sigaltstack *)arg2, - get_sp_from_cpustate((CPUState *)cpu_env)); + ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env)); break; #else goto unimplemented; @@ -4429,7 +4558,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(getrlimit(arg1, &rlim)); if (!is_error(ret)) { struct target_rlimit *target_rlim; - lock_user_struct(target_rlim, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) + goto efault; target_rlim->rlim_cur = tswapl(rlim.rlim_cur); target_rlim->rlim_max = tswapl(rlim.rlim_max); unlock_user_struct(target_rlim, arg2, 1); @@ -4439,7 +4569,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_truncate64 case TARGET_NR_truncate64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = target_truncate64(cpu_env, p, arg2, arg3, arg4); unlock_user(p, arg1, 0); break; @@ -4451,14 +4582,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_stat64 case TARGET_NR_stat64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(stat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat64; #endif #ifdef TARGET_NR_lstat64 case TARGET_NR_lstat64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lstat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat64; @@ -4472,52 +4605,53 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { struct target_eabi_stat64 *target_st; - lock_user_struct(target_st, arg2, 1); + + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; memset(target_st, 0, sizeof(struct target_eabi_stat64)); - /* put_user is probably wrong. */ - put_user(st.st_dev, &target_st->st_dev); - put_user(st.st_ino, &target_st->st_ino); + __put_user(st.st_dev, &target_st->st_dev); + __put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - put_user(st.st_ino, &target_st->__st_ino); + __put_user(st.st_ino, &target_st->__st_ino); #endif - put_user(st.st_mode, &target_st->st_mode); - put_user(st.st_nlink, &target_st->st_nlink); - put_user(st.st_uid, &target_st->st_uid); - put_user(st.st_gid, &target_st->st_gid); - put_user(st.st_rdev, &target_st->st_rdev); - /* XXX: better use of kernel struct */ - put_user(st.st_size, &target_st->st_size); - put_user(st.st_blksize, &target_st->st_blksize); - put_user(st.st_blocks, &target_st->st_blocks); - put_user(st.st_atime, &target_st->target_st_atime); - put_user(st.st_mtime, &target_st->target_st_mtime); - put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 0); + __put_user(st.st_mode, &target_st->st_mode); + __put_user(st.st_nlink, &target_st->st_nlink); + __put_user(st.st_uid, &target_st->st_uid); + __put_user(st.st_gid, &target_st->st_gid); + __put_user(st.st_rdev, &target_st->st_rdev); + __put_user(st.st_size, &target_st->st_size); + __put_user(st.st_blksize, &target_st->st_blksize); + __put_user(st.st_blocks, &target_st->st_blocks); + __put_user(st.st_atime, &target_st->target_st_atime); + __put_user(st.st_mtime, &target_st->target_st_mtime); + __put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 1); } else #endif { struct target_stat64 *target_st; - lock_user_struct(target_st, arg2, 1); + + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; memset(target_st, 0, sizeof(struct target_stat64)); - /* ??? put_user is probably wrong. */ - put_user(st.st_dev, &target_st->st_dev); - put_user(st.st_ino, &target_st->st_ino); + __put_user(st.st_dev, &target_st->st_dev); + __put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - put_user(st.st_ino, &target_st->__st_ino); + __put_user(st.st_ino, &target_st->__st_ino); #endif - put_user(st.st_mode, &target_st->st_mode); - put_user(st.st_nlink, &target_st->st_nlink); - put_user(st.st_uid, &target_st->st_uid); - put_user(st.st_gid, &target_st->st_gid); - put_user(st.st_rdev, &target_st->st_rdev); + __put_user(st.st_mode, &target_st->st_mode); + __put_user(st.st_nlink, &target_st->st_nlink); + __put_user(st.st_uid, &target_st->st_uid); + __put_user(st.st_gid, &target_st->st_gid); + __put_user(st.st_rdev, &target_st->st_rdev); /* XXX: better use of kernel struct */ - put_user(st.st_size, &target_st->st_size); - put_user(st.st_blksize, &target_st->st_blksize); - put_user(st.st_blocks, &target_st->st_blocks); - put_user(st.st_atime, &target_st->target_st_atime); - put_user(st.st_mtime, &target_st->target_st_mtime); - put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 0); + __put_user(st.st_size, &target_st->st_size); + __put_user(st.st_blksize, &target_st->st_blksize); + __put_user(st.st_blocks, &target_st->st_blocks); + __put_user(st.st_atime, &target_st->target_st_atime); + __put_user(st.st_mtime, &target_st->target_st_mtime); + __put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 1); } } } @@ -4525,7 +4659,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef USE_UID16 case TARGET_NR_lchown: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3))); unlock_user(p, arg1, 0); break; @@ -4557,7 +4692,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); if (!is_error(ret)) { - target_grouplist = lock_user(arg2, gidsetsize * 2, 0); + target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0); + if (!target_grouplist) + goto efault; for(i = 0;i < gidsetsize; i++) target_grouplist[i] = tswap16(grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 2); @@ -4572,7 +4709,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); - target_grouplist = lock_user(arg2, gidsetsize * 2, 1); + target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) grouplist[i] = tswap16(target_grouplist[i]); unlock_user(target_grouplist, arg2, 0); @@ -4584,18 +4725,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) case TARGET_NR_fchownat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); + unlock_user(p, arg2, 0); break; #endif #ifdef TARGET_NR_setresuid @@ -4639,7 +4772,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_chown: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3))); unlock_user(p, arg1, 0); break; @@ -4659,7 +4793,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_lchown32 case TARGET_NR_lchown32: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lchown(p, arg2, arg3)); unlock_user(p, arg1, 0); break; @@ -4705,7 +4840,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); if (!is_error(ret)) { - target_grouplist = lock_user(arg2, gidsetsize * 4, 0); + target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) target_grouplist[i] = tswap32(grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 4); @@ -4722,7 +4861,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); - target_grouplist = lock_user(arg2, gidsetsize * 4, 1); + target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) grouplist[i] = tswap32(target_grouplist[i]); unlock_user(target_grouplist, arg2, 0); @@ -4773,7 +4916,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_chown32 case TARGET_NR_chown32: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chown(p, arg2, arg3)); unlock_user(p, arg1, 0); break; @@ -4843,7 +4987,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_GETLK64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); @@ -4853,7 +5000,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); @@ -4865,7 +5015,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (ret == 0) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) { + ret = -TARGET_EFAULT; + goto fail; + } target_efl->l_type = tswap16(fl.l_type); target_efl->l_whence = tswap16(fl.l_whence); target_efl->l_start = tswap64(fl.l_start); @@ -4875,7 +5028,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) { + ret = -TARGET_EFAULT; + goto fail; + } target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswap64(fl.l_start); @@ -4890,7 +5046,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_SETLKW64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); @@ -4900,7 +5059,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); @@ -4998,8 +5160,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) case TARGET_NR_set_tid_address: - ret = get_errno(set_tid_address((int *) arg1)); - break; + ret = get_errno(set_tid_address((int *)g2h(arg1))); + break; #endif #if defined(TARGET_NR_tkill) && defined(__NR_tkill) @@ -5028,14 +5190,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!arg2) ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4)); else { - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!(p = lock_user_string(arg2))) { ret = -TARGET_EFAULT; - else - ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); - if (p) - unlock_user(p, arg2, 0); + goto fail; + } + ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); + unlock_user(p, arg2, 0); } } break; @@ -5050,11 +5210,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_ENOSYS; break; } - fail: +fail: #ifdef DEBUG gemu_log(" = %ld\n", ret); #endif if(do_strace) print_syscall_ret(num, ret); return ret; +efault: + ret = -TARGET_EFAULT; + goto fail; } diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c new file mode 100644 index 0000000000..3f838180cb --- /dev/null +++ b/linux-user/uaccess.c @@ -0,0 +1,51 @@ +/* User memory access */ +#include +#include + +#include "qemu.h" + +/* copy_from_user() and copy_to_user() are usually used to copy data + * buffers between the target and host. These internally perform + * locking/unlocking of the memory. + */ +abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len) +{ + abi_long ret = 0; + void *ghptr; + + if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) { + memcpy(hptr, ghptr, len); + unlock_user(ghptr, gaddr, 0); + } else + ret = -TARGET_EFAULT; + + return ret; +} + + +abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len) +{ + abi_long ret = 0; + void *ghptr; + + if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) { + memcpy(ghptr, hptr, len); + unlock_user(ghptr, gaddr, len); + } else + ret = -TARGET_EFAULT; + + return ret; +} + + +/* Return the length of a string in target memory. */ +/* FIXME - this doesn't check access_ok() - it's rather complicated to + * do it correctly because we need to check the bytes in a page and then + * skip to the next page and check the bytes there until we find the + * terminator. There should be a general function to do this that + * can look for any byte terminator in a buffer - not strlen(). + */ +abi_long target_strlen(abi_ulong gaddr) +{ + return strlen(g2h(gaddr)); +} diff --git a/linux-user/vm86.c b/linux-user/vm86.c index a3c92e1cc9..cb5ff9d75b 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -64,7 +64,9 @@ void save_v86_state(CPUX86State *env) TaskState *ts = env->opaque; struct target_vm86plus_struct * target_v86; - lock_user_struct(target_v86, ts->target_v86, 0); + if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0)) + /* FIXME - should return an error */ + return; /* put the VM86 registers in the userspace register structure */ target_v86->regs.eax = tswap32(env->regs[R_EAX]); target_v86->regs.ebx = tswap32(env->regs[R_EBX]); @@ -424,7 +426,8 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr) ts->vm86_saved_regs.gs = env->segs[R_GS].selector; ts->target_v86 = vm86_addr; - lock_user_struct(target_v86, vm86_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_v86, vm86_addr, 1)) + return -EFAULT; /* build vm86 CPU state */ ts->v86flags = tswap32(target_v86->regs.eflags); env->eflags = (env->eflags & ~SAFE_MASK) | diff --git a/m68k-semi.c b/m68k-semi.c index fc033a1635..b0e5269339 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -107,7 +107,9 @@ static void translate_stat(CPUState *env, target_ulong addr, struct stat *s) { struct m68k_gdb_stat *p; - p = lock_user(addr, sizeof(struct m68k_gdb_stat), 0); + if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct m68k_gdb_stat), 0))) + /* FIXME - should this return an error code? */ + return; p->gdb_st_dev = cpu_to_be32(s->st_dev); p->gdb_st_ino = cpu_to_be32(s->st_ino); p->gdb_st_mode = cpu_to_be32(s->st_mode); @@ -168,9 +170,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(2), ARG(3)); return; } else { - p = lock_user_string(ARG(0)); - result = open(p, translate_openflags(ARG(2)), ARG(3)); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user_string(ARG(0)))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = open(p, translate_openflags(ARG(2)), ARG(3)); + unlock_user(p, ARG(0), 0); + } } break; case HOSTED_CLOSE: @@ -196,9 +202,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), ARG(1), len); return; } else { - p = lock_user(ARG(1), len, 0); - result = read(ARG(0), p, len); - unlock_user(p, ARG(1), len); + if (!(p = lock_user(VERIFY_WRITE, ARG(1), len, 0))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = read(ARG(0), p, len); + unlock_user(p, ARG(1), len); + } } break; case HOSTED_WRITE: @@ -208,9 +218,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), ARG(1), len); return; } else { - p = lock_user(ARG(1), len, 1); - result = write(ARG(0), p, len); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user(VERIFY_READ, ARG(1), len, 1))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = write(ARG(0), p, len); + unlock_user(p, ARG(0), 0); + } } break; case HOSTED_LSEEK: @@ -237,7 +251,12 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) } else { p = lock_user_string(ARG(0)); q = lock_user_string(ARG(2)); - result = rename(p, q); + if (!p || !q) { + /* FIXME - check error code? */ + result = -1; + } else { + result = rename(p, q); + } unlock_user(p, ARG(0), 0); unlock_user(q, ARG(2), 0); } @@ -248,9 +267,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), (int)ARG(1)); return; } else { - p = lock_user_string(ARG(0)); - result = unlink(p); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user_string(ARG(0)))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = unlink(p); + unlock_user(p, ARG(0), 0); + } } break; case HOSTED_STAT: @@ -260,9 +283,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) return; } else { struct stat s; - p = lock_user_string(ARG(0)); - result = stat(p, &s); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user_string(ARG(0)))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = stat(p, &s); + unlock_user(p, ARG(0), 0); + } if (result == 0) { translate_stat(env, ARG(2), &s); } @@ -291,10 +318,15 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) struct gdb_timeval *p; result = qemu_gettimeofday(&tv); if (result != 0) { - p = lock_user(ARG(0), sizeof(struct gdb_timeval), 0); - p->tv_sec = cpu_to_be32(tv.tv_sec); - p->tv_usec = cpu_to_be64(tv.tv_usec); - unlock_user(p, ARG(0), sizeof(struct gdb_timeval)); + if (!(p = lock_user(VERIFY_WRITE, + ARG(0), sizeof(struct gdb_timeval), 0))) { + /* FIXME - check error code? */ + result = -1; + } else { + p->tv_sec = cpu_to_be32(tv.tv_sec); + p->tv_usec = cpu_to_be64(tv.tv_usec); + unlock_user(p, ARG(0), sizeof(struct gdb_timeval)); + } } } break; @@ -312,9 +344,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), (int)ARG(1)); return; } else { - p = lock_user_string(ARG(0)); - result = system(p); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user_string(ARG(0)))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = system(p); + unlock_user(p, ARG(0), 0); + } } break; case HOSTED_INIT_SIM: diff --git a/softmmu-semi.h b/softmmu-semi.h index 13c528bb84..527943a76f 100644 --- a/softmmu-semi.h +++ b/softmmu-semi.h @@ -41,7 +41,7 @@ static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len, cpu_memory_rw_debug(env, addr, p, len, 0); return p; } -#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy) +#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy) static char *softmmu_lock_user_string(CPUState *env, uint32_t addr) { char *p;