proc: nommu: /proc/<pid>/maps: release mmap read lock
authorBen Wolsieffer <Ben.Wolsieffer@hefring.com>
Thu, 14 Sep 2023 16:30:20 +0000 (12:30 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 6 Oct 2023 12:56:42 +0000 (14:56 +0200)
commit1d45e6d9951d426a550a0411a718b9384f2181f3
tree6cad67e85817ace45a96ce738c94116bfcf5a856
parentc5c9ee3887232d9c9c1313212dd4ca9d5e08e337
proc: nommu: /proc/<pid>/maps: release mmap read lock

[ Upstream commit 578d7699e5c2add8c2e9549d9d75dfb56c460cb3 ]

The no-MMU implementation of /proc/<pid>/map doesn't normally release
the mmap read lock, because it uses !IS_ERR_OR_NULL(_vml) to determine
whether to release the lock.  Since _vml is NULL when the end of the
mappings is reached, the lock is not released.

Reading /proc/1/maps twice doesn't cause a hang because it only
takes the read lock, which can be taken multiple times and therefore
doesn't show any problem if the lock isn't released. Instead, you need
to perform some operation that attempts to take the write lock after
reading /proc/<pid>/maps. To actually reproduce the bug, compile the
following code as 'proc_maps_bug':

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>

int main(int argc, char *argv[]) {
        void *buf;
        sleep(1);
        buf = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        puts("mmap returned");
        return 0;
}

Then, run:

  ./proc_maps_bug &; cat /proc/$!/maps; fg

Without this patch, mmap() will hang and the command will never
complete.

This code was incorrectly adapted from the MMU implementation, which at
the time released the lock in m_next() before returning the last entry.

The MMU implementation has diverged further from the no-MMU version since
then, so this patch brings their locking and error handling into sync,
fixing the bug and hopefully avoiding similar issues in the future.

Link: https://lkml.kernel.org/r/20230914163019.4050530-2-ben.wolsieffer@hefring.com
Fixes: 47fecca15c09 ("fs/proc/task_nommu.c: don't use priv->task->mm")
Signed-off-by: Ben Wolsieffer <ben.wolsieffer@hefring.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: Giulio Benetti <giulio.benetti@benettiengineering.com>
Cc: Greg Ungerer <gerg@uclinux.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: fe4419801617 ("proc: nommu: fix empty /proc/<pid>/maps")
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/proc/task_nommu.c