restrict reading from /proc/<pid>/maps to those who share ->mm or can ptrace pid

Contents of /proc/*/maps is sensitive and may become sensitive after
open() (e.g.  if target originally shares our ->mm and later does exec
on suid-root binary).

Check at read() (actually, ->start() of iterator) time that mm_struct
we'd grabbed and locked is
 - still the ->mm of target
 - equal to reader's ->mm or the target is ptracable by reader.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Al Viro 2008-01-02 14:09:57 +00:00 committed by Linus Torvalds
parent ac40532ef0
commit 831830b5a2
6 changed files with 27 additions and 7 deletions

View file

@ -202,6 +202,26 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
(task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
security_ptrace(current,task) == 0)) security_ptrace(current,task) == 0))
struct mm_struct *mm_for_maps(struct task_struct *task)
{
struct mm_struct *mm = get_task_mm(task);
if (!mm)
return NULL;
down_read(&mm->mmap_sem);
task_lock(task);
if (task->mm != mm)
goto out;
if (task->mm != current->mm && __ptrace_may_attach(task) < 0)
goto out;
task_unlock(task);
return mm;
out:
task_unlock(task);
up_read(&mm->mmap_sem);
mmput(mm);
return NULL;
}
static int proc_pid_cmdline(struct task_struct *task, char * buffer) static int proc_pid_cmdline(struct task_struct *task, char * buffer)
{ {
int res = 0; int res = 0;

View file

@ -27,6 +27,8 @@ struct vmalloc_info {
unsigned long largest_chunk; unsigned long largest_chunk;
}; };
extern struct mm_struct *mm_for_maps(struct task_struct *);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
#define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START) #define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
extern void get_vmalloc_info(struct vmalloc_info *vmi); extern void get_vmalloc_info(struct vmalloc_info *vmi);

View file

@ -397,12 +397,11 @@ static void *m_start(struct seq_file *m, loff_t *pos)
if (!priv->task) if (!priv->task)
return NULL; return NULL;
mm = get_task_mm(priv->task); mm = mm_for_maps(priv->task);
if (!mm) if (!mm)
return NULL; return NULL;
priv->tail_vma = tail_vma = get_gate_vma(priv->task); priv->tail_vma = tail_vma = get_gate_vma(priv->task);
down_read(&mm->mmap_sem);
/* Start with last addr hint */ /* Start with last addr hint */
if (last_addr && (vma = find_vma(mm, last_addr))) { if (last_addr && (vma = find_vma(mm, last_addr))) {

View file

@ -165,15 +165,13 @@ static void *m_start(struct seq_file *m, loff_t *pos)
if (!priv->task) if (!priv->task)
return NULL; return NULL;
mm = get_task_mm(priv->task); mm = mm_for_maps(priv->task);
if (!mm) { if (!mm) {
put_task_struct(priv->task); put_task_struct(priv->task);
priv->task = NULL; priv->task = NULL;
return NULL; return NULL;
} }
down_read(&mm->mmap_sem);
/* start from the Nth VMA */ /* start from the Nth VMA */
for (vml = mm->context.vmlist; vml; vml = vml->next) for (vml = mm->context.vmlist; vml; vml = vml->next)
if (n-- == 0) if (n-- == 0)

View file

@ -97,6 +97,7 @@ extern void __ptrace_link(struct task_struct *child,
extern void __ptrace_unlink(struct task_struct *child); extern void __ptrace_unlink(struct task_struct *child);
extern void ptrace_untrace(struct task_struct *child); extern void ptrace_untrace(struct task_struct *child);
extern int ptrace_may_attach(struct task_struct *task); extern int ptrace_may_attach(struct task_struct *task);
extern int __ptrace_may_attach(struct task_struct *task);
static inline void ptrace_link(struct task_struct *child, static inline void ptrace_link(struct task_struct *child,
struct task_struct *new_parent) struct task_struct *new_parent)

View file

@ -120,7 +120,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)
return ret; return ret;
} }
static int may_attach(struct task_struct *task) int __ptrace_may_attach(struct task_struct *task)
{ {
/* May we inspect the given task? /* May we inspect the given task?
* This check is used both for attaching with ptrace * This check is used both for attaching with ptrace
@ -154,7 +154,7 @@ int ptrace_may_attach(struct task_struct *task)
{ {
int err; int err;
task_lock(task); task_lock(task);
err = may_attach(task); err = __ptrace_may_attach(task);
task_unlock(task); task_unlock(task);
return !err; return !err;
} }