[PATCH v2 1/2] module: expose imported namespaces via sysfs

Nicholas Sielicki posted 2 patches 1 month ago
[PATCH v2 1/2] module: expose imported namespaces via sysfs
Posted by Nicholas Sielicki 1 month ago
Previously, the only way for userspace to inspect the symbol
namespaces a module imports is to locate the .ko on disk and invoke
modinfo(8) to decompress/parse the metadata. The kernel validated
namespaces at load time, but it was otherwise discarded.

Add /sys/module/*/import_ns to expose imported namespaces for
currently loaded modules. The file contains one namespace per line and
only exists for modules that import at least one namespace.

Signed-off-by: Nicholas Sielicki <linux@opensource.nslick.com>
---
 Documentation/ABI/testing/sysfs-module |  9 ++++
 include/linux/module.h                 |  1 +
 kernel/module/main.c                   | 69 +++++++++++++++++++++++++-
 3 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module
index 6bc9af6229f0..d5b7d19bd310 100644
--- a/Documentation/ABI/testing/sysfs-module
+++ b/Documentation/ABI/testing/sysfs-module
@@ -48,6 +48,15 @@ Contact:	Kay Sievers <kay.sievers@vrfy.org>
 Description:	Show the initialization state(live, coming, going) of
 		the module.
 
+What:		/sys/module/*/import_ns
+Date:		January 2026
+KernelVersion:	7.1
+Contact:	linux-modules@vger.kernel.org
+Description:	List of symbol namespaces imported by this module via
+		MODULE_IMPORT_NS(). Each namespace appears on a separate line.
+		This file only exists for modules that import at least one
+		namespace.
+
 What:		/sys/module/*/taint
 Date:		Jan 2012
 KernelVersion:	3.3
diff --git a/include/linux/module.h b/include/linux/module.h
index 14f391b186c6..60ed1c3e0ed9 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -413,6 +413,7 @@ struct module {
 	struct module_attribute *modinfo_attrs;
 	const char *version;
 	const char *srcversion;
+	const char *imported_namespaces;
 	struct kobject *holders_dir;
 
 	/* Exported symbols */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c3ce106c70af..53e421ff2ede 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -607,6 +607,36 @@ static const struct module_attribute modinfo_##field = {              \
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
+static void setup_modinfo_import_ns(struct module *mod, const char *s)
+{
+	mod->imported_namespaces = NULL;
+}
+
+static ssize_t show_modinfo_import_ns(const struct module_attribute *mattr,
+				      struct module_kobject *mk, char *buffer)
+{
+	return sysfs_emit(buffer, "%s\n", mk->mod->imported_namespaces);
+}
+
+static int modinfo_import_ns_exists(struct module *mod)
+{
+	return mod->imported_namespaces != NULL;
+}
+
+static void free_modinfo_import_ns(struct module *mod)
+{
+	kfree(mod->imported_namespaces);
+	mod->imported_namespaces = NULL;
+}
+
+static const struct module_attribute modinfo_import_ns = {
+	.attr = { .name = "import_ns", .mode = 0444 },
+	.show = show_modinfo_import_ns,
+	.setup = setup_modinfo_import_ns,
+	.test = modinfo_import_ns_exists,
+	.free = free_modinfo_import_ns,
+};
+
 static struct {
 	char name[MODULE_NAME_LEN];
 	char taints[MODULE_FLAGS_BUF_SIZE];
@@ -1058,6 +1088,7 @@ const struct module_attribute *const modinfo_attrs[] = {
 	&module_uevent,
 	&modinfo_version,
 	&modinfo_srcversion,
+	&modinfo_import_ns,
 	&modinfo_initstate,
 	&modinfo_coresize,
 #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC
@@ -1760,11 +1791,43 @@ static void module_license_taint_check(struct module *mod, const char *license)
 	}
 }
 
+static int copy_modinfo_import_ns(struct module *mod, struct load_info *info)
+{
+	char *ns;
+	size_t len, total_len = 0;
+	char *buf, *p;
+
+	for_each_modinfo_entry(ns, info, "import_ns")
+		total_len += strlen(ns) + 1;
+
+	if (!total_len) {
+		mod->imported_namespaces = NULL;
+		return 0;
+	}
+
+	buf = kmalloc(total_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	p = buf;
+	for_each_modinfo_entry(ns, info, "import_ns") {
+		len = strlen(ns);
+		memcpy(p, ns, len);
+		p += len;
+		*p++ = '\n';
+	}
+	/* Replace trailing newline with null terminator. */
+	*(p - 1) = '\0';
+
+	mod->imported_namespaces = buf;
+	return 0;
+}
+
 static int setup_modinfo(struct module *mod, struct load_info *info)
 {
 	const struct module_attribute *attr;
 	char *imported_namespace;
-	int i;
+	int i, err;
 
 	for (i = 0; (attr = modinfo_attrs[i]); i++) {
 		if (attr->setup)
@@ -1783,6 +1846,10 @@ static int setup_modinfo(struct module *mod, struct load_info *info)
 		}
 	}
 
+	err = copy_modinfo_import_ns(mod, info);
+	if (err)
+		return err;
+
 	return 0;
 }
 
-- 
2.53.0
Re: [PATCH v2 1/2] module: expose imported namespaces via sysfs
Posted by Peter Zijlstra 1 month ago
On Sat, Mar 07, 2026 at 03:00:09AM -0600, Nicholas Sielicki wrote:
> Previously, the only way for userspace to inspect the symbol
> namespaces a module imports is to locate the .ko on disk and invoke
> modinfo(8) to decompress/parse the metadata. The kernel validated
> namespaces at load time, but it was otherwise discarded.
> 
> Add /sys/module/*/import_ns to expose imported namespaces for
> currently loaded modules. The file contains one namespace per line and
> only exists for modules that import at least one namespace.

What I'm missing here is why users would care about this?
Re: [PATCH v2 1/2] module: expose imported namespaces via sysfs
Posted by Matthias Männich 1 month ago
On Sat, Mar 7, 2026 at 9:30 AM Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Sat, Mar 07, 2026 at 03:00:09AM -0600, Nicholas Sielicki wrote:
> > Previously, the only way for userspace to inspect the symbol
> > namespaces a module imports is to locate the .ko on disk and invoke
> > modinfo(8) to decompress/parse the metadata. The kernel validated
> > namespaces at load time, but it was otherwise discarded.
> >
> > Add /sys/module/*/import_ns to expose imported namespaces for
> > currently loaded modules. The file contains one namespace per line and
> > only exists for modules that import at least one namespace.
>
> What I'm missing here is why users would care about this?

FWIW, we use a symbol namespace in Android (GKI) [1] for symbols that
should not be used by all drivers (e.g. direct file system access).
This change would make it much easier to surface at runtime, which
drivers are using which namespace and thus have access to symbols they
should not.

Cheers,
Matthias

[1] https://android.googlesource.com/kernel/common/+/a38b207d4f4e02041f72a8168bb24d1617099988