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
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
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_
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
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>
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
39 @@ -198,65 +198,7 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
43 -static struct mm_struct *__check_mem_permission(struct task_struct *task)
45 - struct mm_struct *mm;
47 - mm = get_task_mm(task);
49 - return ERR_PTR(-EINVAL);
52 - * A task can always look at itself, in case it chooses
53 - * to use system calls instead of load instructions.
55 - if (task == current)
59 - * If current is actively ptrace'ing, and would also be
60 - * permitted to freshly attach with ptrace now, permit it.
62 - if (task_is_stopped_or_traced(task)) {
65 - match = (ptrace_parent(task) == current);
67 - if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
72 - * No one else is allowed.
75 - return ERR_PTR(-EPERM);
79 - * If current may access user memory in @task return a reference to the
80 - * corresponding mm, otherwise ERR_PTR.
82 -static struct mm_struct *check_mem_permission(struct task_struct *task)
84 - struct mm_struct *mm;
88 - * Avoid racing if task exec's as we might get a new mm but validate
89 - * against old credentials.
91 - err = mutex_lock_killable(&task->signal->cred_guard_mutex);
93 - return ERR_PTR(err);
95 - mm = __check_mem_permission(task);
96 - mutex_unlock(&task->signal->cred_guard_mutex);
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;
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)) {
113 mm = ERR_PTR(-EACCES);
115 @@ -276,6 +218,11 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
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)
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;
138 + mm = mm_access(task, PTRACE_MODE_ATTACH);
139 + put_task_struct(task);
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;
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);
157 unsigned long src = *ppos;
159 - struct mm_struct *mm;
160 + struct mm_struct *mm = file->private_data;
168 page = (char *)__get_free_page(GFP_TEMPORARY);
172 - mm = check_mem_permission(task);
179 - if (file->private_data != (void*)((long)current->self_exec_id))
185 @@ -810,13 +758,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
192 free_page((unsigned long) page);
194 - put_task_struct(task);
199 @@ -825,27 +767,15 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
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;
215 page = (char *)__get_free_page(GFP_TEMPORARY);
219 - mm = check_mem_permission(task);
220 - copied = PTR_ERR(mm);
225 - if (file->private_data != (void *)((long)current->self_exec_id))
231 @@ -869,13 +799,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
238 free_page((unsigned long) page);
240 - put_task_struct(task);
245 @@ -895,11 +819,20 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig)
249 +static int mem_release(struct inode *inode, struct file *file)
251 + struct mm_struct *mm = file->private_data;
257 static const struct file_operations proc_mem_operations = {
262 + .release = mem_release,
265 static ssize_t environ_read(struct file *file, char __user *buf,