[PATCH] proc: /proc/<pid>/maps: release mmap read lock

From: Ben Wolsieffer
Date: Thu Jul 28 2022 - 10:59:07 EST


The no-MMU implementation of /proc/<pid>/map doesn't normally release
the mmap read lock, since the !IS_ERR_OR_NULL(_vml) condition in m_stop
is false in most cases.

This patch syncs the relevant locking and error handling code from the
MMU implementation to reduce the divergence between the two
implementations and fix the locking bug.

Signed-off-by: Ben Wolsieffer <Ben.Wolsieffer@xxxxxxxxxxx>
---
fs/proc/task_nommu.c | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index a6d21fc0033c..97f387d30e74 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -208,11 +208,16 @@ static void *m_start(struct seq_file *m, loff_t *pos)
return ERR_PTR(-ESRCH);

mm = priv->mm;
- if (!mm || !mmget_not_zero(mm))
+ if (!mm || !mmget_not_zero(mm)) {
+ put_task_struct(priv->task);
+ priv->task = NULL;
return NULL;
+ }

if (mmap_read_lock_killable(mm)) {
mmput(mm);
+ put_task_struct(priv->task);
+ priv->task = NULL;
return ERR_PTR(-EINTR);
}

@@ -221,23 +226,21 @@ static void *m_start(struct seq_file *m, loff_t *pos)
if (n-- == 0)
return p;

- mmap_read_unlock(mm);
- mmput(mm);
return NULL;
}

-static void m_stop(struct seq_file *m, void *_vml)
+static void m_stop(struct seq_file *m, void *v)
{
struct proc_maps_private *priv = m->private;
+ struct mm_struct *mm = priv->mm;

- if (!IS_ERR_OR_NULL(_vml)) {
- mmap_read_unlock(priv->mm);
- mmput(priv->mm);
- }
- if (priv->task) {
- put_task_struct(priv->task);
- priv->task = NULL;
- }
+ if (!priv->task)
+ return;
+
+ mmap_read_unlock(mm);
+ mmput(mm);
+ put_task_struct(priv->task);
+ priv->task = NULL;
}

static void *m_next(struct seq_file *m, void *_p, loff_t *pos)
--
2.36.1