Skip to contentSkip to conversation

experimental: try-resolve-unexported-symbol-references-in-modules

PATCH In review [email protected] 2 participants 2 messages Jun 27, 2008 – Jun 28, 2008 Module support

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 experimental: try-resolve-unexported-symbol-references-in-modules

For purely experimental purposes, let the kernel resolve unexported-symbol references in external modules when loading them. Iff used carefully, this helps save time on development cycles. building testing experimenting certain kinds of changes becomes really fast.

Signed-off-by <[email protected]>

---

 include/linux/kallsyms.h |   11 +++++++++++
 include/linux/module.h   |   11 ++++++++---
 init/Kconfig             |   18 ++++++++++++++++++
 kernel/kallsyms.c        |   21 ++++++++++++++++++---
 kernel/module.c          |   31 ++++++++++++++++++++++++++++---
 5 files changed, 83 insertions(+), 9 deletions(-)
include/linux/kallsyms.h +11 -0
index 00c1801..f39569d 100644
@@ -13,8 +13,12 @@
 			 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1)
 
 #ifdef CONFIG_KALLSYMS
+struct module;
 /* Lookup the address for a symbol. Returns 0 if not found. */
 unsigned long kallsyms_lookup_name(const char *name);
+/* Like above, but this also tells which module (owner) defines the symbol,
+ * NULL if kernel or no symbol */
+unsigned long kallsyms_lookup_name_owner(const char *name, struct module **owner);
 
 extern int kallsyms_lookup_size_offset(unsigned long addr,
 				  unsigned long *symbolsize,
@@ -42,6 +46,13 @@ static inline unsigned long kallsyms_lookup_name(const char *name)
 	return 0;
 }
 
+static inline unsigned long kallsyms_lookup_name_owner(const char *name,
+		struct module **owner)
+{
+	if (owner) *owner = NULL;
+	return 0;
+}
+
 static inline int kallsyms_lookup_size_offset(unsigned long addr,
 					      unsigned long *symbolsize,
 					      unsigned long *offset)
include/linux/module.h +8 -3
index 3e03b1a..e99da01 100644
@@ -365,8 +365,11 @@ int is_module_address(unsigned long addr);
 int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 			char *name, char *module_name, int *exported);
 
-/* Look for this name: can be of form module:name. */
-unsigned long module_kallsyms_lookup_name(const char *name);
+/* Look for this name: can be of form module:name.
+ * If name is a module symbol, *owner will be set to struct module, NULL
+ * otherwise */
+unsigned long module_kallsyms_lookup_name(const char *name,
+		struct module **owner);
 
 extern void __module_put_and_exit(struct module *mod, long code)
 	__attribute__((noreturn));
@@ -528,8 +531,10 @@ static inline int module_get_kallsym(unsigned int symnum, unsigned long *value,
 	return -ERANGE;
 }
 
-static inline unsigned long module_kallsyms_lookup_name(const char *name)
+static inline unsigned long module_kallsyms_lookup_name(const char *name,
+		struct module **owner)
 {
+	if (owner) *owner = NULL;
 	return 0;
 }
 
init/Kconfig +18 -0
index 6199d11..c0c2810 100644
@@ -892,6 +892,24 @@ config MODULE_SRCVERSION_ALL
 	  the version).  With this option, such a "srcversion" field
 	  will be created for all modules.  If unsure, say N.
 
+config RESOLVE_UNEXPORTED_SYMBOL
+	bool "Try to resolve unexported symbols (experimental use only)"
+	depends on MODULES && KALLSYMS
+	default n
+	help
+	  Say Y here to let the kernel resolve unexported-symbol references
+	  in external modules when loading them. This taints the kernel with
+	  TAINT_PROPRIETARY_MODULE and TAINT_FORCED_MODULE, when the first
+	  unexported symbol gets resolved; this also bypasses version checks,
+	  if enabled, on such symbols. Use carefully.
+	  Building the kernel with KALLSYMS_ALL expands the range of symbols
+	  that can be referenced.
+	  This is purely for experimental purposes. Enable this config if you
+	  prefer experimenting in the kernel using loadable modules. Once the
+	  kernel gets tainted by resolving an unexported symbol, any subsequent
+	  kernel issue becomes the individual's responsibility to worry; do not
+	  report back those issues.
+
 config KMOD
 	bool "Automatic kernel module loading"
 	depends on MODULES
