Commit dafd0940c96fec67974a88ed8e6b8ba3160394cd
1 parent
da39ba5e1d
Exists in
master
and in
39 other branches
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>
Showing 1 changed file with 134 additions and 110 deletions Side-by-side Diff
kernel/module.c
... | ... | @@ -152,154 +152,178 @@ |
152 | 152 | #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL) |
153 | 153 | #endif |
154 | 154 | |
155 | -/* lookup symbol in given range of kernel_symbols */ | |
156 | -static 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 | - | |
167 | -static bool always_ok(bool gplok, bool warn, const char *name) | |
168 | -{ | |
169 | - return true; | |
170 | -} | |
171 | - | |
172 | -static 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 | - | |
188 | -static 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 | - | |
195 | -static bool gpl_only(bool gplok, bool warn, const char *name) | |
196 | -{ | |
197 | - return gplok; | |
198 | -} | |
199 | - | |
200 | -static 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 | - | |
213 | 155 | struct symsearch { |
214 | 156 | const struct kernel_symbol *start, *stop; |
215 | 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 | |
220 | - * passes the check function. */ | |
221 | -static const struct kernel_symbol *search_symarrays(const struct symsearch *arr, | |
222 | - unsigned int num, | |
223 | - const char *name, | |
224 | - bool gplok, | |
225 | - bool warn, | |
226 | - const unsigned long **crc) | |
166 | +static bool each_symbol_in_section(const struct symsearch *arr, | |
167 | + unsigned int arrsize, | |
168 | + struct module *owner, | |
169 | + bool (*fn)(const struct symsearch *syms, | |
170 | + struct module *owner, | |
171 | + unsigned int symnum, void *data), | |
172 | + void *data) | |
227 | 173 | { |
228 | - unsigned int i; | |
229 | - const struct kernel_symbol *ks; | |
174 | + unsigned int i, j; | |
230 | 175 | |
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 | - | |
236 | - if (crc) | |
237 | - *crc = symversion(arr[i].crcs, ks - arr[i].start); | |
238 | - return ks; | |
176 | + for (j = 0; j < arrsize; j++) { | |
177 | + for (i = 0; i < arr[j].stop - arr[j].start; i++) | |
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 | |
244 | - * which owns it */ | |
245 | -static unsigned long find_symbol(const char *name, | |
246 | - struct module **owner, | |
247 | - const unsigned long **crc, | |
248 | - bool gplok, | |
249 | - bool warn) | |
185 | +/* Returns true as soon as fn returns true, otherwise false. */ | |
186 | +static bool each_symbol(bool (*fn)(const struct symsearch *arr, | |
187 | + struct module *owner, | |
188 | + unsigned int symnum, void *data), | |
189 | + void *data) | |
250 | 190 | { |
251 | 191 | struct module *mod; |
252 | - const struct kernel_symbol *ks; | |
253 | 192 | const struct symsearch arr[] = { |
254 | 193 | { __start___ksymtab, __stop___ksymtab, __start___kcrctab, |
255 | - always_ok }, | |
194 | + NOT_GPL_ONLY, false }, | |
256 | 195 | { __start___ksymtab_gpl, __stop___ksymtab_gpl, |
257 | - __start___kcrctab_gpl, gpl_only }, | |
196 | + __start___kcrctab_gpl, | |
197 | + GPL_ONLY, false }, | |
258 | 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 | 201 | { __start___ksymtab_unused, __stop___ksymtab_unused, |
261 | - __start___kcrctab_unused, printk_unused_warning }, | |
202 | + __start___kcrctab_unused, | |
203 | + NOT_GPL_ONLY, true }, | |
262 | 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. */ | |
267 | - ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc); | |
268 | - if (ks) { | |
269 | - if (owner) | |
270 | - *owner = NULL; | |
271 | - return ks->value; | |
272 | - } | |
209 | + if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data)) | |
210 | + return true; | |
273 | 211 | |
274 | - /* Now try modules. */ | |
275 | 212 | list_for_each_entry(mod, &modules, list) { |
276 | 213 | struct symsearch arr[] = { |
277 | 214 | { mod->syms, mod->syms + mod->num_syms, mod->crcs, |
278 | - always_ok }, | |
215 | + NOT_GPL_ONLY, false }, | |
279 | 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 | 219 | { mod->gpl_future_syms, |
282 | 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 | 223 | { mod->unused_syms, |
285 | 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 | 227 | { mod->unused_gpl_syms, |
288 | 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), | |
293 | - name, gplok, warn, crc); | |
294 | - if (ks) { | |
295 | - if (owner) | |
296 | - *owner = mod; | |
297 | - return ks->value; | |
233 | + if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data)) | |
234 | + return true; | |
235 | + } | |
236 | + return false; | |
237 | +} | |
238 | + | |
239 | +struct 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 | + | |
251 | +static 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 */ | |
293 | +static 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 | 313 | DEBUGP("Failed to find symbol %s\n", name); |
302 | 314 | return -ENOENT; |
315 | +} | |
316 | + | |
317 | +/* lookup symbol in given range of kernel_symbols */ | |
318 | +static 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; | |
303 | 327 | } |
304 | 328 | |
305 | 329 | /* Search for module by name: must hold module_mutex. */ |