PATCH: get_module_symbol() not SMP-safe

From: David Woodhouse (David.Woodhouse@mvhi.com)
Date: Sun May 07 2000 - 10:46:39 EST


Unless I'm missing something, there was previously no guarantee, when you
call get_module_symbol and subsequently dereference the pointer it
returns, that the module containing your symbol will still be present by
the time you use it.

This patch changes get_module_symbol to increment the use count of the
module when the lookup is successful, and adds the corresponding
put_module_symbol function which decrements the use count again, given the
value of the symbol.

drivers/net/8290.h wants changing to reflect this.

--- ./include/linux/module.h.smpgetsym Sun May 7 16:30:57 2000
+++ ./include/linux/module.h Sun May 7 16:32:43 2000
@@ -144,6 +144,7 @@
 
 /* Find a symbol exported by the kernel or another module */
 extern unsigned long get_module_symbol(char *, char *);
+extern void put_module_symbol(unsigned long);
 
 extern int try_inc_mod_count(struct module *mod);
 
--- ./kernel/module.c.smpgetsym Sun May 7 16:30:57 2000
+++ ./kernel/module.c Sun May 7 16:37:45 2000
@@ -973,7 +973,9 @@
  * Gets the address for a symbol in the given module. If modname is
  * NULL, it looks for the name in any registered symbol table. If the
  * modname is an empty string, it looks for the symbol in kernel exported
- * symbol tables.
+ * symbol tables. Increase the usage count of the module in which the
+ * symbol was found - it's the only way we can guarantee that it's still
+ * there by the time our caller actually uses it.
  */
 unsigned long
 get_module_symbol(char *modname, char *symname)
@@ -982,20 +984,48 @@
         struct module_symbol *sym;
         int i;
 
+ spin_lock(&unload_lock);
         for (mp = module_list; mp; mp = mp->next) {
                 if (((modname == NULL) || (strcmp(mp->name, modname) == 0)) &&
- MOD_CAN_QUERY(mp) &&
+ MOD_CAN_QUERY(mp) && !(mp->flags & MOD_DELETED) &&
                         (mp->nsyms > 0)) {
                         for (i = mp->nsyms, sym = mp->syms;
                                 i > 0; --i, ++sym) {
 
                                 if (strcmp(sym->name, symname) == 0) {
+ __MOD_INC_USE_COUNT(mp);
+ spin_unlock(&unload_lock);
                                         return sym->value;
                                 }
                         }
                 }
         }
+ spin_unlock(&unload_lock);
         return 0;
+}
+
+/* Decrease the use count of the module containing a symbol with the
+ * address passed.
+ */
+void put_module_symbol(unsigned long deadsym)
+{
+ struct module *mp;
+ struct module_symbol *sym;
+ int i;
+
+ for (mp = module_list; mp; mp = mp->next) {
+ if (MOD_CAN_QUERY(mp) &&
+ (mp->nsyms > 0)) {
+ for (i = mp->nsyms, sym = mp->syms;
+ i > 0; --i, ++sym) {
+
+ if (sym->value == deadsym) {
+ __MOD_DEC_USE_COUNT(mp);
+ return;
+ }
+ }
+ }
+ }
 }
 
 /*
--- ./kernel/ksyms.c.smpgetsym Sun May 7 16:30:57 2000
+++ ./kernel/ksyms.c Sun May 7 16:31:41 2000
@@ -85,6 +85,7 @@
 
 #ifdef CONFIG_MODULES
 EXPORT_SYMBOL(get_module_symbol);
+EXPORT_SYMBOL(put_module_symbol);
 EXPORT_SYMBOL(try_inc_mod_count);
 #endif
 EXPORT_SYMBOL(get_option);

--
dwmw2

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun May 07 2000 - 21:00:21 EST