diff options
Diffstat (limited to 'fs/compat.c')
-rw-r--r-- | fs/compat.c | 136 |
1 files changed, 20 insertions, 116 deletions
diff --git a/fs/compat.c b/fs/compat.c index 424767c954a0..133ed7f5d681 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -1568,7 +1568,8 @@ int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | |||
1568 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | 1568 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) |
1569 | 1569 | ||
1570 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, | 1570 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, |
1571 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout) | 1571 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, |
1572 | struct timespec *end_time) | ||
1572 | { | 1573 | { |
1573 | fd_set_bits fds; | 1574 | fd_set_bits fds; |
1574 | void *bits; | 1575 | void *bits; |
@@ -1615,7 +1616,7 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp, | |||
1615 | zero_fd_set(n, fds.res_out); | 1616 | zero_fd_set(n, fds.res_out); |
1616 | zero_fd_set(n, fds.res_ex); | 1617 | zero_fd_set(n, fds.res_ex); |
1617 | 1618 | ||
1618 | ret = do_select(n, &fds, timeout); | 1619 | ret = do_select(n, &fds, end_time); |
1619 | 1620 | ||
1620 | if (ret < 0) | 1621 | if (ret < 0) |
1621 | goto out; | 1622 | goto out; |
@@ -1641,7 +1642,7 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, | |||
1641 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | 1642 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, |
1642 | struct compat_timeval __user *tvp) | 1643 | struct compat_timeval __user *tvp) |
1643 | { | 1644 | { |
1644 | s64 timeout = -1; | 1645 | struct timespec end_time, *to = NULL; |
1645 | struct compat_timeval tv; | 1646 | struct compat_timeval tv; |
1646 | int ret; | 1647 | int ret; |
1647 | 1648 | ||
@@ -1649,43 +1650,14 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, | |||
1649 | if (copy_from_user(&tv, tvp, sizeof(tv))) | 1650 | if (copy_from_user(&tv, tvp, sizeof(tv))) |
1650 | return -EFAULT; | 1651 | return -EFAULT; |
1651 | 1652 | ||
1652 | if (tv.tv_sec < 0 || tv.tv_usec < 0) | 1653 | to = &end_time; |
1654 | if (poll_select_set_timeout(to, tv.tv_sec, | ||
1655 | tv.tv_usec * NSEC_PER_USEC)) | ||
1653 | return -EINVAL; | 1656 | return -EINVAL; |
1654 | |||
1655 | /* Cast to u64 to make GCC stop complaining */ | ||
1656 | if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
1657 | timeout = -1; /* infinite */ | ||
1658 | else { | ||
1659 | timeout = DIV_ROUND_UP(tv.tv_usec, 1000000/HZ); | ||
1660 | timeout += tv.tv_sec * HZ; | ||
1661 | } | ||
1662 | } | 1657 | } |
1663 | 1658 | ||
1664 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | 1659 | ret = compat_core_sys_select(n, inp, outp, exp, to); |
1665 | 1660 | ret = poll_select_copy_remaining(&end_time, tvp, 1, ret); | |
1666 | if (tvp) { | ||
1667 | struct compat_timeval rtv; | ||
1668 | |||
1669 | if (current->personality & STICKY_TIMEOUTS) | ||
1670 | goto sticky; | ||
1671 | rtv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)); | ||
1672 | rtv.tv_sec = timeout; | ||
1673 | if (compat_timeval_compare(&rtv, &tv) >= 0) | ||
1674 | rtv = tv; | ||
1675 | if (copy_to_user(tvp, &rtv, sizeof(rtv))) { | ||
1676 | sticky: | ||
1677 | /* | ||
1678 | * If an application puts its timeval in read-only | ||
1679 | * memory, we don't want the Linux-specific update to | ||
1680 | * the timeval to cause a fault after the select has | ||
1681 | * completed successfully. However, because we're not | ||
1682 | * updating the timeval, we can't restart the system | ||
1683 | * call. | ||
1684 | */ | ||
1685 | if (ret == -ERESTARTNOHAND) | ||
1686 | ret = -EINTR; | ||
1687 | } | ||
1688 | } | ||
1689 | 1661 | ||
1690 | return ret; | 1662 | return ret; |
1691 | } | 1663 | } |
@@ -1698,15 +1670,16 @@ asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp, | |||
1698 | { | 1670 | { |
1699 | compat_sigset_t ss32; | 1671 | compat_sigset_t ss32; |
1700 | sigset_t ksigmask, sigsaved; | 1672 | sigset_t ksigmask, sigsaved; |
1701 | s64 timeout = MAX_SCHEDULE_TIMEOUT; | ||
1702 | struct compat_timespec ts; | 1673 | struct compat_timespec ts; |
1674 | struct timespec end_time, *to = NULL; | ||
1703 | int ret; | 1675 | int ret; |
1704 | 1676 | ||
1705 | if (tsp) { | 1677 | if (tsp) { |
1706 | if (copy_from_user(&ts, tsp, sizeof(ts))) | 1678 | if (copy_from_user(&ts, tsp, sizeof(ts))) |
1707 | return -EFAULT; | 1679 | return -EFAULT; |
1708 | 1680 | ||
1709 | if (ts.tv_sec < 0 || ts.tv_nsec < 0) | 1681 | to = &end_time; |
1682 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) | ||
1710 | return -EINVAL; | 1683 | return -EINVAL; |
1711 | } | 1684 | } |
1712 | 1685 | ||
@@ -1721,51 +1694,8 @@ asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp, | |||
1721 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | 1694 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
1722 | } | 1695 | } |
1723 | 1696 | ||
1724 | do { | 1697 | ret = compat_core_sys_select(n, inp, outp, exp, to); |
1725 | if (tsp) { | 1698 | ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); |
1726 | if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) { | ||
1727 | timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ); | ||
1728 | timeout += ts.tv_sec * (unsigned long)HZ; | ||
1729 | ts.tv_sec = 0; | ||
1730 | ts.tv_nsec = 0; | ||
1731 | } else { | ||
1732 | ts.tv_sec -= MAX_SELECT_SECONDS; | ||
1733 | timeout = MAX_SELECT_SECONDS * HZ; | ||
1734 | } | ||
1735 | } | ||
1736 | |||
1737 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | ||
1738 | |||
1739 | } while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec)); | ||
1740 | |||
1741 | if (tsp) { | ||
1742 | struct compat_timespec rts; | ||
1743 | |||
1744 | if (current->personality & STICKY_TIMEOUTS) | ||
1745 | goto sticky; | ||
1746 | |||
1747 | rts.tv_sec = timeout / HZ; | ||
1748 | rts.tv_nsec = (timeout % HZ) * (NSEC_PER_SEC/HZ); | ||
1749 | if (rts.tv_nsec >= NSEC_PER_SEC) { | ||
1750 | rts.tv_sec++; | ||
1751 | rts.tv_nsec -= NSEC_PER_SEC; | ||
1752 | } | ||
1753 | if (compat_timespec_compare(&rts, &ts) >= 0) | ||
1754 | rts = ts; | ||
1755 | if (copy_to_user(tsp, &rts, sizeof(rts))) { | ||
1756 | sticky: | ||
1757 | /* | ||
1758 | * If an application puts its timeval in read-only | ||
1759 | * memory, we don't want the Linux-specific update to | ||
1760 | * the timeval to cause a fault after the select has | ||
1761 | * completed successfully. However, because we're not | ||
1762 | * updating the timeval, we can't restart the system | ||
1763 | * call. | ||
1764 | */ | ||
1765 | if (ret == -ERESTARTNOHAND) | ||
1766 | ret = -EINTR; | ||
1767 | } | ||
1768 | } | ||
1769 | 1699 | ||
1770 | if (ret == -ERESTARTNOHAND) { | 1700 | if (ret == -ERESTARTNOHAND) { |
1771 | /* | 1701 | /* |
@@ -1810,18 +1740,16 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | |||
1810 | compat_sigset_t ss32; | 1740 | compat_sigset_t ss32; |
1811 | sigset_t ksigmask, sigsaved; | 1741 | sigset_t ksigmask, sigsaved; |
1812 | struct compat_timespec ts; | 1742 | struct compat_timespec ts; |
1813 | s64 timeout = -1; | 1743 | struct timespec end_time, *to = NULL; |
1814 | int ret; | 1744 | int ret; |
1815 | 1745 | ||
1816 | if (tsp) { | 1746 | if (tsp) { |
1817 | if (copy_from_user(&ts, tsp, sizeof(ts))) | 1747 | if (copy_from_user(&ts, tsp, sizeof(ts))) |
1818 | return -EFAULT; | 1748 | return -EFAULT; |
1819 | 1749 | ||
1820 | /* We assume that ts.tv_sec is always lower than | 1750 | to = &end_time; |
1821 | the number of seconds that can be expressed in | 1751 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) |
1822 | an s64. Otherwise the compiler bitches at us */ | 1752 | return -EINVAL; |
1823 | timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ); | ||
1824 | timeout += ts.tv_sec * HZ; | ||
1825 | } | 1753 | } |
1826 | 1754 | ||
1827 | if (sigmask) { | 1755 | if (sigmask) { |
@@ -1835,7 +1763,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | |||
1835 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | 1763 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
1836 | } | 1764 | } |
1837 | 1765 | ||
1838 | ret = do_sys_poll(ufds, nfds, &timeout); | 1766 | ret = do_sys_poll(ufds, nfds, to); |
1839 | 1767 | ||
1840 | /* We can restart this syscall, usually */ | 1768 | /* We can restart this syscall, usually */ |
1841 | if (ret == -EINTR) { | 1769 | if (ret == -EINTR) { |
@@ -1853,31 +1781,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | |||
1853 | } else if (sigmask) | 1781 | } else if (sigmask) |
1854 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | 1782 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); |
1855 | 1783 | ||
1856 | if (tsp && timeout >= 0) { | 1784 | ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); |
1857 | struct compat_timespec rts; | ||
1858 | |||
1859 | if (current->personality & STICKY_TIMEOUTS) | ||
1860 | goto sticky; | ||
1861 | /* Yes, we know it's actually an s64, but it's also positive. */ | ||
1862 | rts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * | ||
1863 | 1000; | ||
1864 | rts.tv_sec = timeout; | ||
1865 | if (compat_timespec_compare(&rts, &ts) >= 0) | ||
1866 | rts = ts; | ||
1867 | if (copy_to_user(tsp, &rts, sizeof(rts))) { | ||
1868 | sticky: | ||
1869 | /* | ||
1870 | * If an application puts its timeval in read-only | ||
1871 | * memory, we don't want the Linux-specific update to | ||
1872 | * the timeval to cause a fault after the select has | ||
1873 | * completed successfully. However, because we're not | ||
1874 | * updating the timeval, we can't restart the system | ||
1875 | * call. | ||
1876 | */ | ||
1877 | if (ret == -ERESTARTNOHAND && timeout >= 0) | ||
1878 | ret = -EINTR; | ||
1879 | } | ||
1880 | } | ||
1881 | 1785 | ||
1882 | return ret; | 1786 | return ret; |
1883 | } | 1787 | } |