Re: [PATCH v5 2/2] userns: Add KUnit test suite for uid_gid_map

From: Bill Wendling

Date: Wed Sep 09 2026 - 15:56:13 EST


On Wed, Sep 9, 2026 at 8:36 AM Bradley Morgan <brads@xxxxxxxxxxxxxx> wrote:
> On 8 September 2026 23:27:30 BST, Bill Wendling <morbo@xxxxxxxxxx> wrote:
> >diff --git a/init/Kconfig b/init/Kconfig
> >index 8583d9f06c52..27c1ffc675bf 100644
> >--- a/init/Kconfig
> >+++ b/init/Kconfig
> >@@ -1457,6 +1457,17 @@ config USER_NS
> >
> > If unsure, say N.
> >
> >+config USER_NS_MAP_KUNIT_TEST
> >+ tristate "KUint test for user
>
> Hmm! s/KUint/KUnit
>
*headdesk*

-bw

> namespace map insertion" if !KUNIT_ALL_TESTS
> >+ depends on USER_NS && KUNIT
> >+ default KUNIT_ALL_TESTS
> >+ help
> >+ This builds the KUnit test for user namespace uid/gid map insertion.
> >+ It validates map insertion, limits, dynamic allocation of the
> >+ extended extents array, and mapping sorting functions.
> >+
> >+ If unsure, say N.
> >+
> > config PID_NS
> > bool "PID Namespaces"
> > default y
> >diff --git a/kernel/Makefile b/kernel/Makefile
> >index 1e1a31673577..2a64282749b8 100644
> >--- a/kernel/Makefile
> >+++ b/kernel/Makefile
> >@@ -141,6 +141,7 @@ obj-$(CONFIG_WATCH_QUEUE) += watch_queue.o
> >
> > obj-$(CONFIG_RESOURCE_KUNIT_TEST) += resource_kunit.o
> > obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o
> >+obj-$(CONFIG_USER_NS_MAP_KUNIT_TEST) += tests/user_ns_map_kunit.o
> >
> > CFLAGS_kstack_erase.o += $(DISABLE_KSTACK_ERASE)
> > CFLAGS_kstack_erase.o += $(call cc-option,-mgeneral-regs-only)
> >diff --git a/kernel/tests/.kunitconfig b/kernel/tests/.kunitconfig
> >new file mode 100644
> >index 000000000000..b3d1206fd81a
> >--- /dev/null
> >+++ b/kernel/tests/.kunitconfig
> >@@ -0,0 +1,4 @@
> >+CONFIG_KUNIT=y
> >+CONFIG_NAMESPACES=y
> >+CONFIG_USER_NS=y
> >+CONFIG_USER_NS_MAP_KUNIT_TEST=y
> >diff --git a/kernel/tests/user_ns_map_kunit.c b/kernel/tests/user_ns_map_kunit.c
> >new file mode 100644
> >index 000000000000..24c21e43a36c
> >--- /dev/null
> >+++ b/kernel/tests/user_ns_map_kunit.c
> >@@ -0,0 +1,98 @@
> >+// SPDX-License-Identifier: GPL-2.0
> >+/*
> >+ * KUnit test for user namespace map insertion and sorting.
> >+ */
> >+
> >+#define pr_fmt(fmt) "user_namespace: " fmt
> >+
> >+#include <kunit/test.h>
> >+#include <linux/user_namespace.h>
> >+
> >+#define NR_EXTENTS (UID_GID_MAP_MAX_BASE_EXTENTS + 5)
> >+
> >+static void user_ns_map_insert(struct kunit *test)
> >+{
> >+ struct uid_gid_map map;
> >+ struct uid_gid_extent extent;
> >+ int i, ret;
> >+
> >+ memset(&map, 0, sizeof(map));
> >+
> >+ /* Insert up to UID_GID_MAP_MAX_BASE_EXTENTS elements */
> >+ for (i = 0; i < UID_GID_MAP_MAX_BASE_EXTENTS; i++) {
> >+ extent.first = i * 10;
> >+ extent.lower_first = i * 100;
> >+ extent.count = 5;
> >+
> >+ ret = insert_extent(&map, &extent);
> >+ KUNIT_ASSERT_EQ(test, ret, 0);
> >+ }
> >+
> >+ KUNIT_EXPECT_EQ(test, map.nr_extents, UID_GID_MAP_MAX_BASE_EXTENTS);
> >+
> >+ /* Verify the elements ended up in the 'extent' array */
> >+ for (i = 0; i < UID_GID_MAP_MAX_BASE_EXTENTS; i++) {
> >+ KUNIT_EXPECT_EQ(test, map.extent[i].first, i * 10);
> >+ KUNIT_EXPECT_EQ(test, map.extent[i].lower_first, i * 100);
> >+ KUNIT_EXPECT_EQ(test, map.extent[i].count, 5);
> >+ }
> >+}
> >+
> >+static void user_ns_map_insert_extended(struct kunit *test)
> >+{
> >+ struct uid_gid_map map;
> >+ struct uid_gid_extent extent;
> >+ int i, ret;
> >+
> >+ memset(&map, 0, sizeof(map));
> >+
> >+ /* Insert more than UID_GID_MAP_MAX_BASE_EXTENTS elements */
> >+ for (i = 0; i < NR_EXTENTS; i++) {
> >+ int value = 9 - i;
> >+
> >+ extent.first = value * 10;
> >+ extent.lower_first = value * 100;
> >+ extent.count = 5;
> >+
> >+ ret = insert_extent(&map, &extent);
> >+ KUNIT_ASSERT_EQ(test, ret, 0);
> >+ }
> >+
> >+ KUNIT_EXPECT_EQ(test, map.nr_extents, NR_EXTENTS);
> >+
> >+ /* Now sort the map to set up reverse mapping */
> >+ ret = sort_idmaps(&map);
> >+ KUNIT_ASSERT_EQ(test, ret, 0);
> >+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, map.reverse);
> >+
> >+ /* Verify the elements are in 'forward' and that sorting is correct */
> >+ for (i = 0; i < map.nr_extents; i++) {
> >+ KUNIT_EXPECT_EQ(test, map.forward[i].first, i * 10);
> >+ KUNIT_EXPECT_EQ(test, map.forward[i].lower_first, i * 100);
> >+ KUNIT_EXPECT_EQ(test, map.forward[i].count, 5);
> >+
> >+ KUNIT_EXPECT_EQ(test, map.reverse[i].first, i * 10);
> >+ KUNIT_EXPECT_EQ(test, map.reverse[i].lower_first, i * 100);
> >+ KUNIT_EXPECT_EQ(test, map.reverse[i].count, 5);
> >+ }
> >+
> >+ kfree(map.forward);
> >+ kfree(map.reverse);
> >+}
> >+
> >+static struct kunit_case user_ns_map_test_cases[] = {
> >+ KUNIT_CASE(user_ns_map_insert),
> >+ KUNIT_CASE(user_ns_map_insert_extended),
> >+ {}
> >+};
> >+
> >+static struct kunit_suite user_ns_map_test_suite = {
> >+ .name = "user_ns_map",
> >+ .test_cases = user_ns_map_test_cases,
> >+};
> >+
> >+kunit_test_suite(user_ns_map_test_suite);
> >+
> >+MODULE_LICENSE("GPL");
> >+MODULE_DESCRIPTION("KUnit test for user namespace map insertion");
> >+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
> >diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
> >index 786dbf0506ca..d8cbefd36598 100644
> >--- a/kernel/user_namespace.c
> >+++ b/kernel/user_namespace.c
> >@@ -1,5 +1,6 @@
> > // SPDX-License-Identifier: GPL-2.0-only
> >
> >+#include <kunit/visibility.h>
> > #include <linux/export.h>
> > #include <linux/nsproxy.h>
> > #include <linux/slab.h>
> >@@ -786,7 +787,8 @@ static bool mappings_overlap(struct uid_gid_map *new_map,
> > * Takes care to allocate a 4K block of memory if the number of mappings exceeds
> > * UID_GID_MAP_MAX_BASE_EXTENTS.
> > */
> >-static int insert_extent(struct uid_gid_map *map, struct uid_gid_extent *extent)
> >+VISIBLE_IF_KUNIT int insert_extent(struct uid_gid_map *map,
> >+ struct uid_gid_extent *extent)
> > {
> > struct uid_gid_extent *dest;
> >
> >@@ -822,6 +824,7 @@ static int insert_extent(struct uid_gid_map *map, struct uid_gid_extent *extent)
> > *dest = *extent;
> > return 0;
> > }
> >+EXPORT_SYMBOL_IF_KUNIT(insert_extent);
> >
> > /* cmp function to sort() forward mappings */
> > static int cmp_extents_forward(const void *a, const void *b)
> >@@ -857,7 +860,7 @@ static int cmp_extents_reverse(const void *a, const void *b)
> > * sort_idmaps - Sorts an array of idmap entries.
> > * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS.
> > */
> >-static int sort_idmaps(struct uid_gid_map *map)
> >+VISIBLE_IF_KUNIT int sort_idmaps(struct uid_gid_map *map)
> > {
> > if (map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
> > return 0;
> >@@ -878,6 +881,7 @@ static int sort_idmaps(struct uid_gid_map *map)
> >
> > return 0;
> > }
> >+EXPORT_SYMBOL_IF_KUNIT(sort_idmaps);
> >
> > /**
> > * verify_root_map() - check the uid 0 mapping
> >
>
> --- Thanks!
> https://lore.kernel.org/all/EE579805-42F2-4C58-B752-F28779EEB717@xxxxxxxxx/