aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/module.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2008-07-22 20:24:25 -0400
committerRusty Russell <rusty@rustcorp.com.au>2008-07-22 05:24:26 -0400
commitdafd0940c96fec67974a88ed8e6b8ba3160394cd (patch)
tree616da8f0f283509ec71ff2d6e467fa4c6877edc6 /kernel/module.c
parentda39ba5e1d65e997a98f6eb93ba6e6eb505f6e3c (diff)
module: generic each_symbol iterator function
Introduce an each_symbol() iterator to avoid duplicating the knowledge about the 5 different sections containing symbols. Currently only used by find_symbol(), but will be used by symbol_put_addr() too. (Includes NULL ptr deref fix by Jiri Kosina <jkosina@suse.cz>) Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Cc: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c244
1 files changed, 134 insertions, 110 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 705e1d5d516c..c51c089c666e 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -152,156 +152,180 @@ extern const unsigned long __start___kcrctab_unused_gpl[];
152#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL) 152#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
153#endif 153#endif
154 154
155/* lookup symbol in given range of kernel_symbols */
156static const struct kernel_symbol *lookup_symbol(const char *name,
157 const struct kernel_symbol *start,
158 const struct kernel_symbol *stop)
159{
160 const struct kernel_symbol *ks = start;
161 for (; ks < stop; ks++)
162 if (strcmp(ks->name, name) == 0)
163 return ks;
164 return NULL;
165}
166
167static bool always_ok(bool gplok, bool warn, const char *name)
168{
169 return true;
170}
171
172static bool printk_unused_warning(bool gplok, bool warn, const char *name)
173{
174 if (warn) {
175 printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
176 "however this module is using it.\n", name);
177 printk(KERN_WARNING
178 "This symbol will go away in the future.\n");
179 printk(KERN_WARNING
180 "Please evalute if this is the right api to use and if "
181 "it really is, submit a report the linux kernel "
182 "mailinglist together with submitting your code for "
183 "inclusion.\n");
184 }
185 return true;
186}
187
188static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name)
189{
190 if (!gplok)
191 return false;
192 return printk_unused_warning(gplok, warn, name);
193}
194
195static bool gpl_only(bool gplok, bool warn, const char *name)
196{
197 return gplok;
198}
199
200static bool warn_if_not_gpl(bool gplok, bool warn, const char *name)
201{
202 if (!gplok && warn) {
203 printk(KERN_WARNING "Symbol %s is being used "
204 "by a non-GPL module, which will not "
205 "be allowed in the future\n", name);
206 printk(KERN_WARNING "Please see the file "
207 "Documentation/feature-removal-schedule.txt "
208 "in the kernel source tree for more details.\n");
209 }
210 return true;
211}
212
213struct symsearch { 155struct symsearch {
214 const struct kernel_symbol *start, *stop; 156 const struct kernel_symbol *start, *stop;
215 const unsigned long *crcs; 157 const unsigned long *crcs;
216 bool (*check)(bool gplok, bool warn, const char *name); 158 enum {
159 NOT_GPL_ONLY,
160 GPL_ONLY,
161 WILL_BE_GPL_ONLY,
162 } licence;
163 bool unused;
217}; 164};
218 165
219/* Look through this array of symbol tables for a symbol match which 166static bool each_symbol_in_section(const struct symsearch *arr,
220 * passes the check function. */ 167 unsigned int arrsize,
221static const struct kernel_symbol *search_symarrays(const struct symsearch *arr, 168 struct module *owner,
222 unsigned int num, 169 bool (*fn)(const struct symsearch *syms,
223 const char *name, 170 struct module *owner,
224 bool gplok, 171 unsigned int symnum, void *data),
225 bool warn, 172 void *data)
226 const unsigned long **crc)
227{ 173{
228 unsigned int i; 174 unsigned int i, j;
229 const struct kernel_symbol *ks;
230
231 for (i = 0; i < num; i++) {
232 ks = lookup_symbol(name, arr[i].start, arr[i].stop);
233 if (!ks || !arr[i].check(gplok, warn, name))
234 continue;
235 175
236 if (crc) 176 for (j = 0; j < arrsize; j++) {
237 *crc = symversion(arr[i].crcs, ks - arr[i].start); 177 for (i = 0; i < arr[j].stop - arr[j].start; i++)
238 return ks; 178 if (fn(&arr[j], owner, i, data))
179 return true;
239 } 180 }
240 return NULL; 181
182 return false;
241} 183}
242 184
243/* Find a symbol, return value, (optional) crc and (optional) module 185/* Returns true as soon as fn returns true, otherwise false. */
244 * which owns it */ 186static bool each_symbol(bool (*fn)(const struct symsearch *arr,
245static unsigned long find_symbol(const char *name, 187 struct module *owner,
246 struct module **owner, 188 unsigned int symnum, void *data),
247 const unsigned long **crc, 189 void *data)
248 bool gplok,
249 bool warn)
250{ 190{
251 struct module *mod; 191 struct module *mod;
252 const struct kernel_symbol *ks;
253 const struct symsearch arr[] = { 192 const struct symsearch arr[] = {
254 { __start___ksymtab, __stop___ksymtab, __start___kcrctab, 193 { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
255 always_ok }, 194 NOT_GPL_ONLY, false },
256 { __start___ksymtab_gpl, __stop___ksymtab_gpl, 195 { __start___ksymtab_gpl, __stop___ksymtab_gpl,
257 __start___kcrctab_gpl, gpl_only }, 196 __start___kcrctab_gpl,
197 GPL_ONLY, false },
258 { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, 198 { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
259 __start___kcrctab_gpl_future, warn_if_not_gpl }, 199 __start___kcrctab_gpl_future,
200 WILL_BE_GPL_ONLY, false },
260 { __start___ksymtab_unused, __stop___ksymtab_unused, 201 { __start___ksymtab_unused, __stop___ksymtab_unused,
261 __start___kcrctab_unused, printk_unused_warning }, 202 __start___kcrctab_unused,
203 NOT_GPL_ONLY, true },
262 { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, 204 { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
263 __start___kcrctab_unused_gpl, gpl_only_unused_warning }, 205 __start___kcrctab_unused_gpl,
206 GPL_ONLY, true },
264 }; 207 };
265 208
266 /* Core kernel first. */ 209 if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
267 ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc); 210 return true;
268 if (ks) {
269 if (owner)
270 *owner = NULL;
271 return ks->value;
272 }
273 211
274 /* Now try modules. */
275 list_for_each_entry(mod, &modules, list) { 212 list_for_each_entry(mod, &modules, list) {
276 struct symsearch arr[] = { 213 struct symsearch arr[] = {
277 { mod->syms, mod->syms + mod->num_syms, mod->crcs, 214 { mod->syms, mod->syms + mod->num_syms, mod->crcs,
278 always_ok }, 215 NOT_GPL_ONLY, false },
279 { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, 216 { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
280 mod->gpl_crcs, gpl_only }, 217 mod->gpl_crcs,
218 GPL_ONLY, false },
281 { mod->gpl_future_syms, 219 { mod->gpl_future_syms,
282 mod->gpl_future_syms + mod->num_gpl_future_syms, 220 mod->gpl_future_syms + mod->num_gpl_future_syms,
283 mod->gpl_future_crcs, warn_if_not_gpl }, 221 mod->gpl_future_crcs,
222 WILL_BE_GPL_ONLY, false },
284 { mod->unused_syms, 223 { mod->unused_syms,
285 mod->unused_syms + mod->num_unused_syms, 224 mod->unused_syms + mod->num_unused_syms,
286 mod->unused_crcs, printk_unused_warning }, 225 mod->unused_crcs,
226 NOT_GPL_ONLY, true },
287 { mod->unused_gpl_syms, 227 { mod->unused_gpl_syms,
288 mod->unused_gpl_syms + mod->num_unused_gpl_syms, 228 mod->unused_gpl_syms + mod->num_unused_gpl_syms,
289 mod->unused_gpl_crcs, gpl_only_unused_warning }, 229 mod->unused_gpl_crcs,
230 GPL_ONLY, true },
290 }; 231 };
291 232
292 ks = search_symarrays(arr, ARRAY_SIZE(arr), 233 if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))
293 name, gplok, warn, crc); 234 return true;
294 if (ks) { 235 }
295 if (owner) 236 return false;
296 *owner = mod; 237}
297 return ks->value; 238
239struct find_symbol_arg {
240 /* Input */
241 const char *name;
242 bool gplok;
243 bool warn;
244
245 /* Output */
246 struct module *owner;
247 const unsigned long *crc;
248 unsigned long value;
249};
250
251static bool find_symbol_in_section(const struct symsearch *syms,
252 struct module *owner,
253 unsigned int symnum, void *data)
254{
255 struct find_symbol_arg *fsa = data;
256
257 if (strcmp(syms->start[symnum].name, fsa->name) != 0)
258 return false;
259
260 if (!fsa->gplok) {
261 if (syms->licence == GPL_ONLY)
262 return false;
263 if (syms->licence == WILL_BE_GPL_ONLY && fsa->warn) {
264 printk(KERN_WARNING "Symbol %s is being used "
265 "by a non-GPL module, which will not "
266 "be allowed in the future\n", fsa->name);
267 printk(KERN_WARNING "Please see the file "
268 "Documentation/feature-removal-schedule.txt "
269 "in the kernel source tree for more details.\n");
298 } 270 }
299 } 271 }
300 272
273 if (syms->unused && fsa->warn) {
274 printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
275 "however this module is using it.\n", fsa->name);
276 printk(KERN_WARNING
277 "This symbol will go away in the future.\n");
278 printk(KERN_WARNING
279 "Please evalute if this is the right api to use and if "
280 "it really is, submit a report the linux kernel "
281 "mailinglist together with submitting your code for "
282 "inclusion.\n");
283 }
284
285 fsa->owner = owner;
286 fsa->crc = symversion(syms->crcs, symnum);
287 fsa->value = syms->start[symnum].value;
288 return true;
289}
290
291/* Find a symbol, return value, (optional) crc and (optional) module
292 * which owns it */
293static unsigned long find_symbol(const char *name,
294 struct module **owner,
295 const unsigned long **crc,
296 bool gplok,
297 bool warn)
298{
299 struct find_symbol_arg fsa;
300
301 fsa.name = name;
302 fsa.gplok = gplok;
303 fsa.warn = warn;
304
305 if (each_symbol(find_symbol_in_section, &fsa)) {
306 if (owner)
307 *owner = fsa.owner;
308 if (crc)
309 *crc = fsa.crc;
310 return fsa.value;
311 }
312
301 DEBUGP("Failed to find symbol %s\n", name); 313 DEBUGP("Failed to find symbol %s\n", name);
302 return -ENOENT; 314 return -ENOENT;
303} 315}
304 316
317/* lookup symbol in given range of kernel_symbols */
318static const struct kernel_symbol *lookup_symbol(const char *name,
319 const struct kernel_symbol *start,
320 const struct kernel_symbol *stop)
321{
322 const struct kernel_symbol *ks = start;
323 for (; ks < stop; ks++)
324 if (strcmp(ks->name, name) == 0)
325 return ks;
326 return NULL;
327}
328
305/* Search for module by name: must hold module_mutex. */ 329/* Search for module by name: must hold module_mutex. */
306static struct module *find_module(const char *name) 330static struct module *find_module(const char *name)
307{ 331{