This part contains the changes to teh socket interfaces. This includes
updates to the functions for reading and writing struct sockaddr, as
well as updates and some fixes to do_setsockopt() and do_getsockopt().

The implementations of bind() connect(), accept(), getpeername() and
getsockname() have adjustments to use the newer kernel-like apis.
the same is true for the functions that implement send(), sendto(),
recv() and recvfrom().


                                Stuart

Stuart R. Anderson                               [EMAIL PROTECTED]
Network & Software Engineering                   http://www.netsweng.com/
1024D/37A79149:                                  0791 D3B8 9A4C 2CDC A31F
                                                 BD03 0A62 E534 37A7 9149
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c      2007-09-17 00:55:34.000000000 -0400
+++ qemu/linux-user/syscall.c   2007-09-17 01:00:36.000000000 -0400
@@ -527,28 +527,24 @@
     return ret;
 }
 
-static inline void target_to_host_sockaddr(struct sockaddr *addr,
-                                           target_ulong target_addr,
+static inline long copy_from_user_sockaddr(struct sockaddr *addr,
+                                           struct target_sockaddr * 
target_saddr,
                                            socklen_t len)
 {
-    struct target_sockaddr *target_saddr;
+    if( copy_from_user(addr,target_saddr,len) ) return -1;
+    __get_user(addr->sa_family, &target_saddr->sa_family);
 
-    target_saddr = lock_user(target_addr, len, 1);
-    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(target_ulong target_addr,
+static inline long copy_to_user_sockaddr(struct target_sockaddr *target_saddr,
                                            struct sockaddr *addr,
                                            socklen_t len)
 {
-    struct target_sockaddr *target_saddr;
+    if( copy_to_user(target_saddr,addr,len) ) return -1;
+    __put_user(addr->sa_family, &target_saddr->sa_family);
 
-    target_saddr = lock_user(target_addr, len, 0);
-    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?  */
@@ -651,6 +647,8 @@
         if (optlen < sizeof(uint32_t))
             return -EINVAL;
        
+      if( !access_ok(VERIFY_READ, optval, optlen) )
+            return -EFAULT;
         val = tget32(optval);
         ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
         break;
@@ -672,6 +670,8 @@
         case IP_MULTICAST_TTL:
         case IP_MULTICAST_LOOP:
             val = 0;
+           if( !access_ok(VERIFY_READ, optval, optlen) )
+                return -EFAULT;
             if (optlen >= sizeof(uint32_t)) {
                 val = tget32(optval);
             } else if (optlen >= 1) {
@@ -680,7 +680,7 @@
             ret = get_errno(setsockopt(sockfd, level, optname, &val, 
sizeof(val)));
             break;
         default:
-            goto unimplemented;
+            goto unimplemented;
         }
         break;
     case TARGET_SOL_SOCKET:
@@ -746,8 +746,11 @@
         default:
             goto unimplemented;
         }
-       if (optlen < sizeof(uint32_t))
-       return -EINVAL;
+        if (optlen < sizeof(uint32_t))
+         return -EINVAL;
+        if( !access_ok(VERIFY_READ, optval, optlen) )
+          return -EFAULT;
+
 
        val = tget32(optval);
        ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, 
sizeof(val)));
@@ -755,13 +758,13 @@
     default:
     unimplemented:
         gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, 
optname);
-        ret = -ENOSYS;
+        ret = -ENOPROTOOPT;
     }
     return ret;
 }
 
 static long do_getsockopt(int sockfd, int level, int optname,
-                          target_ulong optval, target_ulong optlen)
+                          target_ulong optval, socklen_t *optlen)
 {
     int len, lv, val, ret;
 
@@ -783,7 +786,10 @@
     case SOL_TCP:
         /* TCP options all take an 'int' value.  */
     int_case:
-        len = tget32(optlen);
+       if( get_user(len,optlen) )
+            return -EFAULT;
+       if( !access_ok(VERIFY_WRITE, optval,len) )
+            return -EFAULT;
         if (len < 0)
             return -EINVAL;
         lv = sizeof(int);
@@ -816,7 +822,10 @@
 #endif
         case IP_MULTICAST_TTL:
         case IP_MULTICAST_LOOP:
-            len = tget32(optlen);
+           if( get_user(len,optlen) )
+                return -EINVAL;
+       if( !access_ok(VERIFY_WRITE, optval,len) )
+            return -EFAULT;
             if (len < 0)
                 return -EINVAL;
             lv = sizeof(int);
@@ -835,14 +844,15 @@
             }
             break;
         default:
