diff options
author | Arnaud Patard <arnaud.patard@rtp-net.org> | 2009-06-19 10:44:45 +0300 |
---|---|---|
committer | Riku Voipio <riku.voipio@iki.fi> | 2009-07-08 17:01:08 +0300 |
commit | 917507b01efea8017bfcb4188ac696612e363e72 (patch) | |
tree | 328cc648835a03192dee8620f033d82db56ea763 /linux-user | |
parent | fd4d81dd04b4e606ce40a41d66368ba77c77c753 (diff) | |
download | qemu-917507b01efea8017bfcb4188ac696612e363e72.tar.gz qemu-917507b01efea8017bfcb4188ac696612e363e72.tar.bz2 qemu-917507b01efea8017bfcb4188ac696612e363e72.zip |
linux-user: check some parameters for some socket syscalls.
This patch is fixing following issues :
- commit 8fea36025b9d6d360ff3b78f88a84ccf221807e8 was applied to
do_getsockname instead of do_accept.
- Some syscalls were not checking properly the memory addresses passed
as argument
- Add check before syscalls made for cases like do_getpeername() where
we're using the address parameter after doing the syscall
- Fix do_accept to return EINVAL instead of EFAULT when parameters
invalid to match with linux behaviour
Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/syscall.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 11564fd0bc..a96e86ae72 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1498,13 +1498,17 @@ static abi_long do_bind(int sockfd, abi_ulong target_addr, socklen_t addrlen) { void *addr; + abi_long ret; if (addrlen < 0) return -TARGET_EINVAL; addr = alloca(addrlen+1); - target_to_host_sockaddr(addr, target_addr, addrlen); + ret = target_to_host_sockaddr(addr, target_addr, addrlen); + if (ret) + return ret; + return get_errno(bind(sockfd, addr, addrlen)); } @@ -1513,13 +1517,17 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr, socklen_t addrlen) { void *addr; + abi_long ret; if (addrlen < 0) return -TARGET_EINVAL; addr = alloca(addrlen); - target_to_host_sockaddr(addr, target_addr, addrlen); + ret = target_to_host_sockaddr(addr, target_addr, addrlen); + if (ret) + return ret; + return get_errno(connect(sockfd, addr, addrlen)); } @@ -1543,8 +1551,12 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, 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), + ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), msg.msg_namelen); + if (ret) { + unlock_user_struct(msgp, target_msg, send ? 0 : 1); + return ret; + } } else { msg.msg_name = NULL; msg.msg_namelen = 0; @@ -1586,12 +1598,19 @@ static abi_long do_accept(int fd, abi_ulong target_addr, void *addr; abi_long ret; + if (target_addr == 0) + return get_errno(accept(fd, NULL, NULL)); + + /* linux returns EINVAL if addrlen pointer is invalid */ if (get_user_u32(addrlen, target_addrlen_addr)) - return -TARGET_EFAULT; + return -TARGET_EINVAL; if (addrlen < 0) return -TARGET_EINVAL; + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) + return -TARGET_EINVAL; + addr = alloca(addrlen); ret = get_errno(accept(fd, addr, &addrlen)); @@ -1617,6 +1636,9 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr, if (addrlen < 0) return -TARGET_EINVAL; + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) + return -TARGET_EFAULT; + addr = alloca(addrlen); ret = get_errno(getpeername(fd, addr, &addrlen)); @@ -1636,15 +1658,15 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr, void *addr; abi_long ret; - if (target_addr == 0) - return get_errno(accept(fd, NULL, NULL)); - if (get_user_u32(addrlen, target_addrlen_addr)) return -TARGET_EFAULT; if (addrlen < 0) return -TARGET_EINVAL; + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) + return -TARGET_EFAULT; + addr = alloca(addrlen); ret = get_errno(getsockname(fd, addr, &addrlen)); @@ -1688,7 +1710,11 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, return -TARGET_EFAULT; if (target_addr) { addr = alloca(addrlen); - target_to_host_sockaddr(addr, target_addr, addrlen); + ret = target_to_host_sockaddr(addr, target_addr, addrlen); + if (ret) { + unlock_user(host_msg, msg, 0); + return ret; + } ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen)); } else { ret = get_errno(send(fd, host_msg, len, flags)); |