]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
selftests/mm: verify droppable mappings cannot be locked
authorAnthony Yznaga <anthony.yznaga@oracle.com>
Thu, 16 Apr 2026 03:39:38 +0000 (20:39 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Fri, 29 May 2026 04:04:48 +0000 (21:04 -0700)
For configs that support MAP_DROPPABLE verify that a mapping created with
MAP_DROPPABLE cannot be locked via mlock(), and that it will not be locked
if it's created after mlockall(MCL_FUTURE).

Link: https://lore.kernel.org/20260416033939.49981-3-anthony.yznaga@oracle.com
Signed-off-by: Anthony Yznaga <anthony.yznaga@oracle.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Jason A. Donenfeld <jason@zx2c4.com>
Cc: Liam Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
tools/testing/selftests/mm/mlock2-tests.c

index b474f2b20def2572c9dd138ff76792b4b9a27039..e16e288cc7c1f2051c7c8f3d9d9cca7f15593f03 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #define _GNU_SOURCE
 #include <sys/mman.h>
+#include <linux/mman.h>
 #include <stdint.h>
 #include <unistd.h>
 #include <string.h>
@@ -163,14 +164,17 @@ static int lock_check(unsigned long addr)
        return (vma_rss == vma_size);
 }
 
-static int unlock_lock_check(char *map)
+static int unlock_lock_check(char *map, bool mlock_supported)
 {
-       if (is_vmflag_set((unsigned long)map, LOCKED)) {
+       if (!is_vmflag_set((unsigned long)map, LOCKED))
+               return 0;
+
+       if (mlock_supported)
                ksft_print_msg("VMA flag %s is present on page 1 after unlock\n", LOCKED);
-               return 1;
-       }
+       else
+               ksft_print_msg("VMA flag %s is present on an unsupported VMA\n", LOCKED);
 
-       return 0;
+       return 1;
 }
 
 static void test_mlock_lock(void)
@@ -196,7 +200,7 @@ static void test_mlock_lock(void)
                ksft_exit_fail_msg("munlock(): %s\n", strerror(errno));
        }
 
-       ksft_test_result(!unlock_lock_check(map), "%s: Unlocked\n", __func__);
+       ksft_test_result(!unlock_lock_check(map, true), "%s: Unlocked\n", __func__);
        munmap(map, 2 * page_size);
 }
 
@@ -296,7 +300,7 @@ static void test_munlockall0(void)
                ksft_exit_fail_msg("munlockall(): %s\n", strerror(errno));
        }
 
-       ksft_test_result(!unlock_lock_check(map), "%s: No locked memory\n", __func__);
+       ksft_test_result(!unlock_lock_check(map, true), "%s: No locked memory\n", __func__);
        munmap(map, 2 * page_size);
 }
 
@@ -336,7 +340,67 @@ static void test_munlockall1(void)
                ksft_exit_fail_msg("munlockall() %s\n", strerror(errno));
        }
 
-       ksft_test_result(!unlock_lock_check(map), "%s: No locked memory\n", __func__);
+       ksft_test_result(!unlock_lock_check(map, true), "%s: No locked memory\n", __func__);
+       munmap(map, 2 * page_size);
+}
+
+/* Droppable memory should not be lockable.  */
+static void test_mlock_droppable(void)
+{
+       char *map;
+       unsigned long page_size = getpagesize();
+
+       /* Ensure MCL_FUTURE is not set. */
+       if (munlockall()) {
+               ksft_test_result_fail("munlockall() %s\n", strerror(errno));
+               return;
+       }
+
+       map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
+                  MAP_ANONYMOUS | MAP_DROPPABLE, -1, 0);
+       if (map == MAP_FAILED) {
+               if ((errno == EOPNOTSUPP) || (errno == EINVAL))
+                       ksft_test_result_skip("%s: MAP_DROPPABLE not supported\n", __func__);
+               else
+                       ksft_test_result_fail("mmap error: %s\n", strerror(errno));
+               return;
+       }
+
+       if (mlock2_(map, 2 * page_size, 0))
+               ksft_test_result_fail("mlock2(0): %s\n", strerror(errno));
+       else
+               ksft_test_result(!unlock_lock_check(map, false),
+                               "%s: droppable memory not locked\n", __func__);
+
+       munmap(map, 2 * page_size);
+}
+
+static void test_mlockall_future_droppable(void)
+{
+       char *map;
+       unsigned long page_size = getpagesize();
+
+       if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
+               ksft_test_result_fail("mlockall(MCL_CURRENT | MCL_FUTURE): %s\n", strerror(errno));
+               return;
+       }
+
+       map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
+                  MAP_ANONYMOUS | MAP_DROPPABLE, -1, 0);
+
+       if (map == MAP_FAILED) {
+               if ((errno == EOPNOTSUPP) || (errno == EINVAL))
+                       ksft_test_result_skip("%s: MAP_DROPPABLE not supported\n", __func__);
+               else
+                       ksft_test_result_fail("mmap error: %s\n", strerror(errno));
+               munlockall();
+               return;
+       }
+
+       ksft_test_result(!unlock_lock_check(map, false), "%s: droppable memory not locked\n",
+                       __func__);
+
+       munlockall();
        munmap(map, 2 * page_size);
 }
 
@@ -442,7 +506,7 @@ int main(int argc, char **argv)
 
        munmap(map, size);
 
-       ksft_set_plan(13);
+       ksft_set_plan(15);
 
        test_mlock_lock();
        test_mlock_onfault();
@@ -451,6 +515,8 @@ int main(int argc, char **argv)
        test_lock_onfault_of_present();
        test_vma_management(true);
        test_mlockall();
+       test_mlock_droppable();
+       test_mlockall_future_droppable();
 
        ksft_finished();
 }