-            goto unimplemented;
+            ret = -ENOPROTOOPT;
+            break;
         }
         break;
     default:
     unimplemented:
         gemu_log("getsockopt level=%d optname=%d not yet supported\n",
                  level, optname);
-        ret = -ENOSYS;
+        ret = -EOPNOTSUPP;
         break;
     }
     return ret;
@@ -911,7 +921,7 @@
 {
     void *addr = alloca(addrlen);
    
-    target_to_host_sockaddr(addr, target_addr, addrlen);
+    if( copy_from_user_sockaddr(addr, (struct target_sockaddr *)target_addr, 
addrlen) ) return -EFAULT;
     return get_errno(bind(sockfd, addr, addrlen));
 }
 
@@ -920,7 +930,7 @@
 {
     void *addr = alloca(addrlen);
    
-    target_to_host_sockaddr(addr, target_addr, addrlen);
+    if( copy_from_user_sockaddr(addr, (struct target_sockaddr *)target_addr, 
addrlen) ) return -EFAULT;
     return get_errno(connect(sockfd, addr, addrlen));
 }
 
@@ -937,9 +947,10 @@
     lock_user_struct(msgp, target_msg, 1);
     if (msgp->msg_name) {
         msg.msg_namelen = tswap32(msgp->msg_namelen);
+       if( msg.msg_namelen > sizeof(struct sockaddr_storage) ) return -EINVAL;
         msg.msg_name = alloca(msg.msg_namelen);
-        target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
-                                msg.msg_namelen);
+        if( copy_from_user_sockaddr(msg.msg_name, (struct target_sockaddr 
*)msgp->msg_name,
+                                msg.msg_namelen) ) return -EFAULT;
     } else {
         msg.msg_name = NULL;
         msg.msg_namelen = 0;
@@ -968,46 +979,55 @@
 }
 
 static long do_accept(int fd, target_ulong target_addr,
-                      target_ulong target_addrlen)
+                      socklen_t *target_addrlen)
 {
-    socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(addrlen);
+    socklen_t addrlen;
+    void *addr;
     long ret;
 
+    if( get_user(addrlen,target_addrlen) ) return -EINVAL;
+    addr = alloca(addrlen);
+
     ret = get_errno(accept(fd, addr, &addrlen));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if( copy_to_user_sockaddr((struct target_sockaddr *)target_addr, addr, 
addrlen) ) return -EFAULT;
         tput32(target_addrlen, addrlen);
     }
     return ret;
 }
 
 static long do_getpeername(int fd, target_ulong target_addr,
-                           target_ulong target_addrlen)
+                           socklen_t *target_addrlen)
 {
-    socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(addrlen);
+    socklen_t addrlen;
+    void *addr;
     long ret;
 
+    if( get_user(addrlen,target_addrlen) ) return -EFAULT;
+    addr = alloca(addrlen);
+
     ret = get_errno(getpeername(fd, addr, &addrlen));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
-        tput32(target_addrlen, addrlen);
+        if( copy_to_user_sockaddr((struct target_sockaddr *)target_addr, addr, 
addrlen) ) return -EFAULT;
+        tput32(target_addrlen,addrlen);
     }
     return ret;
 }
 
 static long do_getsockname(int fd, target_ulong target_addr,
-                           target_ulong target_addrlen)
+                           socklen_t *target_addrlen)
 {
-    socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(addrlen);
+    socklen_t addrlen;
+    void *addr;
     long ret;
 
+    if( get_user(addrlen,target_addrlen) ) return -EFAULT;
+    addr = alloca(addrlen);
+
     ret = get_errno(getsockname(fd, addr, &addrlen));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
-        tput32(target_addrlen, addrlen);
+        if( copy_to_user_sockaddr((struct target_sockaddr *)target_addr, addr, 
addrlen) ) return -EFAULT;
+        tput32(target_addrlen,addrlen);
     }
     return ret;
 }
