diff options
| author | Christian Brauner <brauner@kernel.org> | 2026-01-29 14:52:22 +0100 |
|---|---|---|
| committer | Sasha Levin <sashal@kernel.org> | 2026-03-12 07:09:27 -0400 |
| commit | 15f9acce863b400df98e8d77282b96690d19ee7f (patch) | |
| tree | 2f5c3e8c77245923832a653dfb161afbe5e441dc /fs | |
| parent | 73aa05c8f576dcc02ebe50726eb8eec7baddf31f (diff) | |
namespace: fix proc mount iteration
commit 4a403d7aa9074f527f064ef0806aaab38d14b07c upstream.
The m->index isn't updated when m->show() overflows and retains its
value before the current mount causing a restart to start at the same
value. If that happens in short order to due a quickly expanding mount
table this would cause the same mount to be shown again and again.
Ensure that *pos always equals the mount id of the mount that was
returned by start/next. On restart after overflow mnt_find_id_at(*pos)
finds the exact mount. This should avoid duplicates, avoid skips and
should handle concurrent modification just fine.
Cc: <stable@vger.kernel.org>
Fixed: 2eea9ce4310d8 ("mounts: keep list of mounts in an rbtree")
Link: https://patch.msgid.link/20260129-geleckt-treuhand-4bb940acacd9@brauner
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/namespace.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index ecf0e72ce6cf..9e5e3f1db02f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1537,23 +1537,33 @@ static struct mount *mnt_find_id_at_reverse(struct mnt_namespace *ns, u64 mnt_id static void *m_start(struct seq_file *m, loff_t *pos) { struct proc_mounts *p = m->private; + struct mount *mnt; down_read(&namespace_sem); - return mnt_find_id_at(p->ns, *pos); + mnt = mnt_find_id_at(p->ns, *pos); + if (mnt) + *pos = mnt->mnt_id_unique; + return mnt; } static void *m_next(struct seq_file *m, void *v, loff_t *pos) { - struct mount *next = NULL, *mnt = v; + struct mount *mnt = v; struct rb_node *node = rb_next(&mnt->mnt_node); - ++*pos; if (node) { - next = node_to_mount(node); + struct mount *next = node_to_mount(node); *pos = next->mnt_id_unique; + return next; } - return next; + + /* + * No more mounts. Set pos past current mount's ID so that if + * iteration restarts, mnt_find_id_at() returns NULL. + */ + *pos = mnt->mnt_id_unique + 1; + return NULL; } static void m_stop(struct seq_file *m, void *v) |
