diff options
Diffstat (limited to 'fs/compat.c')
-rw-r--r-- | fs/compat.c | 260 |
1 files changed, 223 insertions, 37 deletions
diff --git a/fs/compat.c b/fs/compat.c index c6ba9deabada..18b21b4c9e3a 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -53,6 +53,8 @@ | |||
53 | #include <asm/mmu_context.h> | 53 | #include <asm/mmu_context.h> |
54 | #include <asm/ioctls.h> | 54 | #include <asm/ioctls.h> |
55 | 55 | ||
56 | extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); | ||
57 | |||
56 | /* | 58 | /* |
57 | * Not all architectures have sys_utime, so implement this in terms | 59 | * Not all architectures have sys_utime, so implement this in terms |
58 | * of sys_utimes. | 60 | * of sys_utimes. |
@@ -1657,36 +1659,14 @@ static void select_bits_free(void *bits, int size) | |||
1657 | #define MAX_SELECT_SECONDS \ | 1659 | #define MAX_SELECT_SECONDS \ |
1658 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | 1660 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) |
1659 | 1661 | ||
1660 | asmlinkage long | 1662 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, |
1661 | compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, | 1663 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout) |
1662 | compat_ulong_t __user *exp, struct compat_timeval __user *tvp) | ||
1663 | { | 1664 | { |
1664 | fd_set_bits fds; | 1665 | fd_set_bits fds; |
1665 | char *bits; | 1666 | char *bits; |
1666 | long timeout; | ||
1667 | int size, max_fdset, ret = -EINVAL; | 1667 | int size, max_fdset, ret = -EINVAL; |
1668 | struct fdtable *fdt; | 1668 | struct fdtable *fdt; |
1669 | 1669 | ||
1670 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
1671 | if (tvp) { | ||
1672 | time_t sec, usec; | ||
1673 | |||
1674 | if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp)) | ||
1675 | || __get_user(sec, &tvp->tv_sec) | ||
1676 | || __get_user(usec, &tvp->tv_usec)) { | ||
1677 | ret = -EFAULT; | ||
1678 | goto out_nofds; | ||
1679 | } | ||
1680 | |||
1681 | if (sec < 0 || usec < 0) | ||
1682 | goto out_nofds; | ||
1683 | |||
1684 | if ((unsigned long) sec < MAX_SELECT_SECONDS) { | ||
1685 | timeout = ROUND_UP(usec, 1000000/HZ); | ||
1686 | timeout += sec * (unsigned long) HZ; | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | if (n < 0) | 1670 | if (n < 0) |
1691 | goto out_nofds; | 1671 | goto out_nofds; |
1692 | 1672 | ||
@@ -1723,19 +1703,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp | |||
1723 | zero_fd_set(n, fds.res_out); | 1703 | zero_fd_set(n, fds.res_out); |
1724 | zero_fd_set(n, fds.res_ex); | 1704 | zero_fd_set(n, fds.res_ex); |
1725 | 1705 | ||
1726 | ret = do_select(n, &fds, &timeout); | 1706 | ret = do_select(n, &fds, timeout); |
1727 | |||
1728 | if (tvp && !(current->personality & STICKY_TIMEOUTS)) { | ||
1729 | time_t sec = 0, usec = 0; | ||
1730 | if (timeout) { | ||
1731 | sec = timeout / HZ; | ||
1732 | usec = timeout % HZ; | ||
1733 | usec *= (1000000/HZ); | ||
1734 | } | ||
1735 | if (put_user(sec, &tvp->tv_sec) || | ||
1736 | put_user(usec, &tvp->tv_usec)) | ||
1737 | ret = -EFAULT; | ||
1738 | } | ||
1739 | 1707 | ||
1740 | if (ret < 0) | 1708 | if (ret < 0) |
1741 | goto out; | 1709 | goto out; |
@@ -1756,6 +1724,224 @@ out_nofds: | |||
1756 | return ret; | 1724 | return ret; |
1757 | } | 1725 | } |
1758 | 1726 | ||
1727 | asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, | ||
1728 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1729 | struct compat_timeval __user *tvp) | ||
1730 | { | ||
1731 | s64 timeout = -1; | ||
1732 | struct compat_timeval tv; | ||
1733 | int ret; | ||
1734 | |||
1735 | if (tvp) { | ||
1736 | if (copy_from_user(&tv, tvp, sizeof(tv))) | ||
1737 | return -EFAULT; | ||
1738 | |||
1739 | if (tv.tv_sec < 0 || tv.tv_usec < 0) | ||
1740 | return -EINVAL; | ||
1741 | |||
1742 | /* Cast to u64 to make GCC stop complaining */ | ||
1743 | if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
1744 | timeout = -1; /* infinite */ | ||
1745 | else { | ||
1746 | timeout = ROUND_UP(tv.tv_sec, 1000000/HZ); | ||
1747 | timeout += tv.tv_sec * HZ; | ||
1748 | } | ||
1749 | } | ||
1750 | |||
1751 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | ||
1752 | |||
1753 | if (tvp) { | ||
1754 | if (current->personality & STICKY_TIMEOUTS) | ||
1755 | goto sticky; | ||
1756 | tv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)); | ||
1757 | tv.tv_sec = timeout; | ||
1758 | if (copy_to_user(tvp, &tv, sizeof(tv))) { | ||
1759 | sticky: | ||
1760 | /* | ||
1761 | * If an application puts its timeval in read-only | ||
1762 | * memory, we don't want the Linux-specific update to | ||
1763 | * the timeval to cause a fault after the select has | ||
1764 | * completed successfully. However, because we're not | ||
1765 | * updating the timeval, we can't restart the system | ||
1766 | * call. | ||
1767 | */ | ||
1768 | if (ret == -ERESTARTNOHAND) | ||
1769 | ret = -EINTR; | ||
1770 | } | ||
1771 | } | ||
1772 | |||
1773 | return ret; | ||
1774 | } | ||
1775 | |||
1776 | #ifdef TIF_RESTORE_SIGMASK | ||
1777 | asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp, | ||
1778 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1779 | struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, | ||
1780 | compat_size_t sigsetsize) | ||
1781 | { | ||
1782 | compat_sigset_t ss32; | ||
1783 | sigset_t ksigmask, sigsaved; | ||
1784 | long timeout = MAX_SCHEDULE_TIMEOUT; | ||
1785 | struct compat_timespec ts; | ||
1786 | int ret; | ||
1787 | |||
1788 | if (tsp) { | ||
1789 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
1790 | return -EFAULT; | ||
1791 | |||
1792 | if (ts.tv_sec < 0 || ts.tv_nsec < 0) | ||
1793 | return -EINVAL; | ||
1794 | } | ||
1795 | |||
1796 | if (sigmask) { | ||
1797 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
1798 | return -EINVAL; | ||
1799 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
1800 | return -EFAULT; | ||
1801 | sigset_from_compat(&ksigmask, &ss32); | ||
1802 | |||
1803 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1804 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1805 | } | ||
1806 | |||
1807 | do { | ||
1808 | if (tsp) { | ||
1809 | if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) { | ||
1810 | timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ); | ||
1811 | timeout += ts.tv_sec * (unsigned long)HZ; | ||
1812 | ts.tv_sec = 0; | ||
1813 | ts.tv_nsec = 0; | ||
1814 | } else { | ||
1815 | ts.tv_sec -= MAX_SELECT_SECONDS; | ||
1816 | timeout = MAX_SELECT_SECONDS * HZ; | ||
1817 | } | ||
1818 | } | ||
1819 | |||
1820 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | ||
1821 | |||
1822 | } while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec)); | ||
1823 | |||
1824 | if (tsp && !(current->personality & STICKY_TIMEOUTS)) { | ||
1825 | ts.tv_sec += timeout / HZ; | ||
1826 | ts.tv_nsec += (timeout % HZ) * (1000000000/HZ); | ||
1827 | if (ts.tv_nsec >= 1000000000) { | ||
1828 | ts.tv_sec++; | ||
1829 | ts.tv_nsec -= 1000000000; | ||
1830 | } | ||
1831 | (void)copy_to_user(tsp, &ts, sizeof(ts)); | ||
1832 | } | ||
1833 | |||
1834 | if (ret == -ERESTARTNOHAND) { | ||
1835 | /* | ||
1836 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1837 | * the signal on the way back to userspace, before the signal | ||
1838 | * mask is restored. | ||
1839 | */ | ||
1840 | if (sigmask) { | ||
1841 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1842 | sizeof(sigsaved)); | ||
1843 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
1844 | } | ||
1845 | } else if (sigmask) | ||
1846 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1847 | |||
1848 | return ret; | ||
1849 | } | ||
1850 | |||
1851 | asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp, | ||
1852 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1853 | struct compat_timespec __user *tsp, void __user *sig) | ||
1854 | { | ||
1855 | compat_size_t sigsetsize = 0; | ||
1856 | compat_uptr_t up = 0; | ||
1857 | |||
1858 | if (sig) { | ||
1859 | if (!access_ok(VERIFY_READ, sig, | ||
1860 | sizeof(compat_uptr_t)+sizeof(compat_size_t)) || | ||
1861 | __get_user(up, (compat_uptr_t __user *)sig) || | ||
1862 | __get_user(sigsetsize, | ||
1863 | (compat_size_t __user *)(sig+sizeof(up)))) | ||
1864 | return -EFAULT; | ||
1865 | } | ||
1866 | return compat_sys_pselect7(n, inp, outp, exp, tsp, compat_ptr(up), | ||
1867 | sigsetsize); | ||
1868 | } | ||
1869 | |||
1870 | asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | ||
1871 | unsigned int nfds, struct compat_timespec __user *tsp, | ||
1872 | const compat_sigset_t __user *sigmask, compat_size_t sigsetsize) | ||
1873 | { | ||
1874 | compat_sigset_t ss32; | ||
1875 | sigset_t ksigmask, sigsaved; | ||
1876 | struct compat_timespec ts; | ||
1877 | s64 timeout = -1; | ||
1878 | int ret; | ||
1879 | |||
1880 | if (tsp) { | ||
1881 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
1882 | return -EFAULT; | ||
1883 | |||
1884 | /* We assume that ts.tv_sec is always lower than | ||
1885 | the number of seconds that can be expressed in | ||
1886 | an s64. Otherwise the compiler bitches at us */ | ||
1887 | timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ); | ||
1888 | timeout += ts.tv_sec * HZ; | ||
1889 | } | ||
1890 | |||
1891 | if (sigmask) { | ||
1892 | if (sigsetsize |= sizeof(compat_sigset_t)) | ||
1893 | return -EINVAL; | ||
1894 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
1895 | return -EFAULT; | ||
1896 | sigset_from_compat(&ksigmask, &ss32); | ||
1897 | |||
1898 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1899 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1900 | } | ||
1901 | |||
1902 | ret = do_sys_poll(ufds, nfds, &timeout); | ||
1903 | |||
1904 | /* We can restart this syscall, usually */ | ||
1905 | if (ret == -EINTR) { | ||
1906 | /* | ||
1907 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1908 | * the signal on the way back to userspace, before the signal | ||
1909 | * mask is restored. | ||
1910 | */ | ||
1911 | if (sigmask) { | ||
1912 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1913 | sizeof(sigsaved)); | ||
1914 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
1915 | } | ||
1916 | ret = -ERESTARTNOHAND; | ||
1917 | } else if (sigmask) | ||
1918 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1919 | |||
1920 | if (tsp && timeout >= 0) { | ||
1921 | if (current->personality & STICKY_TIMEOUTS) | ||
1922 | goto sticky; | ||
1923 | /* Yes, we know it's actually an s64, but it's also positive. */ | ||
1924 | ts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * 1000; | ||
1925 | ts.tv_sec = timeout; | ||
1926 | if (copy_to_user(tsp, &ts, sizeof(ts))) { | ||
1927 | sticky: | ||
1928 | /* | ||
1929 | * If an application puts its timeval in read-only | ||
1930 | * memory, we don't want the Linux-specific update to | ||
1931 | * the timeval to cause a fault after the select has | ||
1932 | * completed successfully. However, because we're not | ||
1933 | * updating the timeval, we can't restart the system | ||
1934 | * call. | ||
1935 | */ | ||
1936 | if (ret == -ERESTARTNOHAND && timeout >= 0) | ||
1937 | ret = -EINTR; | ||
1938 | } | ||
1939 | } | ||
1940 | |||
1941 | return ret; | ||
1942 | } | ||
1943 | #endif /* TIF_RESTORE_SIGMASK */ | ||
1944 | |||
1759 | #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) | 1945 | #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) |
1760 | /* Stuff for NFS server syscalls... */ | 1946 | /* Stuff for NFS server syscalls... */ |
1761 | struct compat_nfsctl_svc { | 1947 | struct compat_nfsctl_svc { |