[PATCH] proc: task_mmu bug fix.

Eric W. Biederman
2006-03-01T07:32:35Z

This should fix the big bug that has been crashing kernels when
fuser is called. At least it is the bug I observed here. It seems
you need the right access pattern on /proc/<pid>/maps to trigger this.

seq_operations ->stop is only called once per start making it safe to
call put_task_struct there. However m_next was calling m_stop which
totally messed me up.

Technically the task_struct needs to be held for the duration, so
split m_stop into two functions such that only vma_stop is called
multiple times per start.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>

---

fs/proc/task_mmu.c | 18 ++++++++++++------
1 files changed, 12 insertions(+), 6 deletions(-)

4217fed6dbbf2b5615d8a498b39aad5ee28d3e5f
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 4772543..f299538 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -363,17 +363,13 @@ out:
return priv->tail_vma;
}

-static void m_stop(struct seq_file *m, void *v)
+static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
{
- struct proc_maps_private *priv = m->private;
- struct vm_area_struct *vma = v;
if (vma && vma != priv->tail_vma) {
struct mm_struct *mm = vma->vm_mm;
up_read(&mm->mmap_sem);
mmput(mm);
}
- if (priv->task)
- put_task_struct(priv->task);
}

static void *m_next(struct seq_file *m, void *v, loff_t *pos)
@@ -385,10 +381,20 @@ static void *m_next(struct seq_file *m,
(*pos)++;
if (vma && (vma != tail_vma) && vma->vm_next)
return vma->vm_next;
- m_stop(m, v);
+ vma_stop(priv, vma);
return (vma != tail_vma)? tail_vma: NULL;
}

+static void m_stop(struct seq_file *m, void *v)
+{
+ struct proc_maps_private *priv = m->private;
+ struct vm_area_struct *vma = v;
+
+ vma_stop(priv, vma);
+ if (priv->task)
+ put_task_struct(priv->task);
+}
+
static struct seq_operations proc_pid_maps_op = {
.start = m_start,
.next = m_next,
--
1.2.2.g709a-dirty