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;