kernel/kallsyms.c +18 -3
index 6fc0040..f0e8928 100644
@@ -146,7 +146,8 @@ static unsigned int get_symbol_offset(unsigned long pos)
 }
 
 /* Lookup the address for this symbol. Returns 0 if not found. */
-unsigned long kallsyms_lookup_name(const char *name)
+static unsigned long __kallsyms_lookup_name_owner(const char *name,
+		struct module **owner)
 {
 	char namebuf[KSYM_NAME_LEN];
 	unsigned long i;
@@ -155,10 +156,24 @@ unsigned long kallsyms_lookup_name(const char *name)
 	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
 		off = kallsyms_expand_symbol(off, namebuf);
 
-		if (strcmp(namebuf, name) == 0)
+		if (strcmp(namebuf, name) == 0) {
+			if (owner)
+				*owner = NULL;
 			return kallsyms_addresses[i];
+		}
 	}
-	return module_kallsyms_lookup_name(name);
+	return module_kallsyms_lookup_name(name, owner);
+}
+
+unsigned long kallsyms_lookup_name(const char *name)
+{
+	return __kallsyms_lookup_name_owner(name, NULL);
+}
+
+unsigned long kallsyms_lookup_name_owner(const char *name,
+		struct module **owner)
+{
+	return __kallsyms_lookup_name_owner(name, owner);
 }
 
 static unsigned long get_symbol_pos(unsigned long addr,
kernel/module.c +28 -3
index 5f80478..c8863f1 100644
@@ -1001,13 +1001,30 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
 	struct module *owner;
 	unsigned long ret;
 	const unsigned long *crc;
+	int check_ver = 1;
 
 	ret = find_symbol(name, &owner, &crc,
 			  !(mod->taints & TAINT_PROPRIETARY_MODULE), true);
+
+#ifdef CONFIG_RESOLVE_UNEXPORTED_SYMBOL
+	if (IS_ERR_VALUE(ret)) {
+		unsigned long addr = kallsyms_lookup_name_owner(name, &owner);
+		check_ver = 0;
+		if (addr) {
+			ret = addr;
+			printk(KERN_WARNING "%s: Symbol %s not exported.. "
+				"resolved to %s:%lx - kernel tainted\n", mod->name,
+				name, owner ? owner->name : "", ret);
+			add_taint(TAINT_FORCED_MODULE);
+			add_taint(TAINT_PROPRIETARY_MODULE);
+		}
+	}
+#endif
+
 	if (!IS_ERR_VALUE(ret)) {
 		/* use_module can fail due to OOM,
 		   or module initialization or unloading */
-		if (!check_version(sechdrs, versindex, name, mod, crc) ||
+		if ((check_ver && !check_version(sechdrs, versindex, name, mod, crc)) ||
 		    !use_module(mod, owner))
 			ret = -EINVAL;
 	}
@@ -2435,8 +2452,12 @@ static unsigned long mod_find_symname(struct module *mod, const char *name)
 	return 0;
 }
 
-/* Look for this name: can be of form module:name. */
-unsigned long module_kallsyms_lookup_name(const char *name)
+/* Look for this name: can be of form module:name.
+ * if symbol found in a module, *owner will be set to its struct module,
+ * else NULL
+ */
+unsigned long module_kallsyms_lookup_name(const char *name,
+		struct module **owner)
 {
 	struct module *mod;
 	char *colon;
@@ -2455,6 +2476,10 @@ unsigned long module_kallsyms_lookup_name(const char *name)
 				break;
 	}
 	preempt_enable();
+
+	if (owner)
+		*owner = ret ? mod : NULL;
+
 	return ret;
 }
 #endif /* CONFIG_KALLSYMS */
#1 lore raw
Quoted 4 lines · On Friday 27 June 2008 22:40:50 [email protected] wrote:

For purely experimental purposes, let the kernel resolve unexported-symbol references in external modules when loading them. Iff used carefully, this helps save time on development cycles. building testing experimenting certain kinds of changes becomes really fast.

This is unlikely to ever get into the tree. And that's OK: AFAICT you can do it without any core kernel changes, by building a module which exports the symbols you need.

Cheers,
Rusty.