aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-04-29 04:01:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:17 -0400
commit638fa202cdb207083a12d6f73e313605a8fc1037 (patch)
treee049d74e9f7e15a55149dc17482572c8b2aefa18
parent0d5c9f5f59a61cf8e98e2925cb5d81cbe7694305 (diff)
procfs: mem permission cleanup
This cleans up the permission checks done for /proc/PID/mem i/o calls. It puts all the logic in a new function, check_mem_permission(). The old code repeated the (!MAY_PTRACE(task) || !ptrace_may_attach(task)) magical expression multiple times. The new function does all that work in one place, with clear comments. The old code called security_ptrace() twice on successful checks, once in MAY_PTRACE() and once in __ptrace_may_attach(). Now it's only called once, and only if all other checks have succeeded. Signed-off-by: Roland McGrath <roland@redhat.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/base.c38
1 files changed, 29 insertions, 9 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index b48ddb119945..fcf02f2deeba 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -195,12 +195,32 @@ static int proc_root_link(struct inode *inode, struct path *path)
195 return result; 195 return result;
196} 196}
197 197
198#define MAY_PTRACE(task) \ 198/*
199 (task == current || \ 199 * Return zero if current may access user memory in @task, -error if not.
200 (task->parent == current && \ 200 */
201 (task->ptrace & PT_PTRACED) && \ 201static int check_mem_permission(struct task_struct *task)
202 (task_is_stopped_or_traced(task)) && \ 202{
203 security_ptrace(current,task) == 0)) 203 /*
204 * A task can always look at itself, in case it chooses
205 * to use system calls instead of load instructions.
206 */
207 if (task == current)
208 return 0;
209
210 /*
211 * If current is actively ptrace'ing, and would also be
212 * permitted to freshly attach with ptrace now, permit it.
213 */
214 if (task->parent == current && (task->ptrace & PT_PTRACED) &&
215 task_is_stopped_or_traced(task) &&
216 ptrace_may_attach(task))
217 return 0;
218
219 /*
220 * Noone else is allowed.
221 */
222 return -EPERM;
223}
204 224
205struct mm_struct *mm_for_maps(struct task_struct *task) 225struct mm_struct *mm_for_maps(struct task_struct *task)
206{ 226{
@@ -722,7 +742,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
722 if (!task) 742 if (!task)
723 goto out_no_task; 743 goto out_no_task;
724 744
725 if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) 745 if (check_mem_permission(task))
726 goto out; 746 goto out;
727 747
728 ret = -ENOMEM; 748 ret = -ENOMEM;
@@ -748,7 +768,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
748 768
749 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; 769 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
750 retval = access_process_vm(task, src, page, this_len, 0); 770 retval = access_process_vm(task, src, page, this_len, 0);
751 if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) { 771 if (!retval || check_mem_permission(task)) {
752 if (!ret) 772 if (!ret)
753 ret = -EIO; 773 ret = -EIO;
754 break; 774 break;
@@ -792,7 +812,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
792 if (!task) 812 if (!task)
793 goto out_no_task; 813 goto out_no_task;
794 814
795 if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) 815 if (check_mem_permission(task))
796 goto out; 816 goto out;
797 817
798 copied = -ENOMEM; 818 copied = -ENOMEM;