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
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 2d758de..14c6417 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -677,7 +677,7 @@
     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 @@
             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 86b77f9..7a76c0f 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -108,7 +108,7 @@
     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 42a02d2..684ec06 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 6fc0bbf..68ce12a 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -146,8 +146,8 @@
                           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 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 @@
 /* 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 @@
     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 @@
 
 /* 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 a0f1511..e9da097 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -435,31 +435,32 @@
 }
 
 /* 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 @@
         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 @@
 {
 	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 @@
  * 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 @@
             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 @@
         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 @@
         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 @@
 
 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 @@
 #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 @@
     /* 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 @@
 	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 @@
 	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 @@
 	/*
 	 * ATPCS B01 mandates 8-byte alignment
 	 */
-	return g2h((sp - framesize) & ~7);
+	return (sp - framesize) & ~7;
 }
 
 static int
@@ -1167,33 +1184,43 @@
 	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 @@
         __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 @@
             env->regs[2] = (abi_ulong)frame->puc;
 	}
 
+end:
+	unlock_user_struct(frame, frame_addr, 1);
+
         //	return err;
 }
 
@@ -1338,7 +1365,7 @@
 	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 @@
     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 @@
         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 @@
     }
     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 @@
     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 @@
 /*
  * 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 @@
         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 @@
     * 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 @@
 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 @@
 #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 c645ddf..315ae5c 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -81,14 +81,18 @@
 
     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 @@
     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 @@
     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 07e84d9..656f78e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -504,12 +504,13 @@
 #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 @@
     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 @@
     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 @@
             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 @@
     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 @@
     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 @@
     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 @@
             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 @@
     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 @@
     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 @@
   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 @@
     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 @@
     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 @@
 	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 @@
   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 @@
     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 @@
     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 @@
     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 @@
                                  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 @@
 
     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 @@
 
 	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 @@
                 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 @@
         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 @@
     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 @@
 
     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 @@
 
     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 @@
         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 @@
 
     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 @@
         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 @@
         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 @@
 		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 @@
 }
 #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 @@
         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 @@
         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 @@
 #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 @@
             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 @@
                 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 @@
                 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 @@
         }
         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 @@
         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 @@
 			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 @@
             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 @@
             } 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 @@
             } 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 @@
         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 @@
             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 @@
             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 @@
         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 @@
         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 @@
             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 @@
             }
             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 @@
 	    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 @@
 	    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 @@
             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 @@
                     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 @@
             }
             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 @@
                     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 @@
             }
             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 @@
             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 @@
             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 @@
     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 @@
     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 @@
             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 @@
             }
             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 @@
     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 @@
         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 @@
             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 @@
 
             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_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 @@
             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 @@
         {
             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 @@
 #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_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 @@
         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 @@
         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 @@
         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 @@
         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 @@
 #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 @@
         }
         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 @@
             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 @@
         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 @@
             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 @@
         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 @@
         {
             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 @@
 
 	    dirp = malloc(count);
 	    if (!dirp) {
-                ret = -TARGET_EFAULT;
+                ret = -TARGET_ENOMEM;
                 goto fail;
             }
 
@@ -4138,7 +4258,8 @@
 
 		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 @@
 		    count1 += treclen;
                 }
 		ret = count1;
+                unlock_user(target_dirp, arg2, ret);
             }
-            unlock_user(target_dirp, arg2, ret);
 	    free(dirp);
         }
 #else
@@ -4166,7 +4287,8 @@
             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 @@
         {
             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 @@
             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 @@
             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 @@
             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 @@
             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 @@
             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 @@
         {
             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 @@
 #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 @@
     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 @@
 	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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
             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 @@
             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 @@
         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 @@
         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 @@
 
 #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 @@
             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 @@
             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 @@
 #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 @@
         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 @@
             } 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 @@
 	    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 @@
                 } 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 @@
         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 @@
             } 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 @@
 
 #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 @@
             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 @@
         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 0000000..3f83818
--- /dev/null
+++ b/linux-user/uaccess.c
@@ -0,0 +1,51 @@
+/* User memory access */
+#include <stdio.h>
+#include <string.h>
+
+#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 a3c92e1..cb5ff9d 100644
--- a/linux-user/vm86.c
+++ b/linux-user/vm86.c
@@ -64,7 +64,9 @@
     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 @@
     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) |