aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-17 18:21:19 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-17 18:21:19 -0500
commite268337dfe26dfc7efd422a804dbb27977a3cccc (patch)
tree59b9e22b0de119f0d85f329fa481d965cf7aec42 /fs/proc
parent5e5997849a8eae7a895a88699a1999b637f87303 (diff)
proc: clean up and fix /proc/<pid>/mem handling
Jüri Aedla reported that the /proc/<pid>/mem handling really isn't very robust, and it also doesn't match the permission checking of any of the other related files. This changes it to do the permission checks at open time, and instead of tracking the process, it tracks the VM at the time of the open. That simplifies the code a lot, but does mean that if you hold the file descriptor open over an execve(), you'll continue to read from the _old_ VM. That is different from our previous behavior, but much simpler. If somebody actually finds a load where this matters, we'll need to revert this commit. I suspect that nobody will ever notice - because the process mapping addresses will also have changed as part of the execve. So you cannot actually usefully access the fd across a VM change simply because all the offsets for IO would have changed too. Reported-by: Jüri Aedla <asd@ut.ee> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/base.c145
1 files changed, 39 insertions, 106 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 5485a5388ecb..662ddf2ec4f1 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -198,65 +198,7 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
198 return result; 198 return result;
199} 199}
200 200
201static struct mm_struct *__check_mem_permission(struct task_struct *task) 201static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
202{
203 struct mm_struct *mm;
204
205 mm = get_task_mm(task);
206 if (!mm)
207 return ERR_PTR(-EINVAL);
208
209 /*
210 * A task can always look at itself, in case it chooses
211 * to use system calls instead of load instructions.
212 */
213 if (task == current)
214 return mm;
215
216 /*
217 * If current is actively ptrace'ing, and would also be
218 * permitted to freshly attach with ptrace now, permit it.
219 */
220 if (task_is_stopped_or_traced(task)) {
221 int match;
222 rcu_read_lock();
223 match = (ptrace_parent(task) == current);
224 rcu_read_unlock();
225 if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
226 return mm;
227 }
228
229 /*
230 * No one else is allowed.
231 */
232 mmput(mm);
233 return ERR_PTR(-EPERM);
234}
235
236/*
237 * If current may access user memory in @task return a reference to the
238 * corresponding mm, otherwise ERR_PTR.
239 */
240static struct mm_struct *check_mem_permission(struct task_struct *task)
241{
242 struct mm_struct *mm;
243 int err;
244
245 /*
246 * Avoid racing if task exec's as we might get a new mm but validate
247 * against old credentials.
248 */
249 err = mutex_lock_killable(&task->signal->cred_guard_mutex);
250 if (err)
251 return ERR_PTR(err);
252
253 mm = __check_mem_permission(task);
254 mutex_unlock(&task->signal->cred_guard_mutex);
255
256 return mm;
257}
258
259struct mm_struct *mm_for_maps(struct task_struct *task)
260{ 202{
261 struct mm_struct *mm; 203 struct mm_struct *mm;
262 int err; 204 int err;
@@ -267,7 +209,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
267 209
268 mm = get_task_mm(task); 210 mm = get_task_mm(task);
269 if (mm && mm != current->mm && 211 if (mm && mm != current->mm &&
270 !ptrace_may_access(task, PTRACE_MODE_READ)) { 212 !ptrace_may_access(task, mode)) {
271 mmput(mm); 213 mmput(mm);
272 mm = ERR_PTR(-EACCES); 214 mm = ERR_PTR(-EACCES);
273 } 215 }
@@ -276,6 +218,11 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
276 return mm; 218 return mm;
277} 219}
278 220
221struct mm_struct *mm_for_maps(struct task_struct *task)
222{
223 return mm_access(task, PTRACE_MODE_READ);
224}
225
279static int proc_pid_cmdline(struct task_struct *task, char * buffer) 226static int proc_pid_cmdline(struct task_struct *task, char * buffer)
280{ 227{
281 int res = 0; 228 int res = 0;
@@ -752,38 +699,39 @@ static const struct file_operations proc_single_file_operations = {
752 699
753static int mem_open(struct inode* inode, struct file* file) 700static int mem_open(struct inode* inode, struct file* file)
754{ 701{
755 file->private_data = (void*)((long)current->self_exec_id); 702 struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
703 struct mm_struct *mm;
704
705 if (!task)
706 return -ESRCH;
707
708 mm = mm_access(task, PTRACE_MODE_ATTACH);
709 put_task_struct(task);
710
711 if (IS_ERR(mm))
712 return PTR_ERR(mm);
713
756 /* OK to pass negative loff_t, we can catch out-of-range */ 714 /* OK to pass negative loff_t, we can catch out-of-range */
757 file->f_mode |= FMODE_UNSIGNED_OFFSET; 715 file->f_mode |= FMODE_UNSIGNED_OFFSET;
716 file->private_data = mm;
717
758 return 0; 718 return 0;
759} 719}
760 720
761static ssize_t mem_read(struct file * file, char __user * buf, 721static ssize_t mem_read(struct file * file, char __user * buf,
762 size_t count, loff_t *ppos) 722 size_t count, loff_t *ppos)
763{ 723{
764 struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); 724 int ret;
765 char *page; 725 char *page;
766 unsigned long src = *ppos; 726 unsigned long src = *ppos;
767 int ret = -ESRCH; 727 struct mm_struct *mm = file->private_data;
768 struct mm_struct *mm;
769 728
770 if (!task) 729 if (!mm)
771 goto out_no_task; 730 return 0;
772 731
773 ret = -ENOMEM;
774 page = (char *)__get_free_page(GFP_TEMPORARY); 732 page = (char *)__get_free_page(GFP_TEMPORARY);
775 if (!page) 733 if (!page)
776 goto out; 734 return -ENOMEM;
777
778 mm = check_mem_permission(task);
779 ret = PTR_ERR(mm);
780 if (IS_ERR(mm))
781 goto out_free;
782
783 ret = -EIO;
784
785 if (file->private_data != (void*)((long)current->self_exec_id))
786 goto out_put;
787 735
788 ret = 0; 736 ret = 0;
789 737
@@ -810,13 +758,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
810 } 758 }
811 *ppos = src; 759 *ppos = src;
812 760
813out_put:
814 mmput(mm);
815out_free:
816 free_page((unsigned long) page); 761 free_page((unsigned long) page);
817out:
818 put_task_struct(task);
819out_no_task:
820 return ret; 762 return ret;
821} 763}
822 764
@@ -825,27 +767,15 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
825{ 767{
826 int copied; 768 int copied;
827 char *page; 769 char *page;
828 struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
829 unsigned long dst = *ppos; 770 unsigned long dst = *ppos;
830 struct mm_struct *mm; 771 struct mm_struct *mm = file->private_data;
831 772
832 copied = -ESRCH; 773 if (!mm)
833 if (!task) 774 return 0;
834 goto out_no_task;
835 775
836 copied = -ENOMEM;
837 page = (char *)__get_free_page(GFP_TEMPORARY); 776 page = (char *)__get_free_page(GFP_TEMPORARY);
838 if (!page) 777 if (!page)
839 goto out_task; 778 return -ENOMEM;
840
841 mm = check_mem_permission(task);
842 copied = PTR_ERR(mm);
843 if (IS_ERR(mm))
844 goto out_free;
845
846 copied = -EIO;
847 if (file->private_data != (void *)((long)current->self_exec_id))
848 goto out_mm;
849 779
850 copied = 0; 780 copied = 0;
851 while (count > 0) { 781 while (count > 0) {
@@ -869,13 +799,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
869 } 799 }
870 *ppos = dst; 800 *ppos = dst;
871 801
872out_mm:
873 mmput(mm);
874out_free:
875 free_page((unsigned long) page); 802 free_page((unsigned long) page);
876out_task:
877 put_task_struct(task);
878out_no_task:
879 return copied; 803 return copied;
880} 804}
881 805
@@ -895,11 +819,20 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig)
895 return file->f_pos; 819 return file->f_pos;
896} 820}
897 821
822static int mem_release(struct inode *inode, struct file *file)
823{
824 struct mm_struct *mm = file->private_data;
825
826 mmput(mm);
827 return 0;
828}
829
898static const struct file_operations proc_mem_operations = { 830static const struct file_operations proc_mem_operations = {
899 .llseek = mem_lseek, 831 .llseek = mem_lseek,
900 .read = mem_read, 832 .read = mem_read,
901 .write = mem_write, 833 .write = mem_write,
902 .open = mem_open, 834 .open = mem_open,
835 .release = mem_release,
903}; 836};
904 837
905static ssize_t environ_read(struct file *file, char __user *buf, 838static ssize_t environ_read(struct file *file, char __user *buf,