qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] EFAULT implmentation in linux-user
@ 2007-06-04  0:47 Stuart Anderson
  0 siblings, 0 replies; only message in thread
From: Stuart Anderson @ 2007-06-04  0:47 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1588 bytes --]


The attached patch implements EFAULT detection in linux-user. It is
suprising how much software "relies" on the kernel returning EFAULT
instead of just crashing.

This patch can be broken down into 3 parts:

exec.c:
 	Add page_check_range(), which uses the page map of the target to
 	determine wether an address and range are valid.EFAULT is
 	returned when an invalid address is detected.

linux-user/qemu.h:
 	Add lock_and_check_user_struct(), wich is similar to
 	lock_user_struct(), but adds a call to page_check_range()
 	to detect bad addresses. Once all occurrances of
 	lock_user_struct() have been converted over to this new function,
 	the new function could be renamed back to lock_user_struct() to
 	shorten it slightly.

linux-user/syscall.s:
 	This is where lock_and_check_user_struct() is used. It is used
 	to perform the mapping from target to host addresses. Generally,
 	calls to lock_user_struct() have been replaced with calls to
 	lock_and_check_user_struct(). For example

-    lock_user_struct(target_tv, target_addr, 0);
+    if( (ret=lock_and_check_user_struct(&target_tv,target_addr,
 		sizeof(*target_tv),0,PAGE_WRITE)) != 0 ) return -ret;


These changes permit many of the tests in LTP for error conditions to
now pass.


                                 Stuart

Stuart R. Anderson                               anderson@netsweng.com
Network & Software Engineering                   http://www.netsweng.com/
1024D/37A79149:                                  0791 D3B8 9A4C 2CDC A31F
                                                  BD03 0A62 E534 37A7 9149

[-- Attachment #2: EFAULT implementation --]
[-- Type: TEXT/x-diff, Size: 45204 bytes --]

Index: qemu/exec.c
===================================================================
--- qemu.orig/exec.c	2007-06-03 20:36:07.000000000 -0400
+++ qemu/exec.c	2007-06-03 20:36:27.000000000 -0400
@@ -1846,6 +1846,29 @@
     spin_unlock(&tb_lock);
 }
 
+int page_check_range(target_ulong start, target_ulong len, int flags)
+{
+    PageDesc *p;
+    target_ulong end;
+    target_ulong addr;
+
+    end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
+    start = start & TARGET_PAGE_MASK;
+
+    if( end < start ) return EFAULT;  /* we've wrapped around */
+    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+        p = page_find(addr >> TARGET_PAGE_BITS);
+	if( !p ) return EFAULT;
+	if( !(p->flags & PAGE_VALID) ) return EFAULT;
+
+        if (!(p->flags & PAGE_READ) &&
+            (flags & PAGE_READ) ) return EFAULT;
+        if (!(p->flags & PAGE_WRITE) &&
+            (flags & PAGE_WRITE) ) return EFAULT;
+    }
+    return 0;
+}
+
 /* called from signal handler: invalidate the code and unprotect the
    page. Return TRUE if the fault was succesfully handled. */
 int page_unprotect(target_ulong address, unsigned long pc, void *puc)
Index: qemu/cpu-all.h
===================================================================
--- qemu.orig/cpu-all.h	2007-06-03 20:36:07.000000000 -0400
+++ qemu/cpu-all.h	2007-06-03 20:36:27.000000000 -0400
@@ -691,6 +691,7 @@
 int page_get_flags(target_ulong address);
 void page_set_flags(target_ulong start, target_ulong end, int flags);
 void page_unprotect_range(target_ulong data, target_ulong data_size);
+int page_check_range(target_ulong start, target_ulong len, int flags);
 
 #define SINGLE_CPU_DEFINES
 #ifdef SINGLE_CPU_DEFINES
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c	2007-06-03 20:36:07.000000000 -0400
+++ qemu/linux-user/syscall.c	2007-06-03 20:37:36.000000000 -0400
@@ -402,12 +402,13 @@
 #endif
 }
 
-static inline void host_to_target_rusage(target_ulong target_addr,
+static inline long host_to_target_rusage(target_ulong target_addr,
                                          const struct rusage *rusage)
 {
+    long ret = 0;
     struct target_rusage *target_rusage;
 
-    lock_user_struct(target_rusage, target_addr, 0);
+    if( (ret=lock_and_check_user_struct(&target_rusage,target_addr,sizeof(*target_rusage),0,PAGE_WRITE)) != 0 ) return -ret;
     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);
@@ -429,23 +430,25 @@
     unlock_user_struct(target_rusage, target_addr, 1);
 }
 
