diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-09 18:16:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-09 18:16:00 -0500 |
commit | 5e442a493fc59fa536c76db1fff5b49ca36a88c5 (patch) | |
tree | 47fb93c6430ac7b598bf3bdd03d1399dd1467fad /fs/proc | |
parent | 19e0bafc36abd84a5b4d7c7745b78a6f4626e944 (diff) |
Revert "proc: fix races against execve() of /proc/PID/fd**"
This reverts commit aa6afca5bcaba8101f3ea09d5c3e4100b2b9f0e5.
It escalates of some of the google-chrome SELinux problems with ptrace
("Check failed: pid_ > 0. Did not find zygote process"), and Andrew
says that it is also causing mystery lockdep reports.
Reported-by: Alex VillacĂs Lasso <a_villacis@palosanto.com>
Requested-by: James Morris <jmorris@namei.org>
Requested-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 146 |
1 files changed, 43 insertions, 103 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 2db1bd3173b2..851ba3dcdc29 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1652,46 +1652,12 @@ out: | |||
1652 | return error; | 1652 | return error; |
1653 | } | 1653 | } |
1654 | 1654 | ||
1655 | static int proc_pid_fd_link_getattr(struct vfsmount *mnt, struct dentry *dentry, | ||
1656 | struct kstat *stat) | ||
1657 | { | ||
1658 | struct inode *inode = dentry->d_inode; | ||
1659 | struct task_struct *task = get_proc_task(inode); | ||
1660 | int rc; | ||
1661 | |||
1662 | if (task == NULL) | ||
1663 | return -ESRCH; | ||
1664 | |||
1665 | rc = -EACCES; | ||
1666 | if (lock_trace(task)) | ||
1667 | goto out_task; | ||
1668 | |||
1669 | generic_fillattr(inode, stat); | ||
1670 | unlock_trace(task); | ||
1671 | rc = 0; | ||
1672 | out_task: | ||
1673 | put_task_struct(task); | ||
1674 | return rc; | ||
1675 | } | ||
1676 | |||
1677 | static const struct inode_operations proc_pid_link_inode_operations = { | 1655 | static const struct inode_operations proc_pid_link_inode_operations = { |
1678 | .readlink = proc_pid_readlink, | 1656 | .readlink = proc_pid_readlink, |
1679 | .follow_link = proc_pid_follow_link, | 1657 | .follow_link = proc_pid_follow_link, |
1680 | .setattr = proc_setattr, | 1658 | .setattr = proc_setattr, |
1681 | }; | 1659 | }; |
1682 | 1660 | ||
1683 | static const struct inode_operations proc_fdinfo_link_inode_operations = { | ||
1684 | .setattr = proc_setattr, | ||
1685 | .getattr = proc_pid_fd_link_getattr, | ||
1686 | }; | ||
1687 | |||
1688 | static const struct inode_operations proc_fd_link_inode_operations = { | ||
1689 | .readlink = proc_pid_readlink, | ||
1690 | .follow_link = proc_pid_follow_link, | ||
1691 | .setattr = proc_setattr, | ||
1692 | .getattr = proc_pid_fd_link_getattr, | ||
1693 | }; | ||
1694 | |||
1695 | 1661 | ||
1696 | /* building an inode */ | 1662 | /* building an inode */ |
1697 | 1663 | ||
@@ -1923,61 +1889,49 @@ out: | |||
1923 | 1889 | ||
1924 | static int proc_fd_info(struct inode *inode, struct path *path, char *info) | 1890 | static int proc_fd_info(struct inode *inode, struct path *path, char *info) |
1925 | { | 1891 | { |
1926 | struct task_struct *task; | 1892 | struct task_struct *task = get_proc_task(inode); |
1927 | struct files_struct *files; | 1893 | struct files_struct *files = NULL; |
1928 | struct file *file; | 1894 | struct file *file; |
1929 | int fd = proc_fd(inode); | 1895 | int fd = proc_fd(inode); |
1930 | int rc; | ||
1931 | |||
1932 | task = get_proc_task(inode); | ||
1933 | if (!task) | ||
1934 | return -ENOENT; | ||
1935 | |||
1936 | rc = -EACCES; | ||
1937 | if (lock_trace(task)) | ||
1938 | goto out_task; | ||
1939 | |||
1940 | rc = -ENOENT; | ||
1941 | files = get_files_struct(task); | ||
1942 | if (files == NULL) | ||
1943 | goto out_unlock; | ||
1944 | 1896 | ||
1945 | /* | 1897 | if (task) { |
1946 | * We are not taking a ref to the file structure, so we must | 1898 | files = get_files_struct(task); |
1947 | * hold ->file_lock. | 1899 | put_task_struct(task); |
1948 | */ | 1900 | } |
1949 | spin_lock(&files->file_lock); | 1901 | if (files) { |
1950 | file = fcheck_files(files, fd); | 1902 | /* |
1951 | if (file) { | 1903 | * We are not taking a ref to the file structure, so we must |
1952 | unsigned int f_flags; | 1904 | * hold ->file_lock. |
1953 | struct fdtable *fdt; | 1905 | */ |
1954 | 1906 | spin_lock(&files->file_lock); | |
1955 | fdt = files_fdtable(files); | 1907 | file = fcheck_files(files, fd); |
1956 | f_flags = file->f_flags & ~O_CLOEXEC; | 1908 | if (file) { |
1957 | if (FD_ISSET(fd, fdt->close_on_exec)) | 1909 | unsigned int f_flags; |
1958 | f_flags |= O_CLOEXEC; | 1910 | struct fdtable *fdt; |
1959 | 1911 | ||
1960 | if (path) { | 1912 | fdt = files_fdtable(files); |
1961 | *path = file->f_path; | 1913 | f_flags = file->f_flags & ~O_CLOEXEC; |
1962 | path_get(&file->f_path); | 1914 | if (FD_ISSET(fd, fdt->close_on_exec)) |
1915 | f_flags |= O_CLOEXEC; | ||
1916 | |||
1917 | if (path) { | ||
1918 | *path = file->f_path; | ||
1919 | path_get(&file->f_path); | ||
1920 | } | ||
1921 | if (info) | ||
1922 | snprintf(info, PROC_FDINFO_MAX, | ||
1923 | "pos:\t%lli\n" | ||
1924 | "flags:\t0%o\n", | ||
1925 | (long long) file->f_pos, | ||
1926 | f_flags); | ||
1927 | spin_unlock(&files->file_lock); | ||
1928 | put_files_struct(files); | ||
1929 | return 0; | ||
1963 | } | 1930 | } |
1964 | if (info) | 1931 | spin_unlock(&files->file_lock); |
1965 | snprintf(info, PROC_FDINFO_MAX, | 1932 | put_files_struct(files); |
1966 | "pos:\t%lli\n" | 1933 | } |
1967 | "flags:\t0%o\n", | 1934 | return -ENOENT; |
1968 | (long long) file->f_pos, | ||
1969 | f_flags); | ||
1970 | rc = 0; | ||
1971 | } else | ||
1972 | rc = -ENOENT; | ||
1973 | spin_unlock(&files->file_lock); | ||
1974 | put_files_struct(files); | ||
1975 | |||
1976 | out_unlock: | ||
1977 | unlock_trace(task); | ||
1978 | out_task: | ||
1979 | put_task_struct(task); | ||
1980 | return rc; | ||
1981 | } | 1935 | } |
1982 | 1936 | ||
1983 | static int proc_fd_link(struct inode *inode, struct path *path) | 1937 | static int proc_fd_link(struct inode *inode, struct path *path) |
@@ -2072,7 +2026,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir, | |||
2072 | spin_unlock(&files->file_lock); | 2026 | spin_unlock(&files->file_lock); |
2073 | put_files_struct(files); | 2027 | put_files_struct(files); |
2074 | 2028 | ||
2075 | inode->i_op = &proc_fd_link_inode_operations; | 2029 | inode->i_op = &proc_pid_link_inode_operations; |
2076 | inode->i_size = 64; | 2030 | inode->i_size = 64; |
2077 | ei->op.proc_get_link = proc_fd_link; | 2031 | ei->op.proc_get_link = proc_fd_link; |
2078 | d_set_d_op(dentry, &tid_fd_dentry_operations); | 2032 | d_set_d_op(dentry, &tid_fd_dentry_operations); |
@@ -2104,12 +2058,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir, | |||
2104 | if (fd == ~0U) | 2058 | if (fd == ~0U) |
2105 | goto out; | 2059 | goto out; |
2106 | 2060 | ||
2107 | result = ERR_PTR(-EACCES); | ||
2108 | if (lock_trace(task)) | ||
2109 | goto out; | ||
2110 | |||
2111 | result = instantiate(dir, dentry, task, &fd); | 2061 | result = instantiate(dir, dentry, task, &fd); |
2112 | unlock_trace(task); | ||
2113 | out: | 2062 | out: |
2114 | put_task_struct(task); | 2063 | put_task_struct(task); |
2115 | out_no_task: | 2064 | out_no_task: |
@@ -2129,28 +2078,23 @@ static int proc_readfd_common(struct file * filp, void * dirent, | |||
2129 | retval = -ENOENT; | 2078 | retval = -ENOENT; |
2130 | if (!p) | 2079 | if (!p) |
2131 | goto out_no_task; | 2080 | goto out_no_task; |
2132 | |||
2133 | retval = -EACCES; | ||
2134 | if (lock_trace(p)) | ||
2135 | goto out; | ||
2136 | |||
2137 | retval = 0; | 2081 | retval = 0; |
2138 | 2082 | ||
2139 | fd = filp->f_pos; | 2083 | fd = filp->f_pos; |
2140 | switch (fd) { | 2084 | switch (fd) { |
2141 | case 0: | 2085 | case 0: |
2142 | if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) | 2086 | if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) |
2143 | goto out_unlock; | 2087 | goto out; |
2144 | filp->f_pos++; | 2088 | filp->f_pos++; |
2145 | case 1: | 2089 | case 1: |
2146 | ino = parent_ino(dentry); | 2090 | ino = parent_ino(dentry); |
2147 | if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) | 2091 | if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) |
2148 | goto out_unlock; | 2092 | goto out; |
2149 | filp->f_pos++; | 2093 | filp->f_pos++; |
2150 | default: | 2094 | default: |
2151 | files = get_files_struct(p); | 2095 | files = get_files_struct(p); |
2152 | if (!files) | 2096 | if (!files) |
2153 | goto out_unlock; | 2097 | goto out; |
2154 | rcu_read_lock(); | 2098 | rcu_read_lock(); |
2155 | for (fd = filp->f_pos-2; | 2099 | for (fd = filp->f_pos-2; |
2156 | fd < files_fdtable(files)->max_fds; | 2100 | fd < files_fdtable(files)->max_fds; |
@@ -2174,9 +2118,6 @@ static int proc_readfd_common(struct file * filp, void * dirent, | |||
2174 | rcu_read_unlock(); | 2118 | rcu_read_unlock(); |
2175 | put_files_struct(files); | 2119 | put_files_struct(files); |
2176 | } | 2120 | } |
2177 | |||
2178 | out_unlock: | ||
2179 | unlock_trace(p); | ||
2180 | out: | 2121 | out: |
2181 | put_task_struct(p); | 2122 | put_task_struct(p); |
2182 | out_no_task: | 2123 | out_no_task: |
@@ -2254,7 +2195,6 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir, | |||
2254 | ei->fd = fd; | 2195 | ei->fd = fd; |
2255 | inode->i_mode = S_IFREG | S_IRUSR; | 2196 | inode->i_mode = S_IFREG | S_IRUSR; |
2256 | inode->i_fop = &proc_fdinfo_file_operations; | 2197 | inode->i_fop = &proc_fdinfo_file_operations; |
2257 | inode->i_op = &proc_fdinfo_link_inode_operations; | ||
2258 | d_set_d_op(dentry, &tid_fd_dentry_operations); | 2198 | d_set_d_op(dentry, &tid_fd_dentry_operations); |
2259 | d_add(dentry, inode); | 2199 | d_add(dentry, inode); |
2260 | /* Close the race of the process dying before we return the dentry */ | 2200 | /* Close the race of the process dying before we return the dentry */ |