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

Bill Wendling <[email protected]>
Newsgroups org.kernel.vger.linux-hardening,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add a KUnit test suite to verify the insertion and sorting of mappings
in struct uid_gid_map. This test suite validates both base extent
insertion (<= 5 mappings) and extended extent insertion (> 5 mappings,
which triggers the allocation of the forward and reverse pointers).

This is especially useful for verifying that the __counted_by_ptr
attribute added to 'forward' and 'reverse' pointers works correctly
without causing any runtime bounds-checking panics or traps.

Assisted-by: Gemini Next
Change-Id: If0c2c197a35cd7429cf0d2d6e3b33f0d9f0be66c
Signed-off-by: Bill Wendling <[email protected]>
---
Cc: Kees Cook <[email protected]>
Cc: "Gustavo A. R. Silva" <[email protected]>
Cc: Christian Brauner <[email protected]>
Cc: Aleksa Sarai <[email protected]>
Cc: Jan Kara <[email protected]>
Cc: Nathan Chancellor <[email protected]>
Cc: Miguel Ojeda <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Nicolas Schier <[email protected]>
Cc: Gary Guo <[email protected]>
Cc: "Thomas Weißschuh" <[email protected]>
Cc: Alice Ryhl <[email protected]>
Cc: Douglas Anderson <[email protected]>
Cc: Anand Moon <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
 init/Kconfig                  | 10 ++++
 kernel/.kunitconfig           |  3 ++
 kernel/user_namespace.c       |  4 ++
 kernel/user_namespace_kunit.c | 87 +++++++++++++++++++++++++++++++++++
 4 files changed, 104 insertions(+)
 create mode 100644 kernel/.kunitconfig
 create mode 100644 kernel/user_namespace_kunit.c

diff --git a/init/Kconfig b/init/Kconfig
index f63bf5e05e79..ba6a40b7315a 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1457,6 +1457,16 @@ config USER_NS
 
 	  If unsure, say N.
 
+config USER_NAMESPACE_KUNIT_TEST
+	tristate "KUnit test for user 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/.kunitconfig b/kernel/.kunitconfig
new file mode 100644
index 000000000000..7314dce05dc2
--- /dev/null
+++ b/kernel/.kunitconfig
@@ -0,0 +1,3 @@
+CONFIG_KUNIT=y
+CONFIG_USER_NS=y
+CONFIG_USER_NAMESPACE_KUNIT_TEST=y
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 7e5371d8f515..64c64e1028e8 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -1413,3 +1413,7 @@ static __init int user_namespaces_init(void)
 	return 0;
 }
 subsys_initcall(user_namespaces_init);
+
+#if IS_ENABLED(CONFIG_USER_NAMESPACE_KUNIT_TEST)
+#include "user_namespace_kunit.c"
+#endif
diff --git a/kernel/user_namespace_kunit.c b/kernel/user_namespace_kunit.c
new file mode 100644
index 000000000000..6d7662ef1916
--- /dev/null
+++ b/kernel/user_namespace_kunit.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit test for user namespace map insertion and sorting.
+ */
+
+#include <kunit/test.h>
+#include <linux/user_namespace.h>
+
+static void test_user_ns_map_insert_base(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 (5) 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_EXPECT_EQ(test, ret, 0);
+		KUNIT_EXPECT_EQ(test, map.nr_extents, i + 1);
+		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 test_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 (e.g., 10) elements */
+	for (i = 0; i < 10; i++) {
+		extent.first = i * 10;
+		extent.lower_first = i * 100;
+		extent.count = 5;
+
+		ret = insert_extent(&map, &extent);
+		KUNIT_EXPECT_EQ(test, ret, 0);
+		KUNIT_EXPECT_EQ(test, map.nr_extents, i + 1);
+
+		if (i < UID_GID_MAP_MAX_BASE_EXTENTS) {
+			KUNIT_EXPECT_EQ(test, map.extent[i].first, i * 10);
+		} else {
+			KUNIT_EXPECT_NOT_ERR_OR_NULL(test, map.forward);
+			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);
+		}
+	}
+
+	/* Now sort the map to set up reverse mapping */
+	ret = sort_idmaps(&map);
+	KUNIT_EXPECT_EQ(test, ret, 0);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, map.reverse);
+
+	/* Verify sorting is correct */
+	for (i = 0; i < map.nr_extents; i++) {
+		KUNIT_EXPECT_EQ(test, map.forward[i].count, 5);
+		KUNIT_EXPECT_EQ(test, map.reverse[i].count, 5);
+	}
+
+	/* Clean up allocations to avoid leaks */
+	kfree(map.forward);
+	kfree(map.reverse);
+}
+
+static struct kunit_case user_ns_map_test_cases[] = {
+	KUNIT_CASE(test_user_ns_map_insert_base),
+	KUNIT_CASE(test_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);
-- 
2.55.0.860.g4b6b3295ed-goog
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.