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