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;