-static inline void target_to_host_timeval(struct timeval *tv,
+static inline long target_to_host_timeval(struct timeval *tv,
                                           target_ulong target_addr)
 {
+    long ret = 0;
     struct target_timeval *target_tv;
 
-    lock_user_struct(target_tv, target_addr, 1);
+    if( (ret=lock_and_check_user_struct(&target_tv,target_addr,sizeof(*target_tv),1,PAGE_READ)) != 0 ) return -ret;
     tv->tv_sec = tswapl(target_tv->tv_sec);
     tv->tv_usec = tswapl(target_tv->tv_usec);
     unlock_user_struct(target_tv, target_addr, 0);
 }
 
-static inline void host_to_target_timeval(target_ulong target_addr,
+static inline long host_to_target_timeval(target_ulong target_addr,
                                           const struct timeval *tv)
 {
+    long ret = 0;
     struct target_timeval *target_tv;
 
-    lock_user_struct(target_tv, target_addr, 0);
+    if( (ret=lock_and_check_user_struct(&target_tv,target_addr,sizeof(*target_tv),0,PAGE_WRITE)) != 0 ) return -ret;
     target_tv->tv_sec = tswapl(tv->tv_sec);
     target_tv->tv_usec = tswapl(tv->tv_usec);
     unlock_user_struct(target_tv, target_addr, 1);
@@ -464,21 +467,21 @@
     int ok;
 
     if (rfd_p) {
-        target_rfds = lock_user(rfd_p, sizeof(target_long) * n, 1);
+	if( (ret=lock_and_check_user_struct(&target_rfds,rfd_p,sizeof(target_long)*n,1,PAGE_READ)) != 0 ) return -ret;
         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(target_long) * n, 1);
+	if( (ret=lock_and_check_user_struct(&target_wfds,wfd_p,sizeof(target_long)*n,1,PAGE_READ)) != 0 ) return -ret;
         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(target_long) * n, 1);
+	if( (ret=lock_and_check_user_struct(&target_efds,efd_p,sizeof(target_long)*n,1,PAGE_READ)) != 0 ) return -ret;
         efds_ptr = target_to_host_fds(&efds, target_efds, n);
     } else {
         target_efds = NULL;
@@ -486,7 +489,7 @@
     }
             
     if (target_tv) {
-        target_to_host_timeval(&tv, target_tv);
+        if( (ret=target_to_host_timeval(&tv, target_tv)) != 0 ) return ret;
         tv_ptr = &tv;
     } else {
         tv_ptr = NULL;
@@ -500,7 +503,7 @@
         host_to_target_fds(target_efds, efds_ptr, n);
 
         if (target_tv) {
-            host_to_target_timeval(target_tv, &tv);
+            if( (ret=host_to_target_timeval(target_tv, &tv)) != 0 ) return ret;
         }
     }
     if (target_rfds)
@@ -513,28 +516,34 @@
     return ret;
 }
 
-static inline void target_to_host_sockaddr(struct sockaddr *addr,
+static inline long target_to_host_sockaddr(struct sockaddr *addr,
                                            target_ulong target_addr,
-                                           socklen_t len)
+                                           socklen_t len,
+                                           int pg_access)
 {
+    long ret = 0;
     struct target_sockaddr *target_saddr;
 
-    target_saddr = lock_user(target_addr, len, 1);
+    if( (ret=lock_and_check_user_struct(&target_saddr,target_addr,len,1,pg_access)) != 0 ) return -ret;
     memcpy(addr, target_saddr, len);
     addr->sa_family = tswap16(target_saddr->sa_family);
     unlock_user(target_saddr, target_addr, 0);
+    return ret;
 }
 
-static inline void host_to_target_sockaddr(target_ulong target_addr,
+static inline long host_to_target_sockaddr(target_ulong target_addr,
                                            struct sockaddr *addr,
-                                           socklen_t len)
+                                           socklen_t len,
+                                           int pg_access)
 {
+    long ret = 0;
     struct target_sockaddr *target_saddr;
 
-    target_saddr = lock_user(target_addr, len, 0);
+    if( (ret=lock_and_check_user_struct(&target_saddr,target_addr,len,1,pg_access)) != 0 ) return -ret;
     memcpy(target_saddr, addr, len);
     target_saddr->sa_family = tswap16(addr->sa_family);
     unlock_user(target_saddr, target_addr, len);
+    return ret;
 }
 
 /* ??? Should this also swap msgh->name?  */
@@ -895,18 +904,20 @@
 static long do_bind(int sockfd, target_ulong target_addr,
                     socklen_t addrlen)
 {
+    long ret = 0;
     void *addr = alloca(addrlen);
     
-    target_to_host_sockaddr(addr, target_addr, addrlen);
+    if( (ret=target_to_host_sockaddr(addr, target_addr, addrlen,PAGE_READ)) != 0 ) return -ret;
     return get_errno(bind(sockfd, addr, addrlen));
 }
 
 static long do_connect(int sockfd, target_ulong target_addr,
                     socklen_t addrlen)
 {
+    long ret = 0;
     void *addr = alloca(addrlen);
     
-    target_to_host_sockaddr(addr, target_addr, addrlen);
+    if( (ret=target_to_host_sockaddr(addr, target_addr, addrlen,PAGE_READ)) != 0 ) return -ret;
     return get_errno(connect(sockfd, addr, addrlen));
 }
 
@@ -920,12 +931,23 @@
     struct iovec *vec;
     target_ulong target_vec;
 
