diff options
Diffstat (limited to 'fs/compat.c')
-rw-r--r-- | fs/compat.c | 210 |
1 files changed, 80 insertions, 130 deletions
diff --git a/fs/compat.c b/fs/compat.c index 5f9ec449c79..e5f49f53850 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -869,7 +869,7 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd, | |||
869 | buf.dirent = dirent; | 869 | buf.dirent = dirent; |
870 | 870 | ||
871 | error = vfs_readdir(file, compat_fillonedir, &buf); | 871 | error = vfs_readdir(file, compat_fillonedir, &buf); |
872 | if (error >= 0) | 872 | if (buf.result) |
873 | error = buf.result; | 873 | error = buf.result; |
874 | 874 | ||
875 | fput(file); | 875 | fput(file); |
@@ -956,9 +956,8 @@ asmlinkage long compat_sys_getdents(unsigned int fd, | |||
956 | buf.error = 0; | 956 | buf.error = 0; |
957 | 957 | ||
958 | error = vfs_readdir(file, compat_filldir, &buf); | 958 | error = vfs_readdir(file, compat_filldir, &buf); |
959 | if (error < 0) | 959 | if (error >= 0) |
960 | goto out_putf; | 960 | error = buf.error; |
961 | error = buf.error; | ||
962 | lastdirent = buf.previous; | 961 | lastdirent = buf.previous; |
963 | if (lastdirent) { | 962 | if (lastdirent) { |
964 | if (put_user(file->f_pos, &lastdirent->d_off)) | 963 | if (put_user(file->f_pos, &lastdirent->d_off)) |
@@ -966,8 +965,6 @@ asmlinkage long compat_sys_getdents(unsigned int fd, | |||
966 | else | 965 | else |
967 | error = count - buf.count; | 966 | error = count - buf.count; |
968 | } | 967 | } |
969 | |||
970 | out_putf: | ||
971 | fput(file); | 968 | fput(file); |
972 | out: | 969 | out: |
973 | return error; | 970 | return error; |
@@ -1047,19 +1044,16 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, | |||
1047 | buf.error = 0; | 1044 | buf.error = 0; |
1048 | 1045 | ||
1049 | error = vfs_readdir(file, compat_filldir64, &buf); | 1046 | error = vfs_readdir(file, compat_filldir64, &buf); |
1050 | if (error < 0) | 1047 | if (error >= 0) |
1051 | goto out_putf; | 1048 | error = buf.error; |
1052 | error = buf.error; | ||
1053 | lastdirent = buf.previous; | 1049 | lastdirent = buf.previous; |
1054 | if (lastdirent) { | 1050 | if (lastdirent) { |
1055 | typeof(lastdirent->d_off) d_off = file->f_pos; | 1051 | typeof(lastdirent->d_off) d_off = file->f_pos; |
1056 | error = -EFAULT; | ||
1057 | if (__put_user_unaligned(d_off, &lastdirent->d_off)) | 1052 | if (__put_user_unaligned(d_off, &lastdirent->d_off)) |
1058 | goto out_putf; | 1053 | error = -EFAULT; |
1059 | error = count - buf.count; | 1054 | else |
1055 | error = count - buf.count; | ||
1060 | } | 1056 | } |
1061 | |||
1062 | out_putf: | ||
1063 | fput(file); | 1057 | fput(file); |
1064 | out: | 1058 | out: |
1065 | return error; | 1059 | return error; |
@@ -1475,6 +1469,57 @@ out_ret: | |||
1475 | 1469 | ||
1476 | #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) | 1470 | #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) |
1477 | 1471 | ||
1472 | static int poll_select_copy_remaining(struct timespec *end_time, void __user *p, | ||
1473 | int timeval, int ret) | ||
1474 | { | ||
1475 | struct timespec ts; | ||
1476 | |||
1477 | if (!p) | ||
1478 | return ret; | ||
1479 | |||
1480 | if (current->personality & STICKY_TIMEOUTS) | ||
1481 | goto sticky; | ||
1482 | |||
1483 | /* No update for zero timeout */ | ||
1484 | if (!end_time->tv_sec && !end_time->tv_nsec) | ||
1485 | return ret; | ||
1486 | |||
1487 | ktime_get_ts(&ts); | ||
1488 | ts = timespec_sub(*end_time, ts); | ||
1489 | if (ts.tv_sec < 0) | ||
1490 | ts.tv_sec = ts.tv_nsec = 0; | ||
1491 | |||
1492 | if (timeval) { | ||
1493 | struct compat_timeval rtv; | ||
1494 | |||
1495 | rtv.tv_sec = ts.tv_sec; | ||
1496 | rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC; | ||
1497 | |||
1498 | if (!copy_to_user(p, &rtv, sizeof(rtv))) | ||
1499 | return ret; | ||
1500 | } else { | ||
1501 | struct compat_timespec rts; | ||
1502 | |||
1503 | rts.tv_sec = ts.tv_sec; | ||
1504 | rts.tv_nsec = ts.tv_nsec; | ||
1505 | |||
1506 | if (!copy_to_user(p, &rts, sizeof(rts))) | ||
1507 | return ret; | ||
1508 | } | ||
1509 | /* | ||
1510 | * If an application puts its timeval in read-only memory, we | ||
1511 | * don't want the Linux-specific update to the timeval to | ||
1512 | * cause a fault after the select has completed | ||
1513 | * successfully. However, because we're not updating the | ||
1514 | * timeval, we can't restart the system call. | ||
1515 | */ | ||
1516 | |||
1517 | sticky: | ||
1518 | if (ret == -ERESTARTNOHAND) | ||
1519 | ret = -EINTR; | ||
1520 | return ret; | ||
1521 | } | ||
1522 | |||
1478 | /* | 1523 | /* |
1479 | * Ooo, nasty. We need here to frob 32-bit unsigned longs to | 1524 | * Ooo, nasty. We need here to frob 32-bit unsigned longs to |
1480 | * 64-bit unsigned longs. | 1525 | * 64-bit unsigned longs. |
@@ -1556,7 +1601,8 @@ int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | |||
1556 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | 1601 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) |
1557 | 1602 | ||
1558 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, | 1603 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, |
1559 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout) | 1604 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, |
1605 | struct timespec *end_time) | ||
1560 | { | 1606 | { |
1561 | fd_set_bits fds; | 1607 | fd_set_bits fds; |
1562 | void *bits; | 1608 | void *bits; |
@@ -1603,7 +1649,7 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp, | |||
1603 | zero_fd_set(n, fds.res_out); | 1649 | zero_fd_set(n, fds.res_out); |
1604 | zero_fd_set(n, fds.res_ex); | 1650 | zero_fd_set(n, fds.res_ex); |
1605 | 1651 | ||
1606 | ret = do_select(n, &fds, timeout); | 1652 | ret = do_select(n, &fds, end_time); |
1607 | 1653 | ||
1608 | if (ret < 0) | 1654 | if (ret < 0) |
1609 | goto out; | 1655 | goto out; |
@@ -1629,7 +1675,7 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, | |||
1629 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | 1675 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, |
1630 | struct compat_timeval __user *tvp) | 1676 | struct compat_timeval __user *tvp) |
1631 | { | 1677 | { |
1632 | s64 timeout = -1; | 1678 | struct timespec end_time, *to = NULL; |
1633 | struct compat_timeval tv; | 1679 | struct compat_timeval tv; |
1634 | int ret; | 1680 | int ret; |
1635 | 1681 | ||
@@ -1637,43 +1683,15 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, | |||
1637 | if (copy_from_user(&tv, tvp, sizeof(tv))) | 1683 | if (copy_from_user(&tv, tvp, sizeof(tv))) |
1638 | return -EFAULT; | 1684 | return -EFAULT; |
1639 | 1685 | ||
1640 | if (tv.tv_sec < 0 || tv.tv_usec < 0) | 1686 | to = &end_time; |
1687 | if (poll_select_set_timeout(to, | ||
1688 | tv.tv_sec + (tv.tv_usec / USEC_PER_SEC), | ||
1689 | (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC)) | ||
1641 | return -EINVAL; | 1690 | return -EINVAL; |
1642 | |||
1643 | /* Cast to u64 to make GCC stop complaining */ | ||
1644 | if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
1645 | timeout = -1; /* infinite */ | ||
1646 | else { | ||
1647 | timeout = DIV_ROUND_UP(tv.tv_usec, 1000000/HZ); | ||
1648 | timeout += tv.tv_sec * HZ; | ||
1649 | } | ||
1650 | } | 1691 | } |
1651 | 1692 | ||
1652 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | 1693 | ret = compat_core_sys_select(n, inp, outp, exp, to); |
1653 | 1694 | ret = poll_select_copy_remaining(&end_time, tvp, 1, ret); | |
1654 | if (tvp) { | ||
1655 | struct compat_timeval rtv; | ||
1656 | |||
1657 | if (current->personality & STICKY_TIMEOUTS) | ||
1658 | goto sticky; | ||
1659 | rtv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)); | ||
1660 | rtv.tv_sec = timeout; | ||
1661 | if (compat_timeval_compare(&rtv, &tv) >= 0) | ||
1662 | rtv = tv; | ||
1663 | if (copy_to_user(tvp, &rtv, sizeof(rtv))) { | ||
1664 | sticky: | ||
1665 | /* | ||
1666 | * If an application puts its timeval in read-only | ||
1667 | * memory, we don't want the Linux-specific update to | ||
1668 | * the timeval to cause a fault after the select has | ||
1669 | * completed successfully. However, because we're not | ||
1670 | * updating the timeval, we can't restart the system | ||
1671 | * call. | ||
1672 | */ | ||
1673 | if (ret == -ERESTARTNOHAND) | ||
1674 | ret = -EINTR; | ||
1675 | } | ||
1676 | } | ||
1677 | 1695 | ||
1678 | return ret; | 1696 | return ret; |
1679 | } | 1697 | } |
@@ -1686,15 +1704,16 @@ asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp, | |||
1686 | { | 1704 | { |
1687 | compat_sigset_t ss32; | 1705 | compat_sigset_t ss32; |
1688 | sigset_t ksigmask, sigsaved; | 1706 | sigset_t ksigmask, sigsaved; |
1689 | s64 timeout = MAX_SCHEDULE_TIMEOUT; | ||
1690 | struct compat_timespec ts; | 1707 | struct compat_timespec ts; |
1708 | struct timespec end_time, *to = NULL; | ||
1691 | int ret; | 1709 | int ret; |
1692 | 1710 | ||
1693 | if (tsp) { | 1711 | if (tsp) { |
1694 | if (copy_from_user(&ts, tsp, sizeof(ts))) | 1712 | if (copy_from_user(&ts, tsp, sizeof(ts))) |
1695 | return -EFAULT; | 1713 | return -EFAULT; |
1696 | 1714 | ||
1697 | if (ts.tv_sec < 0 || ts.tv_nsec < 0) | 1715 | to = &end_time; |
1716 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) | ||
1698 | return -EINVAL; | 1717 | return -EINVAL; |
1699 | } | 1718 | } |
1700 | 1719 | ||
@@ -1709,51 +1728,8 @@ asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp, | |||
1709 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | 1728 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
1710 | } | 1729 | } |
1711 | 1730 | ||
1712 | do { | 1731 | ret = compat_core_sys_select(n, inp, outp, exp, to); |
1713 | if (tsp) { | 1732 | ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); |
1714 | if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) { | ||
1715 | timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ); | ||
1716 | timeout += ts.tv_sec * (unsigned long)HZ; | ||
1717 | ts.tv_sec = 0; | ||
1718 | ts.tv_nsec = 0; | ||
1719 | } else { | ||
1720 | ts.tv_sec -= MAX_SELECT_SECONDS; | ||
1721 | timeout = MAX_SELECT_SECONDS * HZ; | ||
1722 | } | ||
1723 | } | ||
1724 | |||
1725 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | ||
1726 | |||
1727 | } while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec)); | ||
1728 | |||
1729 | if (tsp) { | ||
1730 | struct compat_timespec rts; | ||
1731 | |||
1732 | if (current->personality & STICKY_TIMEOUTS) | ||
1733 | goto sticky; | ||
1734 | |||
1735 | rts.tv_sec = timeout / HZ; | ||
1736 | rts.tv_nsec = (timeout % HZ) * (NSEC_PER_SEC/HZ); | ||
1737 | if (rts.tv_nsec >= NSEC_PER_SEC) { | ||
1738 | rts.tv_sec++; | ||
1739 | rts.tv_nsec -= NSEC_PER_SEC; | ||
1740 | } | ||
1741 | if (compat_timespec_compare(&rts, &ts) >= 0) | ||
1742 | rts = ts; | ||
1743 | if (copy_to_user(tsp, &rts, sizeof(rts))) { | ||
1744 | sticky: | ||
1745 | /* | ||
1746 | * If an application puts its timeval in read-only | ||
1747 | * memory, we don't want the Linux-specific update to | ||
1748 | * the timeval to cause a fault after the select has | ||
1749 | * completed successfully. However, because we're not | ||
1750 | * updating the timeval, we can't restart the system | ||
1751 | * call. | ||
1752 | */ | ||
1753 | if (ret == -ERESTARTNOHAND) | ||
1754 | ret = -EINTR; | ||
1755 | } | ||
1756 | } | ||
1757 | 1733 | ||
1758 | if (ret == -ERESTARTNOHAND) { | 1734 | if (ret == -ERESTARTNOHAND) { |
1759 | /* | 1735 | /* |
@@ -1798,18 +1774,16 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | |||
1798 | compat_sigset_t ss32; | 1774 | compat_sigset_t ss32; |
1799 | sigset_t ksigmask, sigsaved; | 1775 | sigset_t ksigmask, sigsaved; |
1800 | struct compat_timespec ts; | 1776 | struct compat_timespec ts; |
1801 | s64 timeout = -1; | 1777 | struct timespec end_time, *to = NULL; |
1802 | int ret; | 1778 | int ret; |
1803 | 1779 | ||
1804 | if (tsp) { | 1780 | if (tsp) { |
1805 | if (copy_from_user(&ts, tsp, sizeof(ts))) | 1781 | if (copy_from_user(&ts, tsp, sizeof(ts))) |
1806 | return -EFAULT; | 1782 | return -EFAULT; |
1807 | 1783 | ||
1808 | /* We assume that ts.tv_sec is always lower than | 1784 | to = &end_time; |
1809 | the number of seconds that can be expressed in | 1785 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) |
1810 | an s64. Otherwise the compiler bitches at us */ | 1786 | return -EINVAL; |
1811 | timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ); | ||
1812 | timeout += ts.tv_sec * HZ; | ||
1813 | } | 1787 | } |
1814 | 1788 | ||
1815 | if (sigmask) { | 1789 | if (sigmask) { |
@@ -1823,7 +1797,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | |||
1823 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | 1797 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
1824 | } | 1798 | } |
1825 | 1799 | ||
1826 | ret = do_sys_poll(ufds, nfds, &timeout); | 1800 | ret = do_sys_poll(ufds, nfds, to); |
1827 | 1801 | ||
1828 | /* We can restart this syscall, usually */ | 1802 | /* We can restart this syscall, usually */ |
1829 | if (ret == -EINTR) { | 1803 | if (ret == -EINTR) { |
@@ -1841,31 +1815,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | |||
1841 | } else if (sigmask) | 1815 | } else if (sigmask) |
1842 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | 1816 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); |
1843 | 1817 | ||
1844 | if (tsp && timeout >= 0) { | 1818 | ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); |
1845 | struct compat_timespec rts; | ||
1846 | |||
1847 | if (current->personality & STICKY_TIMEOUTS) | ||
1848 | goto sticky; | ||
1849 | /* Yes, we know it's actually an s64, but it's also positive. */ | ||
1850 | rts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * | ||
1851 | 1000; | ||
1852 | rts.tv_sec = timeout; | ||
1853 | if (compat_timespec_compare(&rts, &ts) >= 0) | ||
1854 | rts = ts; | ||
1855 | if (copy_to_user(tsp, &rts, sizeof(rts))) { | ||
1856 | sticky: | ||
1857 | /* | ||
1858 | * If an application puts its timeval in read-only | ||
1859 | * memory, we don't want the Linux-specific update to | ||
1860 | * the timeval to cause a fault after the select has | ||
1861 | * completed successfully. However, because we're not | ||
1862 | * updating the timeval, we can't restart the system | ||
1863 | * call. | ||
1864 | */ | ||
1865 | if (ret == -ERESTARTNOHAND && timeout >= 0) | ||
1866 | ret = -EINTR; | ||
1867 | } | ||
1868 | } | ||
1869 | 1819 | ||
1870 | return ret; | 1820 | return ret; |
1871 | } | 1821 | } |