aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorVasiliy Kulikov <segoon@openwall.com>2011-11-02 16:38:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-02 19:07:00 -0400
commitaa6afca5bcaba8101f3ea09d5c3e4100b2b9f0e5 (patch)
treed8a6fec9d15cbaf37513a18666f5611aa7cb7a83 /fs/proc
parent887df07891de0435c25cffb92268fea2c621f99c (diff)
proc: fix races against execve() of /proc/PID/fd**
fd* files are restricted to the task's owner, and other users may not get direct access to them. But one may open any of these files and run any setuid program, keeping opened file descriptors. As there are permission checks on open(), but not on readdir() and read(), operations on the kept file descriptors will not be checked. It makes it possible to violate procfs permission model. Reading fdinfo/* may disclosure current fds' position and flags, reading directory contents of fdinfo/ and fd/ may disclosure the number of opened files by the target task. This information is not sensible per se, but it can reveal some private information (like length of a password stored in a file) under certain conditions. Used existing (un)lock_trace functions to check for ptrace_may_access(), but instead of using EPERM return code from it use EACCES to be consistent with existing proc_pid_follow_link()/proc_pid_readlink() return code. If they differ, attacker can guess what fds exist by analyzing stat() return code. Patched handlers: stat() for fd/*, stat() and read() for fdindo/*, readdir() and lookup() for fd/ and fdinfo/. Signed-off-by: Vasiliy Kulikov <segoon@openwall.com> Cc: Cyrill Gorcunov <gorcunov@gmail.com> Cc: <stable@kernel.org> Cc: <stable@vger.kernel.org> Signed-off-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.c146
1 files changed, 103 insertions, 43 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 8f0087e20e16..d4f4913f00db 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1652,12 +1652,46 @@ out:
1652 return error; 1652 return error;
1653} 1653}
1654 1654
1655static 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;
1672out_task:
1673 put_task_struct(task);
1674 return rc;
1675}
1676
1655static const struct inode_operations proc_pid_link_inode_operations = { 1677static const struct inode_operations proc_pid_link_inode_operations = {
1656 .readlink = proc_pid_readlink, 1678 .readlink = proc_pid_readlink,
1657 .follow_link = proc_pid_follow_link, 1679 .follow_link = proc_pid_follow_link,
1658 .setattr = proc_setattr, 1680 .setattr = proc_setattr,
1659}; 1681};
1660 1682
1683static const struct inode_operations proc_fdinfo_link_inode_operations = {
1684 .setattr = proc_setattr,
1685 .getattr = proc_pid_fd_link_getattr,
1686};
1687
1688static 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
1661 1695
1662/* building an inode */ 1696/* building an inode */
1663 1697
@@ -1889,49 +1923,61 @@ out:
1889 1923
1890static int proc_fd_info(struct inode *inode, struct path *path, char *info) 1924static int proc_fd_info(struct inode *inode, struct path *path, char *info)
1891{ 1925{
1892 struct task_struct *task = get_proc_task(inode); 1926 struct task_struct *task;
1893 struct files_struct *files = NULL; 1927 struct files_struct *files;
1894 struct file *file; 1928 struct file *file;
1895 int fd = proc_fd(inode); 1929 int fd = proc_fd(inode);
1930 int rc;
1896 1931
1897 if (task) { 1932 task = get_proc_task(inode);
1898 files = get_files_struct(task); 1933 if (!task)
1899 put_task_struct(task); 1934 return -ENOENT;
1900 } 1935
1901 if (files) { 1936 rc = -EACCES;
1902 /* 1937 if (lock_trace(task))
1903 * We are not taking a ref to the file structure, so we must 1938 goto out_task;
1904 * hold ->file_lock. 1939
1905 */ 1940 rc = -ENOENT;
1906 spin_lock(&files->file_lock); 1941 files = get_files_struct(task);
1907 file = fcheck_files(files, fd); 1942 if (files == NULL)
1908 if (file) { 1943 goto out_unlock;
1909 unsigned int f_flags; 1944
1910 struct fdtable *fdt; 1945 /*
1911 1946 * We are not taking a ref to the file structure, so we must
1912 fdt = files_fdtable(files); 1947 * hold ->file_lock.
1913 f_flags = file->f_flags & ~O_CLOEXEC; 1948 */
1914 if (FD_ISSET(fd, fdt->close_on_exec)) 1949 spin_lock(&files->file_lock);
1915 f_flags |= O_CLOEXEC; 1950 file = fcheck_files(files, fd);
1916 1951 if (file) {
1917 if (path) { 1952 unsigned int f_flags;
1918 *path = file->f_path; 1953 struct fdtable *fdt;
1919 path_get(&file->f_path); 1954
1920 } 1955 fdt = files_fdtable(files);
1921 if (info) 1956 f_flags = file->f_flags & ~O_CLOEXEC;
1922 snprintf(info, PROC_FDINFO_MAX, 1957 if (FD_ISSET(fd, fdt->close_on_exec))
1923 "pos:\t%lli\n" 1958 f_flags |= O_CLOEXEC;
1924 "flags:\t0%o\n", 1959
1925 (long long) file->f_pos, 1960 if (path) {
1926 f_flags); 1961 *path = file->f_path;
1927 spin_unlock(&files->file_lock); 1962 path_get(&file->f_path);
1928 put_files_struct(files);
1929 return 0;
1930 } 1963 }
1931 spin_unlock(&files->file_lock); 1964 if (info)
1932 put_files_struct(files); 1965 snprintf(info, PROC_FDINFO_MAX,
1933 } 1966 "pos:\t%lli\n"
1934 return -ENOENT; 1967 "flags:\t0%o\n",
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
1976out_unlock:
1977 unlock_trace(task);
1978out_task:
1979 put_task_struct(task);
1980 return rc;
1935} 1981}
1936 1982
1937static int proc_fd_link(struct inode *inode, struct path *path) 1983static int proc_fd_link(struct inode *inode, struct path *path)
@@ -2026,7 +2072,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
2026 spin_unlock(&files->file_lock); 2072 spin_unlock(&files->file_lock);
2027 put_files_struct(files); 2073 put_files_struct(files);
2028 2074
2029 inode->i_op = &proc_pid_link_inode_operations; 2075 inode->i_op = &proc_fd_link_inode_operations;
2030 inode->i_size = 64; 2076 inode->i_size = 64;
2031 ei->op.proc_get_link = proc_fd_link; 2077 ei->op.proc_get_link = proc_fd_link;
2032 d_set_d_op(dentry, &tid_fd_dentry_operations); 2078 d_set_d_op(dentry, &tid_fd_dentry_operations);
@@ -2058,7 +2104,12 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
2058 if (fd == ~0U) 2104 if (fd == ~0U)
2059 goto out; 2105 goto out;
2060 2106
2107 result = ERR_PTR(-EACCES);
2108 if (lock_trace(task))
2109 goto out;
2110
2061 result = instantiate(dir, dentry, task, &fd); 2111 result = instantiate(dir, dentry, task, &fd);
2112 unlock_trace(task);
2062out: 2113out:
2063 put_task_struct(task); 2114 put_task_struct(task);
2064out_no_task: 2115out_no_task:
@@ -2078,23 +2129,28 @@ static int proc_readfd_common(struct file * filp, void * dirent,
2078 retval = -ENOENT; 2129 retval = -ENOENT;
2079 if (!p) 2130 if (!p)
2080 goto out_no_task; 2131 goto out_no_task;
2132
2133 retval = -EACCES;
2134 if (lock_trace(p))
2135 goto out;
2136
2081 retval = 0; 2137 retval = 0;
2082 2138
2083 fd = filp->f_pos; 2139 fd = filp->f_pos;
2084 switch (fd) { 2140 switch (fd) {
2085 case 0: 2141 case 0:
2086 if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) 2142 if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
2087 goto out; 2143 goto out_unlock;
2088 filp->f_pos++; 2144 filp->f_pos++;
2089 case 1: 2145 case 1:
2090 ino = parent_ino(dentry); 2146 ino = parent_ino(dentry);
2091 if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) 2147 if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
2092 goto out; 2148 goto out_unlock;
2093 filp->f_pos++; 2149 filp->f_pos++;
2094 default: 2150 default:
2095 files = get_files_struct(p); 2151 files = get_files_struct(p);
2096 if (!files) 2152 if (!files)
2097 goto out; 2153 goto out_unlock;
2098 rcu_read_lock(); 2154 rcu_read_lock();
2099 for (fd = filp->f_pos-2; 2155 for (fd = filp->f_pos-2;
2100 fd < files_fdtable(files)->max_fds; 2156 fd < files_fdtable(files)->max_fds;
@@ -2118,6 +2174,9 @@ static int proc_readfd_common(struct file * filp, void * dirent,
2118 rcu_read_unlock(); 2174 rcu_read_unlock();
2119 put_files_struct(files); 2175 put_files_struct(files);
2120 } 2176 }
2177
2178out_unlock:
2179 unlock_trace(p);
2121out: 2180out:
2122 put_task_struct(p); 2181 put_task_struct(p);
2123out_no_task: 2182out_no_task:
@@ -2195,6 +2254,7 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
2195 ei->fd = fd; 2254 ei->fd = fd;
2196 inode->i_mode = S_IFREG | S_IRUSR; 2255 inode->i_mode = S_IFREG | S_IRUSR;
2197 inode->i_fop = &proc_fdinfo_file_operations; 2256 inode->i_fop = &proc_fdinfo_file_operations;
2257 inode->i_op = &proc_fdinfo_link_inode_operations;
2198 d_set_d_op(dentry, &tid_fd_dentry_operations); 2258 d_set_d_op(dentry, &tid_fd_dentry_operations);
2199 d_add(dentry, inode); 2259 d_add(dentry, inode);
2200 /* Close the race of the process dying before we return the dentry */ 2260 /* Close the race of the process dying before we return the dentry */