-    lock_user_struct(msgp, target_msg, 1);
+    if( send ) {
+       if( (ret=lock_and_check_user_struct(&msgp,target_msg,sizeof(*msgp),1,
+		PAGE_READ)) != 0  ) return -ret;
+    } else {
+       if( (ret=lock_and_check_user_struct(&msgp,target_msg,sizeof(*msgp),1,
+		PAGE_WRITE)) != 0 ) return -ret;
+    }
     if (msgp->msg_name) {
         msg.msg_namelen = tswap32(msgp->msg_namelen);
         msg.msg_name = alloca(msg.msg_namelen);
-        target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
-                                msg.msg_namelen);
+        if( send ) {
+          if( (ret=target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
+                                msg.msg_namelen,PAGE_READ)) != 0 ) return -ret;
+        } else {
+          if( (ret=target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
+                                msg.msg_namelen,PAGE_WRITE)) != 0 ) return -ret;
+	}
     } else {
         msg.msg_name = NULL;
         msg.msg_namelen = 0;
@@ -958,11 +980,12 @@
 {
     socklen_t addrlen = tget32(target_addrlen);
     void *addr = alloca(addrlen);
-    long ret;
+    long ret,ret2;
 
     ret = get_errno(accept(fd, addr, &addrlen));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if( (ret2=host_to_target_sockaddr(target_addr, addr, addrlen, PAGE_WRITE)) != 0 ) return -ret2;
+        if( (ret2=page_check_range(target_addrlen,sizeof(socklen_t),PAGE_WRITE)) != 0 ) return -ret2;
         tput32(target_addrlen, addrlen);
     }
     return ret;
@@ -971,13 +994,18 @@
 static long do_getpeername(int fd, target_ulong target_addr,
                            target_ulong target_addrlen)
 {
-    socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(addrlen);
-    long ret;
+    socklen_t addrlen;
+    void *addr;
+    long ret,ret2;
+
+    if( (ret=page_check_range(target_addrlen,sizeof(socklen_t),PAGE_READ)) != 0 ) return -ret;
+    addrlen = tget32(target_addrlen);
+    addr = alloca(addrlen);
 
     ret = get_errno(getpeername(fd, addr, &addrlen));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if( (ret2=host_to_target_sockaddr(target_addr, addr, addrlen, PAGE_WRITE)) != 0 ) return -ret2;
+        if( (ret2=page_check_range(target_addrlen,sizeof(socklen_t),PAGE_WRITE)) != 0 ) return -ret2;
         tput32(target_addrlen, addrlen);
     }
     return ret;
@@ -986,13 +1014,17 @@
 static long do_getsockname(int fd, target_ulong target_addr,
                            target_ulong target_addrlen)
 {
-    socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(addrlen);
-    long ret;
+    socklen_t addrlen;
+    void *addr;
+    long ret,ret2;
+
+    if( (ret=page_check_range(target_addrlen,sizeof(socklen_t),PAGE_WRITE)) != 0 ) return -ret;
+    addrlen = tget32(target_addrlen);
+    addr = alloca(addrlen);
 
     ret = get_errno(getsockname(fd, addr, &addrlen));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if( (ret2=host_to_target_sockaddr(target_addr, addr, addrlen, PAGE_WRITE)) ) return -ret2;
         tput32(target_addrlen, addrlen);
     }
     return ret;
@@ -1019,10 +1051,10 @@
     void *host_msg;
     long ret;
 
-    host_msg = lock_user(msg, len, 1);
+    if( (ret=lock_and_check_user_struct(&host_msg,msg,len,1,PAGE_READ)) != 0 ) return -ret;
     if (target_addr) {
         addr = alloca(addrlen);
-        target_to_host_sockaddr(addr, target_addr, addrlen);
+        if( (ret=target_to_host_sockaddr(addr, target_addr, addrlen, PAGE_READ)) != 0 ) return -ret;
         ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
     } else {
         ret = get_errno(send(fd, host_msg, len, flags));
@@ -1037,9 +1069,9 @@
     socklen_t addrlen;
     void *addr;
     void *host_msg;
-    long ret;
+    long ret,ret2;
 
-    host_msg = lock_user(msg, len, 0);
+    if( (ret2=lock_and_check_user_struct(&host_msg,msg,len,0,PAGE_WRITE)) != 0 ) return -ret2;
     if (target_addr) {
         addrlen = tget32(target_addrlen);
         addr = alloca(addrlen);
@@ -1050,7 +1082,7 @@
     }
     if (!is_error(ret)) {
         if (target_addr) {
-            host_to_target_sockaddr(target_addr, addr, addrlen);
+            if( (ret2=host_to_target_sockaddr(target_addr, addr, addrlen, PAGE_WRITE)) != 0 ) return -ret2;
             tput32(target_addrlen, addrlen);
         }
         unlock_user(host_msg, msg, len);
@@ -1257,13 +1289,15 @@
   target_ulong __unused4;
 };
 
-static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip,
-                                           target_ulong target_addr)
+static inline long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+                                           target_ulong target_addr,
+                                           int pg_access)
 {
+    long ret = 0;
     struct target_ipc_perm *target_ip;
     struct target_semid_ds *target_sd;
 
-    lock_user_struct(target_sd, target_addr, 1);
+    if( (ret=lock_and_check_user_struct(&target_sd,target_addr,sizeof(*target_sd),1,pg_access)) ) return -ret;
     target_ip=&(target_sd->sem_perm);
     host_ip->__key = tswapl(target_ip->__key);
     host_ip->uid = tswapl(target_ip->uid);
@@ -1272,15 +1306,19 @@
     host_ip->cgid = tswapl(target_ip->cgid);
     host_ip->mode = tswapl(target_ip->mode);
     unlock_user_struct(target_sd, target_addr, 0);
+
+    return ret;
 }
 
-static inline void host_to_target_ipc_perm(target_ulong target_addr,
-                                           struct ipc_perm *host_ip)
+static inline long host_to_target_ipc_perm(target_ulong target_addr,
+                                           struct ipc_perm *host_ip,
+                                           int pg_access)
 {
+    long ret = 0;
     struct target_ipc_perm *target_ip;
     struct target_semid_ds *target_sd;
 
-    lock_user_struct(target_sd, target_addr, 0);
+    if( (ret=lock_and_check_user_struct(&target_sd,target_addr,sizeof(*target_sd),0,pg_access)) ) return -ret;
     target_ip = &(target_sd->sem_perm);
     target_ip->__key = tswapl(host_ip->__key);
     target_ip->uid = tswapl(host_ip->uid);
@@ -1289,32 +1327,42 @@
     target_ip->cgid = tswapl(host_ip->cgid);
     target_ip->mode = tswapl(host_ip->mode);
     unlock_user_struct(target_sd, target_addr, 1);
+
+    return ret;
 }
 
