updated on Wed Jan 25 08:34:36 UTC 2012
[aur-mirror.git] / linux-fbcondecor / CVE-2012-0056.patch
blob6a83fef1c7877c2f637c594bde3ebd342ae5eb90
1 From e268337dfe26dfc7efd422a804dbb27977a3cccc Mon Sep 17 00:00:00 2001
2 From: Linus Torvalds <torvalds@linux-foundation.org>
3 Date: Tue, 17 Jan 2012 15:21:19 -0800
4 Subject: [PATCH] proc: clean up and fix /proc/<pid>/mem handling
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=utf8
7 Content-Transfer-Encoding: 8bit
9 Jüri Aedla reported that the /proc/<pid>/mem handling really isn't very
10 robust, and it also doesn't match the permission checking of any of the
11 other related files.
13 This changes it to do the permission checks at open time, and instead of
14 tracking the process, it tracks the VM at the time of the open. That
15 simplifies the code a lot, but does mean that if you hold the file
16 descriptor open over an execve(), you'll continue to read from the _old_
17 VM.
19 That is different from our previous behavior, but much simpler. If
20 somebody actually finds a load where this matters, we'll need to revert
21 this commit.
23 I suspect that nobody will ever notice - because the process mapping
24 addresses will also have changed as part of the execve. So you cannot
25 actually usefully access the fd across a VM change simply because all
26 the offsets for IO would have changed too.
28 Reported-by: Jüri Aedla <asd@ut.ee>
29 Cc: Al Viro <viro@zeniv.linux.org.uk>
30 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
31 ---
32 fs/proc/base.c | 145 +++++++++++++++-----------------------------------------
33 1 files changed, 39 insertions(+), 106 deletions(-)
35 diff --git a/fs/proc/base.c b/fs/proc/base.c
36 index 5485a53..662ddf2 100644
37 --- a/fs/proc/base.c
38 +++ b/fs/proc/base.c
39 @@ -198,65 +198,7 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
40 return result;
43 -static struct mm_struct *__check_mem_permission(struct task_struct *task)
45 - struct mm_struct *mm;
47 - mm = get_task_mm(task);
48 - if (!mm)
49 - return ERR_PTR(-EINVAL);
51 - /*
52 - * A task can always look at itself, in case it chooses
53 - * to use system calls instead of load instructions.
54 - */
55 - if (task == current)
56 - return mm;
58 - /*
59 - * If current is actively ptrace'ing, and would also be
60 - * permitted to freshly attach with ptrace now, permit it.
61 - */
62 - if (task_is_stopped_or_traced(task)) {
63 - int match;
64 - rcu_read_lock();
65 - match = (ptrace_parent(task) == current);
66 - rcu_read_unlock();
67 - if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
68 - return mm;
69 - }
71 - /*
72 - * No one else is allowed.
73 - */
74 - mmput(mm);
75 - return ERR_PTR(-EPERM);
78 -/*
79 - * If current may access user memory in @task return a reference to the
80 - * corresponding mm, otherwise ERR_PTR.
81 - */
82 -static struct mm_struct *check_mem_permission(struct task_struct *task)
84 - struct mm_struct *mm;
85 - int err;
87 - /*
88 - * Avoid racing if task exec's as we might get a new mm but validate
89 - * against old credentials.
90 - */
91 - err = mutex_lock_killable(&task->signal->cred_guard_mutex);
92 - if (err)
93 - return ERR_PTR(err);
95 - mm = __check_mem_permission(task);
96 - mutex_unlock(&task->signal->cred_guard_mutex);
98 - return mm;
101 -struct mm_struct *mm_for_maps(struct task_struct *task)
102 +static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
104 struct mm_struct *mm;
105 int err;
106 @@ -267,7 +209,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
108 mm = get_task_mm(task);
109 if (mm && mm != current->mm &&
110 - !ptrace_may_access(task, PTRACE_MODE_READ)) {
111 + !ptrace_may_access(task, mode)) {
112 mmput(mm);
113 mm = ERR_PTR(-EACCES);
115 @@ -276,6 +218,11 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
116 return mm;
119 +struct mm_struct *mm_for_maps(struct task_struct *task)
121 + return mm_access(task, PTRACE_MODE_READ);
124 static int proc_pid_cmdline(struct task_struct *task, char * buffer)
126 int res = 0;
127 @@ -752,38 +699,39 @@ static const struct file_operations proc_single_file_operations = {
129 static int mem_open(struct inode* inode, struct file* file)
131 - file->private_data = (void*)((long)current->self_exec_id);
132 + struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
133 + struct mm_struct *mm;
135 + if (!task)
136 + return -ESRCH;
138 + mm = mm_access(task, PTRACE_MODE_ATTACH);
139 + put_task_struct(task);
141 + if (IS_ERR(mm))
142 + return PTR_ERR(mm);
144 /* OK to pass negative loff_t, we can catch out-of-range */
145 file->f_mode |= FMODE_UNSIGNED_OFFSET;
146 + file->private_data = mm;
148 return 0;
151 static ssize_t mem_read(struct file * file, char __user * buf,
152 size_t count, loff_t *ppos)
154 - struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
155 + int ret;
156 char *page;
157 unsigned long src = *ppos;
158 - int ret = -ESRCH;
159 - struct mm_struct *mm;
160 + struct mm_struct *mm = file->private_data;
162 - if (!task)
163 - goto out_no_task;
164 + if (!mm)
165 + return 0;
167 - ret = -ENOMEM;
168 page = (char *)__get_free_page(GFP_TEMPORARY);
169 if (!page)
170 - goto out;
172 - mm = check_mem_permission(task);
173 - ret = PTR_ERR(mm);
174 - if (IS_ERR(mm))
175 - goto out_free;
177 - ret = -EIO;
179 - if (file->private_data != (void*)((long)current->self_exec_id))
180 - goto out_put;
181 + return -ENOMEM;
183 ret = 0;
185 @@ -810,13 +758,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
187 *ppos = src;
189 -out_put:
190 - mmput(mm);
191 -out_free:
192 free_page((unsigned long) page);
193 -out:
194 - put_task_struct(task);
195 -out_no_task:
196 return ret;
199 @@ -825,27 +767,15 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
201 int copied;
202 char *page;
203 - struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
204 unsigned long dst = *ppos;
205 - struct mm_struct *mm;
206 + struct mm_struct *mm = file->private_data;
208 - copied = -ESRCH;
209 - if (!task)
210 - goto out_no_task;
211 + if (!mm)
212 + return 0;
214 - copied = -ENOMEM;
215 page = (char *)__get_free_page(GFP_TEMPORARY);
216 if (!page)
217 - goto out_task;
219 - mm = check_mem_permission(task);
220 - copied = PTR_ERR(mm);
221 - if (IS_ERR(mm))
222 - goto out_free;
224 - copied = -EIO;
225 - if (file->private_data != (void *)((long)current->self_exec_id))
226 - goto out_mm;
227 + return -ENOMEM;
229 copied = 0;
230 while (count > 0) {
231 @@ -869,13 +799,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
233 *ppos = dst;
235 -out_mm:
236 - mmput(mm);
237 -out_free:
238 free_page((unsigned long) page);
239 -out_task:
240 - put_task_struct(task);
241 -out_no_task:
242 return copied;
245 @@ -895,11 +819,20 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig)
246 return file->f_pos;
249 +static int mem_release(struct inode *inode, struct file *file)
251 + struct mm_struct *mm = file->private_data;
253 + mmput(mm);
254 + return 0;
257 static const struct file_operations proc_mem_operations = {
258 .llseek = mem_lseek,
259 .read = mem_read,
260 .write = mem_write,
261 .open = mem_open,
262 + .release = mem_release,
265 static ssize_t environ_read(struct file *file, char __user *buf,
267 1.7.6.5