History

module: expose imported namespaces via sysfs

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. 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. Exposing this data via sysfs provides a runtime mechanism to verify which namespaces are being used by modules. For example, this allows userspace to audit driver API access in Android GKI, which uses symbol namespaces to restrict vendor drivers from using specific kernel interfaces (e.g., direct filesystem access).

Nicholas Sielicki committed 8 months ago

Commit 3fe1dcb1 parent 44a063c3 files · +78 −1Browse files

Unified · Split

3 files
  1. Documentation/ABI/testing/sysfs-module +9 −0
  2. include/linux/module.h +1 −0
  3. kernel/module/main.c +68 −1
Documentation/ABI/testing/sysfs-module+9−0
@@ -48,6 +48,15 @@ Contact: Kay Sievers <kay.sievers@vrfy.org> · 47 unmodified lines
4848 Description: Show the initialization state(live, coming, going) of
4949 the module.
5050
51+What: /sys/module/*/import_ns
52+Date: January 2026
53+KernelVersion: 7.1
54+Contact: linux-modules@vger.kernel.org
55+Description: List of symbol namespaces imported by this module via
56+ MODULE_IMPORT_NS(). Each namespace appears on a separate line.
57+ This file only exists for modules that import at least one
58+ namespace.
59+
5160 What: /sys/module/*/taint
5261 Date: Jan 2012
5362 KernelVersion: 3.3
include/linux/module.h+1−0
@@ -413,6 +413,7 @@ struct module { · 412 unmodified lines
413413 struct module_attribute *modinfo_attrs;
414414 const char *version;
415415 const char *srcversion;
416+ const char *imported_namespaces;
416417 struct kobject *holders_dir;
417418
418419 /* Exported symbols */
kernel/module/main.c+68−1
@@ -607,6 +607,36 @@ static const struct module_attribute modinfo_##field = { \ · 606 unmodified lines
607607 MODINFO_ATTR(version);
608608 MODINFO_ATTR(srcversion);
609609
610+static void setup_modinfo_import_ns(struct module *mod, const char *s)
611+{
612+ mod->imported_namespaces = NULL;
613+}
614+
615+static ssize_t show_modinfo_import_ns(const struct module_attribute *mattr,
616+ struct module_kobject *mk, char *buffer)
617+{
618+ return sysfs_emit(buffer, "%s\n", mk->mod->imported_namespaces);
619+}
620+
621+static int modinfo_import_ns_exists(struct module *mod)
622+{
623+ return mod->imported_namespaces != NULL;
624+}
625+
626+static void free_modinfo_import_ns(struct module *mod)
627+{
628+ kfree(mod->imported_namespaces);
629+ mod->imported_namespaces = NULL;
630+}
631+
632+static const struct module_attribute modinfo_import_ns = {
633+ .attr = { .name = "import_ns", .mode = 0444 },
634+ .show = show_modinfo_import_ns,
635+ .setup = setup_modinfo_import_ns,
636+ .test = modinfo_import_ns_exists,
637+ .free = free_modinfo_import_ns,
638+};
639+
610640 static struct {
611641 char name[MODULE_NAME_LEN];
612642 char taints[MODULE_FLAGS_BUF_SIZE];
@@ -1058,6 +1088,7 @@ const struct module_attribute *const modinfo_attrs[] = { · 445 unmodified lines
10581088 &module_uevent,
10591089 &modinfo_version,
10601090 &modinfo_srcversion,
1091+ &modinfo_import_ns,
10611092 &modinfo_initstate,
10621093 &modinfo_coresize,
10631094 #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC
@@ -1760,11 +1791,43 @@ static void module_license_taint_check(struct module *mod, const char *license) · 696 unmodified lines
17601791 }
17611792 }
17621793
1794+static int copy_modinfo_import_ns(struct module *mod, struct load_info *info)
1795+{
1796+ char *ns;
1797+ size_t len, total_len = 0;
1798+ char *buf, *p;
1799+
1800+ for_each_modinfo_entry(ns, info, "import_ns")
1801+ total_len += strlen(ns) + 1;
1802+
1803+ if (!total_len) {
1804+ mod->imported_namespaces = NULL;
1805+ return 0;
1806+ }
1807+
1808+ buf = kmalloc(total_len, GFP_KERNEL);
1809+ if (!buf)
1810+ return -ENOMEM;
1811+
1812+ p = buf;
1813+ for_each_modinfo_entry(ns, info, "import_ns") {
1814+ len = strlen(ns);
1815+ memcpy(p, ns, len);
1816+ p += len;
1817+ *p++ = '\n';
1818+ }
1819+ /* Replace trailing newline with null terminator. */
1820+ *(p - 1) = '\0';
1821+
1822+ mod->imported_namespaces = buf;
1823+ return 0;
1824+}
1825+
17631826 static int setup_modinfo(struct module *mod, struct load_info *info)
17641827 {
17651828 const struct module_attribute *attr;
17661829 char *imported_namespace;
1767− int i;
1830+ int i, err;
17681831
17691832 for (i = 0; (attr = modinfo_attrs[i]); i++) {
17701833 if (attr->setup)
@@ -1783,6 +1846,10 @@ static int setup_modinfo(struct module *mod, struct load_info *info) · 12 unmodified lines
17831846 }
17841847 }
17851848
1849+ err = copy_modinfo_import_ns(mod, info);
1850+ if (err)
1851+ return err;
1852+
17861853 return 0;
17871854 }
17881855

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t