Commit 917507b01efea8017bfcb4188ac696612e363e72
Committed by
Riku Voipio
1 parent
fd4d81dd
linux-user: check some parameters for some socket syscalls.
This patch is fixing following issues : - commit 8fea3602 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>
Showing
1 changed file
with
34 additions
and
8 deletions
linux-user/syscall.c
@@ -1498,13 +1498,17 @@ static abi_long do_bind(int sockfd, abi_ulong target_addr, | @@ -1498,13 +1498,17 @@ static abi_long do_bind(int sockfd, abi_ulong target_addr, | ||
1498 | socklen_t addrlen) | 1498 | socklen_t addrlen) |
1499 | { | 1499 | { |
1500 | void *addr; | 1500 | void *addr; |
1501 | + abi_long ret; | ||
1501 | 1502 | ||
1502 | if (addrlen < 0) | 1503 | if (addrlen < 0) |
1503 | return -TARGET_EINVAL; | 1504 | return -TARGET_EINVAL; |
1504 | 1505 | ||
1505 | addr = alloca(addrlen+1); | 1506 | addr = alloca(addrlen+1); |
1506 | 1507 | ||
1507 | - target_to_host_sockaddr(addr, target_addr, addrlen); | 1508 | + ret = target_to_host_sockaddr(addr, target_addr, addrlen); |
1509 | + if (ret) | ||
1510 | + return ret; | ||
1511 | + | ||
1508 | return get_errno(bind(sockfd, addr, addrlen)); | 1512 | return get_errno(bind(sockfd, addr, addrlen)); |
1509 | } | 1513 | } |
1510 | 1514 | ||
@@ -1513,13 +1517,17 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr, | @@ -1513,13 +1517,17 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr, | ||
1513 | socklen_t addrlen) | 1517 | socklen_t addrlen) |
1514 | { | 1518 | { |
1515 | void *addr; | 1519 | void *addr; |
1520 | + abi_long ret; | ||
1516 | 1521 | ||
1517 | if (addrlen < 0) | 1522 | if (addrlen < 0) |
1518 | return -TARGET_EINVAL; | 1523 | return -TARGET_EINVAL; |
1519 | 1524 | ||
1520 | addr = alloca(addrlen); | 1525 | addr = alloca(addrlen); |
1521 | 1526 | ||
1522 | - target_to_host_sockaddr(addr, target_addr, addrlen); | 1527 | + ret = target_to_host_sockaddr(addr, target_addr, addrlen); |
1528 | + if (ret) | ||
1529 | + return ret; | ||
1530 | + | ||
1523 | return get_errno(connect(sockfd, addr, addrlen)); | 1531 | return get_errno(connect(sockfd, addr, addrlen)); |
1524 | } | 1532 | } |
1525 | 1533 | ||
@@ -1543,8 +1551,12 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, | @@ -1543,8 +1551,12 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, | ||
1543 | if (msgp->msg_name) { | 1551 | if (msgp->msg_name) { |
1544 | msg.msg_namelen = tswap32(msgp->msg_namelen); | 1552 | msg.msg_namelen = tswap32(msgp->msg_namelen); |
1545 | msg.msg_name = alloca(msg.msg_namelen); | 1553 | msg.msg_name = alloca(msg.msg_namelen); |
1546 | - target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), | 1554 | + ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), |
1547 | msg.msg_namelen); | 1555 | msg.msg_namelen); |
1556 | + if (ret) { | ||
1557 | + unlock_user_struct(msgp, target_msg, send ? 0 : 1); | ||
1558 | + return ret; | ||
1559 | + } | ||
1548 | } else { | 1560 | } else { |
1549 | msg.msg_name = NULL; | 1561 | msg.msg_name = NULL; |
1550 | msg.msg_namelen = 0; | 1562 | msg.msg_namelen = 0; |
@@ -1586,12 +1598,19 @@ static abi_long do_accept(int fd, abi_ulong target_addr, | @@ -1586,12 +1598,19 @@ static abi_long do_accept(int fd, abi_ulong target_addr, | ||
1586 | void *addr; | 1598 | void *addr; |
1587 | abi_long ret; | 1599 | abi_long ret; |
1588 | 1600 | ||
1601 | + if (target_addr == 0) | ||
1602 | + return get_errno(accept(fd, NULL, NULL)); | ||
1603 | + | ||
1604 | + /* linux returns EINVAL if addrlen pointer is invalid */ | ||
1589 | if (get_user_u32(addrlen, target_addrlen_addr)) | 1605 | if (get_user_u32(addrlen, target_addrlen_addr)) |
1590 | - return -TARGET_EFAULT; | 1606 | + return -TARGET_EINVAL; |
1591 | 1607 | ||
1592 | if (addrlen < 0) | 1608 | if (addrlen < 0) |
1593 | return -TARGET_EINVAL; | 1609 | return -TARGET_EINVAL; |
1594 | 1610 | ||
1611 | + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) | ||
1612 | + return -TARGET_EINVAL; | ||
1613 | + | ||
1595 | addr = alloca(addrlen); | 1614 | addr = alloca(addrlen); |
1596 | 1615 | ||
1597 | ret = get_errno(accept(fd, addr, &addrlen)); | 1616 | ret = get_errno(accept(fd, addr, &addrlen)); |
@@ -1617,6 +1636,9 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr, | @@ -1617,6 +1636,9 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr, | ||
1617 | if (addrlen < 0) | 1636 | if (addrlen < 0) |
1618 | return -TARGET_EINVAL; | 1637 | return -TARGET_EINVAL; |
1619 | 1638 | ||
1639 | + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) | ||
1640 | + return -TARGET_EFAULT; | ||
1641 | + | ||
1620 | addr = alloca(addrlen); | 1642 | addr = alloca(addrlen); |
1621 | 1643 | ||
1622 | ret = get_errno(getpeername(fd, addr, &addrlen)); | 1644 | ret = get_errno(getpeername(fd, addr, &addrlen)); |
@@ -1636,15 +1658,15 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr, | @@ -1636,15 +1658,15 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr, | ||
1636 | void *addr; | 1658 | void *addr; |
1637 | abi_long ret; | 1659 | abi_long ret; |
1638 | 1660 | ||
1639 | - if (target_addr == 0) | ||
1640 | - return get_errno(accept(fd, NULL, NULL)); | ||
1641 | - | ||
1642 | if (get_user_u32(addrlen, target_addrlen_addr)) | 1661 | if (get_user_u32(addrlen, target_addrlen_addr)) |
1643 | return -TARGET_EFAULT; | 1662 | return -TARGET_EFAULT; |
1644 | 1663 | ||
1645 | if (addrlen < 0) | 1664 | if (addrlen < 0) |
1646 | return -TARGET_EINVAL; | 1665 | return -TARGET_EINVAL; |
1647 | 1666 | ||
1667 | + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) | ||
1668 | + return -TARGET_EFAULT; | ||
1669 | + | ||
1648 | addr = alloca(addrlen); | 1670 | addr = alloca(addrlen); |
1649 | 1671 | ||
1650 | ret = get_errno(getsockname(fd, addr, &addrlen)); | 1672 | 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, | @@ -1688,7 +1710,11 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, | ||
1688 | return -TARGET_EFAULT; | 1710 | return -TARGET_EFAULT; |
1689 | if (target_addr) { | 1711 | if (target_addr) { |
1690 | addr = alloca(addrlen); | 1712 | addr = alloca(addrlen); |
1691 | - target_to_host_sockaddr(addr, target_addr, addrlen); | 1713 | + ret = target_to_host_sockaddr(addr, target_addr, addrlen); |
1714 | + if (ret) { | ||
1715 | + unlock_user(host_msg, msg, 0); | ||
1716 | + return ret; | ||
1717 | + } | ||
1692 | ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen)); | 1718 | ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen)); |
1693 | } else { | 1719 | } else { |
1694 | ret = get_errno(send(fd, host_msg, len, flags)); | 1720 | ret = get_errno(send(fd, host_msg, len, flags)); |