@@ -1018,6 +1038,8 @@
     int tab[2];
     long ret;
 
+    if( !access_ok(VERIFY_WRITE,target_tab,2*sizeof(int)) )
+       return -EFAULT;
     ret = get_errno(socketpair(domain, type, protocol, tab));
     if (!is_error(ret)) {
         tput32(target_tab, tab[0]);
@@ -1030,18 +1052,18 @@
                       target_ulong target_addr, socklen_t addrlen)
 {
     void *addr;
-    void *host_msg;
+    void *target_msg = (void *)msg;
+    void *host_msg = alloca(len);
     long ret;
 
-    host_msg = lock_user(msg, len, 1);
+    if (copy_from_user(host_msg,target_msg,len) ) return -EFAULT;
     if (target_addr) {
         addr = alloca(addrlen);
-        target_to_host_sockaddr(addr, target_addr, addrlen);
+        if (copy_from_user_sockaddr(addr, (struct target_sockaddr 
*)target_addr, addrlen) ) return -EFAULT;
         ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
     } else {
         ret = get_errno(send(fd, host_msg, len, flags));
     }
-    unlock_user(host_msg, msg, 0);
     return ret;
 }
 
@@ -1050,12 +1072,13 @@
 {
     socklen_t addrlen;
     void *addr;
-    void *host_msg;
+    void *target_msg = (void *)msg;
+    void *host_msg = alloca(len);
     long ret;
 
-    host_msg = lock_user(msg, len, 0);
     if (target_addr) {
-        addrlen = tget32(target_addrlen);
+       addrlen = tget32(target_addrlen);
+       if( addrlen > sizeof(struct sockaddr_storage) ) return -EINVAL;
         addr = alloca(addrlen);
         ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
     } else {
@@ -1064,12 +1087,10 @@
     }
     if (!is_error(ret)) {
         if (target_addr) {
-            host_to_target_sockaddr(target_addr, addr, addrlen);
+            if (copy_to_user_sockaddr((struct target_sockaddr *)target_addr, 
addr, addrlen) ) return -EFAULT;
             tput32(target_addrlen, addrlen);
         }
-        unlock_user(host_msg, msg, len);
-    } else {
-        unlock_user(host_msg, msg, 0);
+        if( copy_to_user(target_msg, host_msg, len) ) return -EFAULT;
     }
     return ret;
 }
@@ -1116,7 +1137,7 @@
             int sockfd = tgetl(vptr);
             target_ulong target_addr = tgetl(vptr + n);
             target_ulong target_addrlen = tgetl(vptr + 2 * n);
-            ret = do_accept(sockfd, target_addr, target_addrlen);
+            ret = do_accept(sockfd, target_addr, (socklen_t *)target_addrlen);
         }
         break;
     case SOCKOP_getsockname:
@@ -1124,7 +1145,7 @@
             int sockfd = tgetl(vptr);
             target_ulong target_addr = tgetl(vptr + n);
             target_ulong target_addrlen = tgetl(vptr + 2 * n);
-            ret = do_getsockname(sockfd, target_addr, target_addrlen);
+            ret = do_getsockname(sockfd, target_addr, (socklen_t 
*)target_addrlen);
         }
         break;
     case SOCKOP_getpeername:
@@ -1132,7 +1153,7 @@
             int sockfd = tgetl(vptr);
             target_ulong target_addr = tgetl(vptr + n);
             target_ulong target_addrlen = tgetl(vptr + 2 * n);
-            ret = do_getpeername(sockfd, target_addr, target_addrlen);
+            ret = do_getpeername(sockfd, target_addr, (socklen_t 
*)target_addrlen);
         }
         break;
     case SOCKOP_socketpair:
@@ -1226,12 +1247,12 @@
             target_ulong optval = tgetl(vptr + 3 * n);
             target_ulong poptlen = tgetl(vptr + 4 * n);
 
-            ret = do_getsockopt(sockfd, level, optname, optval, poptlen);
+            ret = do_getsockopt(sockfd, level, optname, optval, (socklen_t 
*)poptlen);
         }
         break;
     default:
         gemu_log("Unsupported socketcall: %d\n", num);
-        ret = -ENOSYS;
+        ret = -EINVAL;
         break;
     }
     return ret;

Reply via email to