-static inline void target_to_host_semid_ds(struct semid_ds *host_sd,
-                                          target_ulong target_addr)
+static inline long target_to_host_semid_ds(struct semid_ds *host_sd,
+                                          target_ulong target_addr,
+                                          int pg_access)
 {
+    long ret = 0;
     struct target_semid_ds *target_sd;
 
-    lock_user_struct(target_sd, target_addr, 1);
-    target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
+    if( (ret=lock_and_check_user_struct(&target_sd,target_addr,sizeof(*target_sd),1,pg_access)) != 0 ) return -ret;
+    if( (ret=target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr,pg_access)) != 0 ) return ret;
     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 ret;
 }
 
-static inline void host_to_target_semid_ds(target_ulong target_addr,
-                                           struct semid_ds *host_sd)
+static inline long host_to_target_semid_ds(target_ulong target_addr,
+                                           struct semid_ds *host_sd,
+                                           int pg_access)
 {
+    long ret = 0;
     struct target_semid_ds *target_sd;
 
-    lock_user_struct(target_sd, target_addr, 0);
-    host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
+    if( (ret=lock_and_check_user_struct(&target_sd,target_addr,sizeof(*target_sd),0,pg_access)) != 0 ) return -ret;
+    if( (ret=host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm),pg_access)) != 0 ) return ret;
     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 ret;
 }
 
 union semun {
@@ -1329,67 +1377,75 @@
 	unsigned short int *array;
 };
 
-static inline void target_to_host_semun(unsigned long cmd,
+static inline long target_to_host_semun(unsigned long cmd,
                                         union semun *host_su,
                                         target_ulong target_addr,
-                                        struct semid_ds *ds)
+                                        struct semid_ds *ds,
+                                        int pg_access)
 {
+    long ret = 0;
     union target_semun *target_su;
 
     switch( cmd ) {
 	case IPC_STAT:
 	case IPC_SET:
-           lock_user_struct(target_su, target_addr, 1);
-	   target_to_host_semid_ds(ds,target_su->buf);
+	   if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),1,pg_access)) != 0 ) return -ret;
+	   if( (ret=target_to_host_semid_ds(ds,target_su->buf, pg_access)) != 0 ) return -ret;
 	   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( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),1,pg_access)) != 0 ) return -ret;
 	   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( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),1,pg_access)) != 0 ) return -ret;
 	   *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 ret;
 }
 
-static inline void host_to_target_semun(unsigned long cmd,
+static inline long host_to_target_semun(unsigned long cmd,
                                         target_ulong target_addr,
                                         union semun *host_su,
-                                        struct semid_ds *ds)
+                                        struct semid_ds *ds,
+					int pg_access)
 {
+    long ret = 0;
     union target_semun *target_su;
 
     switch( cmd ) {
 	case IPC_STAT:
 	case IPC_SET:
-           lock_user_struct(target_su, target_addr, 0);
-	   host_to_target_semid_ds(target_su->buf,ds);
+	   if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),0,pg_access)) != 0 ) return -ret;
+	   if( (ret=host_to_target_semid_ds(target_su->buf,ds, pg_access)) != 0 ) return -ret;
            unlock_user_struct(target_su, target_addr, 1);
 	   break;
 	case GETVAL:
 	case SETVAL:
-           lock_user_struct(target_su, target_addr, 0);
+	   if( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),0,pg_access)) != 0 ) return -ret;
 	   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( (ret=lock_and_check_user_struct(&target_su,target_addr,sizeof(*target_su),0,pg_access)) != 0 ) return -ret;
 	   *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 ret;
 }
 
 static inline long do_semctl(long first, long second, long third, long ptr)
@@ -1401,34 +1457,34 @@
 
     switch( cmd ) {
 	case GETVAL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_WRITE)) != 0 ) return -ret;
             ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_WRITE);
             break;
 	case SETVAL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_READ)) != 0 ) return -ret;
             ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_READ);
             break;
 	case GETALL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_WRITE)) != 0 ) return -ret;
             ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_WRITE);
             break;
 	case SETALL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_READ)) != 0 ) return -ret;
             ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_READ);
             break;
 	case IPC_STAT:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_WRITE)) != 0 ) return -ret;
             ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_READ);
             break;
 	case IPC_SET:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            if( (ret=target_to_host_semun(cmd,&arg,ptr,&dsarg,PAGE_READ)) != 0 ) return -ret;
             ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            host_to_target_semun(cmd,ptr,&arg,&dsarg,PAGE_READ);
             break;
     default:
             ret = get_errno(semctl(first, second, cmd, arg));
@@ -1455,13 +1511,15 @@
   target_ulong __unused5;
 };
 
-static inline void target_to_host_msqid_ds(struct msqid_ds *host_md,
-                                          target_ulong target_addr)
+static inline long target_to_host_msqid_ds(struct msqid_ds *host_md,
+                                          target_ulong target_addr,
+                                          int pg_access)
 {
+    long ret = 0;
     struct target_msqid_ds *target_md;
 
-    lock_user_struct(target_md, target_addr, 1);
-    target_to_host_ipc_perm(&(host_md->msg_perm),target_addr);
+    if( (ret=lock_and_check_user_struct(&target_md,target_addr,sizeof(*target_md),1,pg_access)) != 0 ) return -ret;
+    if( (ret=target_to_host_ipc_perm(&(host_md->msg_perm),target_addr,pg_access)) != 0 ) return ret;
     host_md->msg_stime = tswapl(target_md->msg_stime);
     host_md->msg_rtime = tswapl(target_md->msg_rtime);
     host_md->msg_ctime = tswapl(target_md->msg_ctime);
@@ -1471,15 +1529,18 @@
     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 ret;
 }
 
