浏览代码

module: make module_address_lookup safe

module_address_lookup releases preemption then returns a pointer into
the module space.  The only user (kallsyms) copies the result, so just
do that under the preempt disable.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 17 年之前
父节点
当前提交
6dd06c9fbe
共有 3 个文件被更改,包括 30 次插入25 次删除
  1. 13 9
      include/linux/module.h
  2. 4 7
      kernel/kallsyms.c
  3. 13 9
      kernel/module.c

+ 13 - 9
include/linux/module.h

@@ -446,11 +446,14 @@ static inline void __module_get(struct module *module)
 	__mod ? __mod->name : "kernel";		\
 	__mod ? __mod->name : "kernel";		\
 })
 })
 
 
-/* For kallsyms to ask for address resolution.  NULL means not found. */
-const char *module_address_lookup(unsigned long addr,
-				  unsigned long *symbolsize,
-				  unsigned long *offset,
-				  char **modname);
+/* For kallsyms to ask for address resolution.  namebuf should be at
+ * least KSYM_NAME_LEN long: a pointer to namebuf is returned if
+ * found, otherwise NULL. */
+char *module_address_lookup(unsigned long addr,
+			    unsigned long *symbolsize,
+			    unsigned long *offset,
+			    char **modname,
+			    char *namebuf);
 int lookup_module_symbol_name(unsigned long addr, char *symname);
 int lookup_module_symbol_name(unsigned long addr, char *symname);
 int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
 int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
 
 
@@ -516,10 +519,11 @@ static inline void module_put(struct module *module)
 #define module_name(mod) "kernel"
 #define module_name(mod) "kernel"
 
 
 /* For kallsyms to ask for address resolution.  NULL means not found. */
 /* For kallsyms to ask for address resolution.  NULL means not found. */
-static inline const char *module_address_lookup(unsigned long addr,
-						unsigned long *symbolsize,
-						unsigned long *offset,
-						char **modname)
+static inline char *module_address_lookup(unsigned long addr,
+					  unsigned long *symbolsize,
+					  unsigned long *offset,
+					  char **modname,
+					  char *namebuf)
 {
 {
 	return NULL;
 	return NULL;
 }
 }

+ 4 - 7
kernel/kallsyms.c

@@ -233,10 +233,11 @@ static unsigned long get_symbol_pos(unsigned long addr,
 int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
 int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
 				unsigned long *offset)
 				unsigned long *offset)
 {
 {
+	char namebuf[KSYM_NAME_LEN];
 	if (is_ksym_addr(addr))
 	if (is_ksym_addr(addr))
 		return !!get_symbol_pos(addr, symbolsize, offset);
 		return !!get_symbol_pos(addr, symbolsize, offset);
 
 
-	return !!module_address_lookup(addr, symbolsize, offset, NULL);
+	return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf);
 }
 }
 
 
 /*
 /*
@@ -251,8 +252,6 @@ const char *kallsyms_lookup(unsigned long addr,
 			    unsigned long *offset,
 			    unsigned long *offset,
 			    char **modname, char *namebuf)
 			    char **modname, char *namebuf)
 {
 {
-	const char *msym;
-
 	namebuf[KSYM_NAME_LEN - 1] = 0;
 	namebuf[KSYM_NAME_LEN - 1] = 0;
 	namebuf[0] = 0;
 	namebuf[0] = 0;
 
 
@@ -268,10 +267,8 @@ const char *kallsyms_lookup(unsigned long addr,
 	}
 	}
 
 
 	/* see if it's in a module */
 	/* see if it's in a module */
-	msym = module_address_lookup(addr, symbolsize, offset, modname);
-	if (msym)
-		return strncpy(namebuf, msym, KSYM_NAME_LEN - 1);
-
+	return module_address_lookup(addr, symbolsize, offset, modname,
+				     namebuf);
 	return NULL;
 	return NULL;
 }
 }
 
 

+ 13 - 9
kernel/module.c

@@ -2230,14 +2230,13 @@ static const char *get_ksymbol(struct module *mod,
 	return mod->strtab + mod->symtab[best].st_name;
 	return mod->strtab + mod->symtab[best].st_name;
 }
 }
 
 
-/* For kallsyms to ask for address resolution.  NULL means not found.
-   We don't lock, as this is used for oops resolution and races are a
-   lesser concern. */
-/* FIXME: Risky: returns a pointer into a module w/o lock */
-const char *module_address_lookup(unsigned long addr,
-				  unsigned long *size,
-				  unsigned long *offset,
-				  char **modname)
+/* For kallsyms to ask for address resolution.  NULL means not found.  Careful
+ * not to lock to avoid deadlock on oopses, simply disable preemption. */
+char *module_address_lookup(unsigned long addr,
+			    unsigned long *size,
+			    unsigned long *offset,
+			    char **modname,
+			    char *namebuf)
 {
 {
 	struct module *mod;
 	struct module *mod;
 	const char *ret = NULL;
 	const char *ret = NULL;
@@ -2252,8 +2251,13 @@ const char *module_address_lookup(unsigned long addr,
 			break;
 			break;
 		}
 		}
 	}
 	}
+	/* Make a copy in here where it's safe */
+	if (ret) {
+		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
+		ret = namebuf;
+	}
 	preempt_enable();
 	preempt_enable();
-	return ret;
+	return (char *)ret;
 }
 }
 
 
 int lookup_module_symbol_name(unsigned long addr, char *symname)
 int lookup_module_symbol_name(unsigned long addr, char *symname)