summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-09-14 11:04:56 +0100
committerMark Brown <broonie@kernel.org>2026-09-14 11:04:56 +0100
commit77b3361016c0d29cff7008b150dd1c967be900c4 (patch)
treea02a8ebb859c504b30e79fa77ef4984159ce2d32 /kernel
parent1bba356e2e939d6af42c002909b71ae9ef8ba403 (diff)
parentf30afd22d01612fc4cdc8008071ae5fce2f39665 (diff)
downloadlinux-next-77b3361016c0d29cff7008b150dd1c967be900c4.tar.gz
linux-next-77b3361016c0d29cff7008b150dd1c967be900c4.zip
Merge branch 'vfs.all' of https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/pid_namespace.c3
-rw-r--r--kernel/tests/.kunitconfig4
-rw-r--r--kernel/tests/user_ns_map_kunit.c98
-rw-r--r--kernel/user_namespace.c32
-rw-r--r--kernel/utsname.c1
6 files changed, 124 insertions, 15 deletions
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/pid_namespace.c b/kernel/pid_namespace.c
index d36afc58ee1d..8bc9edb40b78 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -238,9 +238,10 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
* kernel_wait4() will also block until our children traced from the
* parent namespace are detached and become EXIT_DEAD.
*/
+ /* Task work must not busy-loop the reaper, see signal_pending(). */
+ guard(no_notify_signal)();
do {
clear_thread_flag(TIF_SIGPENDING);
- clear_thread_flag(TIF_NOTIFY_SIGNAL);
rc = kernel_wait4(-1, NULL, __WALL, NULL);
} while (rc != -ECHILD);
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..033dccc6a535
--- /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 = uid_gid_map_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 = uid_gid_map_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 = uid_gid_map_sort(&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 0bed462e9b2a..98b0279b6cc6 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>
@@ -162,9 +163,6 @@ int create_user_ns(struct cred *new)
ns_tree_add(ns);
return 0;
fail_keyring:
-#ifdef CONFIG_PERSISTENT_KEYRINGS
- key_put(ns->persistent_keyring_register);
-#endif
ns_common_free(ns);
fail_free:
kmem_cache_free(user_ns_cachep, ns);
@@ -782,11 +780,13 @@ static bool mappings_overlap(struct uid_gid_map *new_map,
}
/*
- * insert_extent - Safely insert a new idmap extent into struct uid_gid_map.
+ * uid_gid_map_insert_extent - Safely insert a new idmap extent into
+ * struct uid_gid_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 uid_gid_map_insert_extent(struct uid_gid_map *map,
+ struct uid_gid_extent *extent)
{
struct uid_gid_extent *dest;
@@ -809,15 +809,20 @@ static int insert_extent(struct uid_gid_map *map, struct uid_gid_extent *extent)
map->reverse = NULL;
}
- if (map->nr_extents < UID_GID_MAP_MAX_BASE_EXTENTS)
- dest = &map->extent[map->nr_extents];
+ /*
+ * nr_extents must be updated before the extent and forward arrays are
+ * accessed, otherwise KSAN will assert an out-of-bounds error.
+ */
+ map->nr_extents++;
+ if (map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
+ dest = &map->extent[map->nr_extents - 1];
else
- dest = &map->forward[map->nr_extents];
+ dest = &map->forward[map->nr_extents - 1];
*dest = *extent;
- map->nr_extents++;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(uid_gid_map_insert_extent);
/* cmp function to sort() forward mappings */
static int cmp_extents_forward(const void *a, const void *b)
@@ -850,10 +855,10 @@ static int cmp_extents_reverse(const void *a, const void *b)
}
/*
- * sort_idmaps - Sorts an array of idmap entries.
+ * uid_gid_map_sort - 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 uid_gid_map_sort(struct uid_gid_map *map)
{
if (map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
return 0;
@@ -874,6 +879,7 @@ static int sort_idmaps(struct uid_gid_map *map)
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(uid_gid_map_sort);
/**
* verify_root_map() - check the uid 0 mapping
@@ -1042,7 +1048,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
(next_line != NULL))
goto out;
- ret = insert_extent(&new_map, &extent);
+ ret = uid_gid_map_insert_extent(&new_map, &extent);
if (ret < 0)
goto out;
ret = -EINVAL;
@@ -1086,7 +1092,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
* If we want to use binary search for lookup, this clones the extent
* array and sorts both copies.
*/
- ret = sort_idmaps(&new_map);
+ ret = uid_gid_map_sort(&new_map);
if (ret < 0)
goto out;
diff --git a/kernel/utsname.c b/kernel/utsname.c
index ebbfc578a9d3..1ebf87e24607 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -81,7 +81,6 @@ struct uts_namespace *copy_utsname(u64 flags,
{
struct uts_namespace *new_ns;
- BUG_ON(!old_ns);
get_uts_ns(old_ns);
if (!(flags & CLONE_NEWUTS))