-static inline void host_to_target_msqid_ds(target_ulong target_addr,
-                                           struct msqid_ds *host_md)
+static inline long host_to_target_msqid_ds(target_ulong target_addr,
+                                          struct msqid_ds *host_md,
+                                          int pg_access)
 {
+    long ret = 0;
     struct target_msqid_ds *target_md;
 
-    lock_user_struct(target_md, target_addr, 0);
-    host_to_target_ipc_perm(target_addr,&(host_md->msg_perm));
+    if( (ret=lock_and_check_user_struct(&target_md,target_addr,sizeof(*target_md),0,pg_access)) != 0 ) return -ret;
+    if( (ret=host_to_target_ipc_perm(target_addr,&(host_md->msg_perm),pg_access)) != 0 ) return ret;
     target_md->msg_stime = tswapl(host_md->msg_stime);
     target_md->msg_rtime = tswapl(host_md->msg_rtime);
     target_md->msg_ctime = tswapl(host_md->msg_ctime);
@@ -1489,6 +1550,8 @@
     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 ret;
 }
 
 static inline long do_msgctl(long first, long second, long ptr)
@@ -1498,10 +1561,15 @@
     long ret = 0;
     switch( cmd ) {
     case IPC_STAT:
+        if( (ret=target_to_host_msqid_ds(&dsarg,ptr,PAGE_WRITE)) != 0 ) return -ret;
+        ret = get_errno(msgctl(first, cmd, &dsarg));
+        host_to_target_msqid_ds(ptr,&dsarg,PAGE_WRITE);
+	break;
     case IPC_SET:
-        target_to_host_msqid_ds(&dsarg,ptr);
+        if( (ret=target_to_host_msqid_ds(&dsarg,ptr,PAGE_READ)) != 0 ) return -ret;
         ret = get_errno(msgctl(first, cmd, &dsarg));
-        host_to_target_msqid_ds(ptr,&dsarg);
+        host_to_target_msqid_ds(ptr,&dsarg,PAGE_WRITE);
+	break;
     default:
         ret = get_errno(msgctl(first, cmd, &dsarg));
     }
@@ -1519,7 +1587,7 @@
     struct msgbuf *host_mb;
     long ret = 0;
 
-    lock_user_struct(target_mb,msgp,0);
+    if( (ret=lock_and_check_user_struct(&target_mb,msgp,sizeof(long)+msgsz,1,PAGE_READ)) != 0 ) return -ret;
     host_mb = malloc(msgsz+sizeof(long));
     host_mb->mtype = tswapl(target_mb->mtype);
     memcpy(host_mb->mtext,target_mb->mtext,msgsz);
@@ -1536,7 +1604,7 @@
     struct msgbuf *host_mb;
     long ret = 0;
 
-    lock_user_struct(target_mb, msgp, 0);
+    if( (ret=lock_and_check_user_struct(&target_mb,msgp,sizeof(long)+msgsz,0,PAGE_WRITE)) != 0 ) return -ret;
     host_mb = malloc(msgsz+sizeof(long));
     ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg));
     if (ret > 0)
@@ -2016,6 +2084,7 @@
 static int write_ldt(CPUX86State *env, 
                      target_ulong ptr, unsigned long bytecount, int oldmode)
 {
+    long ret = 0;
     struct target_modify_ldt_ldt_s ldt_info;
     struct target_modify_ldt_ldt_s *target_ldt_info;
     int seg_32bit, contents, read_exec_only, limit_in_pages;
@@ -2024,7 +2093,7 @@
 
     if (bytecount != sizeof(ldt_info))
         return -EINVAL;
-    lock_user_struct(target_ldt_info, ptr, 1);
+    if( (ret=lock_and_check_user_struct(&target_ldt_info,ptr,sizeof(struct target_modify_ldt_ldt_s),1,PAGE_READ)) != 0 ) return -ret;
     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);
@@ -2223,7 +2292,7 @@
 
     switch(cmd) {
     case TARGET_F_GETLK:
-        lock_user_struct(target_fl, arg, 1);
+	if( (ret=lock_and_check_user_struct(&target_fl,arg,sizeof(struct target_flock),1,PAGE_READ)) != 0 ) return -ret;
         fl.l_type = tswap16(target_fl->l_type);
         fl.l_whence = tswap16(target_fl->l_whence);
         fl.l_start = tswapl(target_fl->l_start);
@@ -2232,6 +2301,7 @@
         unlock_user_struct(target_fl, arg, 0);
         ret = fcntl(fd, cmd, &fl);
         if (ret == 0) {
+	    if( (ret=lock_and_check_user_struct(&target_fl,arg,sizeof(struct target_flock),0,PAGE_WRITE)) != 0 ) return -ret;
             lock_user_struct(target_fl, arg, 0);
             target_fl->l_type = tswap16(fl.l_type);
             target_fl->l_whence = tswap16(fl.l_whence);
@@ -2244,7 +2314,7 @@
         
     case TARGET_F_SETLK:
     case TARGET_F_SETLKW:
-        lock_user_struct(target_fl, arg, 1);
+	if( (ret=lock_and_check_user_struct(&target_fl,arg,sizeof(struct target_flock),1,PAGE_READ)) != 0 ) return -ret;
         fl.l_type = tswap16(target_fl->l_type);
         fl.l_whence = tswap16(target_fl->l_whence);
         fl.l_start = tswapl(target_fl->l_start);
@@ -2255,7 +2325,7 @@
         break;
         
     case TARGET_F_GETLK64:
-        lock_user_struct(target_fl64, arg, 1);
+	if( (ret=lock_and_check_user_struct(&target_fl64,arg,sizeof(struct target_flock64),1,PAGE_READ)) != 0 ) return -ret;
         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);
@@ -2264,7 +2334,7 @@
         unlock_user_struct(target_fl64, arg, 0);
         ret = fcntl(fd, cmd >> 1, &fl64);
         if (ret == 0) {
-            lock_user_struct(target_fl64, arg, 0);
+	    if( (ret=lock_and_check_user_struct(&target_fl64,arg,sizeof(struct target_flock64),0,PAGE_WRITE)) != 0 ) return -ret;
             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);
@@ -2275,7 +2345,7 @@
 		break;
     case TARGET_F_SETLK64:
     case TARGET_F_SETLKW64:
-        lock_user_struct(target_fl64, arg, 1);
+	if( (ret=lock_and_check_user_struct(&target_fl64,arg,sizeof(struct target_flock64),1,PAGE_READ)) != 0 ) return -ret;
         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);
