Commit dafd0940c96fec67974a88ed8e6b8ba3160394cd

Authored by Rusty Russell
1 parent da39ba5e1d

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

... ... @@ -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. */