[PATCH 0/2] mm/hugetlb: fix list corruption in allocate_file_region_entries()

Xiangfeng Cai posted 2 patches 1 week, 5 days ago
mm/hugetlb.c                                  |   2 +-
tools/testing/selftests/mm/.gitignore         |   1 +
tools/testing/selftests/mm/Makefile           |   1 +
.../selftests/mm/hugetlb_region_cache_race.c  | 315 ++++++++++++++++++
tools/testing/selftests/mm/run_vmtests.sh     |   1 +
5 files changed, 319 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/mm/hugetlb_region_cache_race.c
[PATCH 0/2] mm/hugetlb: fix list corruption in allocate_file_region_entries()
Posted by Xiangfeng Cai 1 week, 5 days ago
To: Andrew Morton <akpm@linux-foundation.org>
To: Muchun Song <muchun.song@linux.dev>
To: Oscar Salvador <osalvador@suse.de>
Cc: David Hildenbrand <david@kernel.org>
Cc: Wei Yang <richard.weiyang@linux.alibaba.com>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Shuah Khan <shuah@kernel.org>
Cc: linux-mm@kvack.org
Cc: linux-kselftest@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: stable@vger.kernel.org

allocate_file_region_entries() refills resv->region_cache with freshly
allocated file_region descriptors.  It allocates with GFP_KERNEL, so it
drops resv->lock, gathers the new entries on a stack-local list head, and
on regaining the lock moves them into resv->region_cache with
list_splice().  list_splice() does not re-initialize the source head, so
if the retry loop iterates again -- which happens when a concurrent
region_* operation on the same shared resv_map consumes cache entries
during the unlocked window -- the next list_add() operates on the stale,
already spliced head and corrupts the list.  On a CONFIG_DEBUG_LIST=y
kernel this is a hard BUG(); without list debugging it silently links a
kernel-stack address into resv->region_cache.

This was observed as a real host panic on a dense KVM host where a QEMU
guest-RAM hugetlbfs file was mapped MAP_SHARED by both QEMU and a separate
SPDK/DPDK vhost-user target, generating concurrent region_* traffic on one
shared resv_map.

Patch 1 fixes it by using list_splice_init().  The bug is present in
mainline; the Fixes: commit dates back to v5.10.

Patch 2 adds a selftest that reproduces the race (opt-in --trigger mode,
since it panics a vulnerable host) and runs a safe single-threaded
functional check by default.

Xiangfeng Cai (2):
  mm/hugetlb: fix list corruption in allocate_file_region_entries()
  selftests/mm: add hugetlb_region_cache_race regression test

 mm/hugetlb.c                                  |   2 +-
 tools/testing/selftests/mm/.gitignore         |   1 +
 tools/testing/selftests/mm/Makefile           |   1 +
 .../selftests/mm/hugetlb_region_cache_race.c  | 315 ++++++++++++++++++
 tools/testing/selftests/mm/run_vmtests.sh     |   1 +
 5 files changed, 319 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/mm/hugetlb_region_cache_race.c

-- 
2.55.0.122.gf85a7e6620