@@ -2417,23 +2487,26 @@
 }
 #endif
 
-static inline void target_to_host_timespec(struct timespec *host_ts,
+static inline long target_to_host_timespec(struct timespec *host_ts,
                                            target_ulong target_addr)
 {
+    long ret = 0;
     struct target_timespec *target_ts;
 
-    lock_user_struct(target_ts, target_addr, 1);
+    if( (ret=lock_and_check_user_struct(&target_ts,target_addr,sizeof(struct target_timespec),1,PAGE_READ)) != 0 ) return -ret;
     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(target_ulong target_addr,
+static inline long host_to_target_timespec(target_ulong target_addr,
                                            struct timespec *host_ts)
 {
+    long ret = 0;
     struct target_timespec *target_ts;
 
     lock_user_struct(target_ts, target_addr, 0);
+    if( (ret=lock_and_check_user_struct(&target_ts,target_addr,sizeof(struct target_timespec),0,PAGE_WRITE)) != 0 ) return -ret;
     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);
@@ -2442,7 +2515,7 @@
 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
                 long arg4, long arg5, long arg6)
 {
-    long ret;
+    long ret = 0;
     struct stat st;
     struct statfs stfs;
     void *p;
@@ -2669,7 +2742,7 @@
             struct utimbuf tbuf, *host_tbuf;
             struct target_utimbuf *target_tbuf;
             if (arg2) {
-                lock_user_struct(target_tbuf, arg2, 1);
+		if( (ret=lock_and_check_user_struct(&target_tbuf,arg2,sizeof(struct target_utimbuf),1,PAGE_READ)) != 0 ) return -ret;
                 tbuf.actime = tswapl(target_tbuf->actime);
                 tbuf.modtime = tswapl(target_tbuf->modtime);
                 unlock_user_struct(target_tbuf, arg2, 0);
@@ -2687,9 +2760,9 @@
         {
             struct timeval *tvp, tv[2];
             if (arg2) {
-                target_to_host_timeval(&tv[0], arg2);
-                target_to_host_timeval(&tv[1],
-                    arg2 + sizeof (struct target_timeval));
+                if( (ret=target_to_host_timeval(&tv[0], arg2)) != 0 ) return ret;
+                if( (ret=target_to_host_timeval(&tv[1],
+                    arg2 + sizeof (struct target_timeval))) != 0 ) return ret;
                 tvp = tv;
             } else {
                 tvp = NULL;
@@ -2858,7 +2931,7 @@
             struct target_old_sigaction *old_act;
             struct target_sigaction act, oact, *pact;
             if (arg2) {
-                lock_user_struct(old_act, arg2, 1);
+		if( (ret=lock_and_check_user_struct(&old_act,arg2,sizeof(*old_act),1,PAGE_READ)) != 0 ) return -ret;
                 act._sa_handler = old_act->_sa_handler;
                 target_siginitset(&act.sa_mask, old_act->sa_mask);
                 act.sa_flags = old_act->sa_flags;
@@ -2870,7 +2943,7 @@
             }
             ret = get_errno(do_sigaction(arg1, pact, &oact));
             if (!is_error(ret) && arg3) {
-                lock_user_struct(old_act, arg3, 0);
+		if( (ret=lock_and_check_user_struct(&old_act,arg3,sizeof(*old_act),0,PAGE_WRITE)) != 0 ) return -ret;
                 old_act->_sa_handler = oact._sa_handler;
                 old_act->sa_mask = oact.sa_mask.sig[0];
                 old_act->sa_flags = oact.sa_flags;
@@ -2881,7 +2954,7 @@
 	    struct target_sigaction act, oact, *pact, *old_act;
 
 	    if (arg2) {
-		lock_user_struct(old_act, arg2, 1);
+		if( (ret=lock_and_check_user_struct(&old_act,arg2,sizeof(*old_act),1,PAGE_READ)) != 0 ) return -ret;
 		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;
@@ -2894,7 +2967,7 @@
 	    ret = get_errno(do_sigaction(arg1, pact, &oact));
 
 	    if (!is_error(ret) && arg3) {
-		lock_user_struct(old_act, arg3, 0);
+		if( (ret=lock_and_check_user_struct(&old_act,arg3,sizeof(*old_act),0,PAGE_WRITE)) != 0 ) return -ret;
 		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];
@@ -2912,12 +2985,14 @@
             struct target_sigaction *act;
             struct target_sigaction *oact;
 
-            if (arg2)
-                lock_user_struct(act, arg2, 1);
+            if (arg2) {
+		if( (ret=lock_and_check_user_struct(&act,arg2,sizeof(*act),1,PAGE_READ)) != 0 ) return -ret;
+                }
             else
                 act = NULL;
-            if (arg3)
-                lock_user_struct(oact, arg3, 0);
+            if (arg3) {
+		if( (ret=lock_and_check_user_struct(&oact,arg2,sizeof(*oact),0,PAGE_WRITE)) != 0 ) return -ret;
+                }
             else
                 oact = NULL;
             ret = get_errno(do_sigaction(arg1, act, oact));
@@ -3044,7 +3119,7 @@
             sigset_t set;
             ret = get_errno(sigpending(&set));
             if (!is_error(ret)) {
-                p = lock_user(arg1, sizeof(target_sigset_t), 0);
+		if( (ret=lock_and_check_user_struct(&p,arg1,sizeof(target_sigset_t),0,PAGE_WRITE)) != 0 ) return -ret;
                 host_to_target_sigset(p, &set);
                 unlock_user(p, arg1, sizeof(target_sigset_t));
             }
@@ -3054,7 +3129,7 @@
     case TARGET_NR_sigsuspend:
         {
             sigset_t set;
-            p = lock_user(arg1, sizeof(target_sigset_t), 1);
+	    if( (ret=lock_and_check_user_struct(&p,arg1,sizeof(target_sigset_t),1,PAGE_READ)) != 0 ) return -ret;
             target_to_host_old_sigset(&set, p);
             unlock_user(p, arg1, 0);
             ret = get_errno(sigsuspend(&set));
@@ -3064,7 +3139,7 @@
     case TARGET_NR_rt_sigsuspend:
         {
             sigset_t set;
-            p = lock_user(arg1, sizeof(target_sigset_t), 1);
+	    if( (ret=lock_and_check_user_struct(&p,arg1,sizeof(target_sigset_t),1,PAGE_READ)) != 0 ) return -ret;
             target_to_host_sigset(&set, p);
             unlock_user(p, arg1, 0);
             ret = get_errno(sigsuspend(&set));
@@ -3076,18 +3151,18 @@
             struct timespec uts, *puts;
             siginfo_t uinfo;
             
-            p = lock_user(arg1, sizeof(target_sigset_t), 1);
+	    if( (ret=lock_and_check_user_struct(&p,arg1,sizeof(target_sigset_t),1,PAGE_READ)) != 0 ) return -ret;
             target_to_host_sigset(&set, p);
             unlock_user(p, arg1, 0);
             if (arg3) {
                 puts = &uts;
-                target_to_host_timespec(puts, arg3);
+                if( (ret=target_to_host_timespec(puts, arg3)) != 0 ) return ret;
             } else {
                 puts = NULL;
             }
             ret = get_errno(sigtimedwait(&set, &uinfo, puts));
             if (!is_error(ret) && arg2) {
-                p = lock_user(arg2, sizeof(target_sigset_t), 0);
+		if( (ret=lock_and_check_user_struct(&p,arg2,sizeof(target_sigset_t),0,PAGE_WRITE)) != 0 ) return -ret;
                 host_to_target_siginfo(p, &uinfo);
                 unlock_user(p, arg2, sizeof(target_sigset_t));
             }
@@ -3096,7 +3171,7 @@
     case TARGET_NR_rt_sigqueueinfo:
         {
             siginfo_t uinfo;
-            p = lock_user(arg3, sizeof(target_sigset_t), 1);
+	    if( (ret=lock_and_check_user_struct(&p,arg3,sizeof(target_sigset_t),1,PAGE_READ)) != 0 ) return -ret;
             target_to_host_siginfo(&uinfo, p);
             unlock_user(p, arg1, 0);
             ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
@@ -3151,7 +3226,7 @@
             struct rusage rusage;
             ret = get_errno(getrusage(arg1, &rusage));
             if (!is_error(ret)) {
-                host_to_target_rusage(arg2, &rusage);
+                if( (ret=host_to_target_rusage(arg2, &rusage)) != 0 ) return ret;
             }
         }
         break;
@@ -3160,14 +3235,14 @@
             struct timeval tv;
             ret = get_errno(gettimeofday(&tv, NULL));
             if (!is_error(ret)) {
-                host_to_target_timeval(arg1, &tv);
+                if( (ret=host_to_target_timeval(arg1, &tv)) != 0 ) return ret;
             }
         }
         break;
     case TARGET_NR_settimeofday:
         {
             struct timeval tv;
-            target_to_host_timeval(&tv, arg1);
+            if( (ret=target_to_host_timeval(&tv, arg1)) != 0 ) return ret;
             ret = get_errno(settimeofday(&tv, NULL));
         }
         break;
@@ -3486,19 +3561,19 @@
 
             if (arg2) {
                 pvalue = &value;
-                target_to_host_timeval(&pvalue->it_interval, 
-                                       arg2);
-                target_to_host_timeval(&pvalue->it_value, 
-                                       arg2 + sizeof(struct target_timeval));
+                if( (ret=target_to_host_timeval(&pvalue->it_interval,
+                                       arg2)) != 0 ) return ret;
+                if( (ret=target_to_host_timeval(&pvalue->it_value,
+                                       arg2 + sizeof(struct target_timeval))) != 0 ) return ret;
             } else {
                 pvalue = NULL;
             }
             ret = get_errno(setitimer(arg1, pvalue, &ovalue));
             if (!is_error(ret) && arg3) {
-                host_to_target_timeval(arg3,
-                                       &ovalue.it_interval);
-                host_to_target_timeval(arg3 + sizeof(struct target_timeval),
-                                       &ovalue.it_value);
+                if( (ret=host_to_target_timeval(arg3,
+                                       &ovalue.it_interval)) != 0 ) return ret;
+                if( (ret=host_to_target_timeval(arg3 + sizeof(struct target_timeval),
+                                       &ovalue.it_value)) != 0 ) return ret;
             }
         }
         break;
@@ -3508,10 +3583,10 @@
             
             ret = get_errno(getitimer(arg1, &value));
             if (!is_error(ret) && arg2) {
-                host_to_target_timeval(arg2,
-                                       &value.it_interval);
-                host_to_target_timeval(arg2 + sizeof(struct target_timeval),
-                                       &value.it_value);
+                if( (ret=host_to_target_timeval(arg2,
+                                       &value.it_interval)) != 0 ) return ret;
+                if( (ret=host_to_target_timeval(arg2 + sizeof(struct target_timeval),
+                                       &value.it_value)) != 0 ) return ret;
             }
         }
         break;
@@ -3532,7 +3607,7 @@
             if (!is_error(ret)) {
                 struct target_stat *target_st;
 
-                lock_user_struct(target_st, arg2, 0);
+		if( (ret=lock_and_check_user_struct(&target_st,arg2,sizeof(*target_st),9,PAGE_WRITE)) != 0 ) return -ret;
 #if defined(TARGET_MIPS)
                 target_st->st_dev = tswap32(st.st_dev);
 #else
@@ -3963,17 +4038,17 @@
             struct timespec ts;
             ret = get_errno(sched_rr_get_interval(arg1, &ts));
             if (!is_error(ret)) {
-                host_to_target_timespec(arg2, &ts);
+                if( (ret=host_to_target_timespec(arg2, &ts)) != 0 ) return ret;
             }
         }
         break;
     case TARGET_NR_nanosleep:
         {
             struct timespec req, rem;
-            target_to_host_timespec(&req, arg1);
+            if( (ret=target_to_host_timespec(&req, arg1)) != 0 ) return ret;
             ret = get_errno(nanosleep(&req, &rem));
             if (is_error(ret) && arg2) {
-                host_to_target_timespec(arg2, &rem);
+                if( (ret=host_to_target_timespec(arg2, &rem)) != 0 ) return ret;
             }
         }
         break;
@@ -4070,6 +4145,7 @@
 #ifdef TARGET_NR_stat64
     case TARGET_NR_stat64:
         p = lock_user_string(arg1);
+        if( ret=page_check_range(p,1,PAGE_READ) ) return -ret;
         ret = get_errno(stat(path(p), &st));
         unlock_user(p, arg1, 0);
         goto do_stat64;
@@ -4077,6 +4153,7 @@
 #ifdef TARGET_NR_lstat64
     case TARGET_NR_lstat64:
         p = lock_user_string(arg1);
+        if( ret=page_check_range(p,1,PAGE_READ) ) return -ret;
         ret = get_errno(lstat(path(p), &st));
         unlock_user(p, arg1, 0);
         goto do_stat64;
@@ -4090,7 +4167,7 @@
 #ifdef TARGET_ARM
                 if (((CPUARMState *)cpu_env)->eabi) {
                     struct target_eabi_stat64 *target_st;
-                    lock_user_struct(target_st, arg2, 1);
+		    if( (ret=lock_and_check_user_struct(&target_st,arg2,sizeof(*target_st),1,PAGE_WRITE)) != 0 ) return -ret;
                     memset(target_st, 0, sizeof(struct target_eabi_stat64));
                     /* put_user is probably wrong.  */
                     put_user(st.st_dev, &target_st->st_dev);
@@ -4115,7 +4192,7 @@
 #endif
                 {
                     struct target_stat64 *target_st;
-                    lock_user_struct(target_st, arg2, 1);
+		    if( (ret=lock_and_check_user_struct(&target_st,arg2,sizeof(*target_st),1,PAGE_WRITE)) != 0 ) return -ret;
                     memset(target_st, 0, sizeof(struct target_stat64));
                     /* ??? put_user is probably wrong.  */
                     put_user(st.st_dev, &target_st->st_dev);
@@ -4581,7 +4658,7 @@
         struct timespec ts;
         ret = get_errno(clock_gettime(arg1, &ts));
         if (!is_error(ret)) {
-            host_to_target_timespec(arg2, &ts);
+            if( (ret=host_to_target_timespec(arg2, &ts)) != 0 ) return ret;
         }
         break;
     }
@@ -4592,7 +4669,7 @@
         struct timespec ts;
         ret = get_errno(clock_getres(arg1, &ts));
         if (!is_error(ret)) {
-            host_to_target_timespec(arg2, &ts);
+            if( (ret=host_to_target_timespec(arg2, &ts)) != 0 ) return ret;
         }
         break;
     }
Index: qemu/linux-user/qemu.h
===================================================================
--- qemu.orig/linux-user/qemu.h	2007-06-03 20:36:54.000000000 -0400
+++ qemu/linux-user/qemu.h	2007-06-03 20:37:10.000000000 -0400
@@ -295,6 +295,15 @@
 #define unlock_user_struct(host_ptr, guest_addr, copy) \
     unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
 
+static inline long lock_and_check_user_struct(void *host_addr, target_ulong guest_addr, long len, int copy, int pg_access)
+{
+    long *haddr, ret = 0;
+    haddr = (long *)host_addr;
+    if( (ret=page_check_range(guest_addr,len,pg_access)) != 0 ) return ret;
+    *haddr = (long)lock_user(guest_addr, len, copy);
+    return 0;
+}
+
 #define tget8(addr) ldub(addr)
 #define tput8(addr, val) stb(addr, val)
 #define tget16(addr) lduw(addr)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-06-04  0:48 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-04  0:47 [Qemu-devel] [PATCH] EFAULT implmentation in linux-user Stuart Anderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).