Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

modpost: add support for symbol namespaces

Add support for symbols that are exported into namespaces. For that,
extract any namespace suffix from the symbol name. In addition, emit a
warning whenever a module refers to an exported symbol without
explicitly importing the namespace that it is defined in. This patch
consistently adds the namespace suffix to symbol names exported into
Module.symvers.

Example warning emitted by modpost in case of the above violation:

WARNING: module ums-usbat uses symbol usb_stor_resume from namespace
USB_STORAGE, but does not import it.

Co-developed-by: Martijn Coenen <maco@android.com>
Signed-off-by: Martijn Coenen <maco@android.com>
Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Matthias Maennich <maennich@google.com>
Signed-off-by: Jessica Yu <jeyu@kernel.org>

authored by

Matthias Maennich and committed by
Jessica Yu
cb9b55d2 8651ec01

+101 -19
+5 -2
Documentation/kbuild/modules.rst
··· 470 470 471 471 The syntax of the Module.symvers file is:: 472 472 473 - <CRC> <Symbol> <module> 473 + <CRC> <Symbol> <Namespace> <Module> <Export Type> 474 474 475 - 0x2d036834 scsi_remove_host drivers/scsi/scsi_mod 475 + 0xe1cc2a05 usb_stor_suspend USB_STORAGE drivers/usb/storage/usb-storage EXPORT_SYMBOL_GPL 476 + 477 + The fields are separated by tabs and values may be empty (e.g. 478 + if no namespace is defined for an exported symbol). 476 479 477 480 For a kernel build without CONFIG_MODVERSIONS enabled, the CRC 478 481 would read 0x00000000.
+1 -1
scripts/export_report.pl
··· 94 94 # 95 95 while ( <$module_symvers> ) { 96 96 chomp; 97 - my (undef, $symbol, $module, $gpl) = split; 97 + my (undef, $symbol, $namespace, $module, $gpl) = split('\t'); 98 98 $SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; 99 99 } 100 100 close($module_symvers);
+88 -16
scripts/mod/modpost.c
··· 164 164 struct module *module; 165 165 unsigned int crc; 166 166 int crc_valid; 167 + const char *namespace; 167 168 unsigned int weak:1; 168 169 unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */ 169 170 unsigned int kernel:1; /* 1 if symbol is from kernel ··· 232 231 return s; 233 232 } 234 233 return NULL; 234 + } 235 + 236 + static bool contains_namespace(struct namespace_list *list, 237 + const char *namespace) 238 + { 239 + struct namespace_list *ns_entry; 240 + 241 + for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next) 242 + if (strcmp(ns_entry->namespace, namespace) == 0) 243 + return true; 244 + 245 + return false; 246 + } 247 + 248 + static void add_namespace(struct namespace_list **list, const char *namespace) 249 + { 250 + struct namespace_list *ns_entry; 251 + 252 + if (!contains_namespace(*list, namespace)) { 253 + ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) + 254 + strlen(namespace) + 1)); 255 + strcpy(ns_entry->namespace, namespace); 256 + ns_entry->next = *list; 257 + *list = ns_entry; 258 + } 259 + } 260 + 261 + static bool module_imports_namespace(struct module *module, 262 + const char *namespace) 263 + { 264 + return contains_namespace(module->imported_namespaces, namespace); 235 265 } 236 266 237 267 static const struct { ··· 344 312 return export_unknown; 345 313 } 346 314 315 + static const char *sym_extract_namespace(const char **symname) 316 + { 317 + size_t n; 318 + char *dupsymname; 319 + 320 + n = strcspn(*symname, "."); 321 + if (n < strlen(*symname) - 1) { 322 + dupsymname = NOFAIL(strdup(*symname)); 323 + dupsymname[n] = '\0'; 324 + *symname = dupsymname; 325 + return dupsymname + n + 1; 326 + } 327 + 328 + return NULL; 329 + } 330 + 347 331 /** 348 332 * Add an exported symbol - it may have already been added without a 349 333 * CRC, in this case just update the CRC 350 334 **/ 351 - static struct symbol *sym_add_exported(const char *name, struct module *mod, 352 - enum export export) 335 + static struct symbol *sym_add_exported(const char *name, const char *namespace, 336 + struct module *mod, enum export export) 353 337 { 354 338 struct symbol *s = find_symbol(name); 355 339 356 340 if (!s) { 357 341 s = new_symbol(name, mod, export); 342 + s->namespace = namespace; 358 343 } else { 359 344 if (!s->preloaded) { 360 - warn("%s: '%s' exported twice. Previous export " 361 - "was in %s%s\n", mod->name, name, 362 - s->module->name, 363 - is_vmlinux(s->module->name) ?"":".ko"); 345 + warn("%s: '%s' exported twice. Previous export was in %s%s\n", 346 + mod->name, name, s->module->name, 347 + is_vmlinux(s->module->name) ? "" : ".ko"); 364 348 } else { 365 349 /* In case Module.symvers was out of date */ 366 350 s->module = mod; ··· 668 620 unsigned int crc; 669 621 enum export export; 670 622 bool is_crc = false; 623 + const char *name, *namespace; 671 624 672 625 if ((!is_vmlinux(mod->name) || mod->is_dot_o) && 673 626 strstarts(symname, "__ksymtab")) ··· 740 691 default: 741 692 /* All exported symbols */ 742 693 if (strstarts(symname, "__ksymtab_")) { 743 - sym_add_exported(symname + strlen("__ksymtab_"), mod, 744 - export); 694 + name = symname + strlen("__ksymtab_"); 695 + namespace = sym_extract_namespace(&name); 696 + sym_add_exported(name, namespace, mod, export); 745 697 } 746 698 if (strcmp(symname, "init_module") == 0) 747 699 mod->has_init = 1; ··· 1993 1943 const char *symname; 1994 1944 char *version; 1995 1945 char *license; 1946 + char *namespace; 1996 1947 struct module *mod; 1997 1948 struct elf_info info = { }; 1998 1949 Elf_Sym *sym; ··· 2023 1972 break; 2024 1973 } 2025 1974 license = get_next_modinfo(&info, "license", license); 1975 + } 1976 + 1977 + namespace = get_modinfo(&info, "import_ns"); 1978 + while (namespace) { 1979 + add_namespace(&mod->imported_namespaces, namespace); 1980 + namespace = get_next_modinfo(&info, "import_ns", namespace); 2026 1981 } 2027 1982 2028 1983 for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { ··· 2175 2118 basename++; 2176 2119 else 2177 2120 basename = mod->name; 2121 + 2122 + if (exp->namespace && 2123 + !module_imports_namespace(mod, exp->namespace)) { 2124 + warn("module %s uses symbol %s from namespace %s, but does not import it.\n", 2125 + basename, exp->name, exp->namespace); 2126 + } 2127 + 2178 2128 if (!mod->gpl_compatible) 2179 2129 check_for_gpl_usage(exp->export, basename, exp->name); 2180 2130 check_for_unused(exp->export, basename, exp->name); ··· 2405 2341 return; 2406 2342 2407 2343 while ((line = get_next_line(&pos, file, size))) { 2408 - char *symname, *modname, *d, *export, *end; 2344 + char *symname, *namespace, *modname, *d, *export, *end; 2409 2345 unsigned int crc; 2410 2346 struct module *mod; 2411 2347 struct symbol *s; ··· 2413 2349 if (!(symname = strchr(line, '\t'))) 2414 2350 goto fail; 2415 2351 *symname++ = '\0'; 2416 - if (!(modname = strchr(symname, '\t'))) 2352 + if (!(namespace = strchr(symname, '\t'))) 2353 + goto fail; 2354 + *namespace++ = '\0'; 2355 + if (!(modname = strchr(namespace, '\t'))) 2417 2356 goto fail; 2418 2357 *modname++ = '\0'; 2419 2358 if ((export = strchr(modname, '\t')) != NULL) ··· 2433 2366 mod = new_module(modname); 2434 2367 mod->skip = 1; 2435 2368 } 2436 - s = sym_add_exported(symname, mod, export_no(export)); 2369 + s = sym_add_exported(symname, namespace, mod, 2370 + export_no(export)); 2437 2371 s->kernel = kernel; 2438 2372 s->preloaded = 1; 2439 2373 sym_update_crc(symname, mod, crc, export_no(export)); ··· 2463 2395 { 2464 2396 struct buffer buf = { }; 2465 2397 struct symbol *symbol; 2398 + const char *namespace; 2466 2399 int n; 2467 2400 2468 2401 for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { 2469 2402 symbol = symbolhash[n]; 2470 2403 while (symbol) { 2471 - if (dump_sym(symbol)) 2472 - buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", 2473 - symbol->crc, symbol->name, 2474 - symbol->module->name, 2475 - export_str(symbol->export)); 2404 + if (dump_sym(symbol)) { 2405 + namespace = symbol->namespace; 2406 + buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n", 2407 + symbol->crc, symbol->name, 2408 + namespace ? namespace : "", 2409 + symbol->module->name, 2410 + export_str(symbol->export)); 2411 + } 2476 2412 symbol = symbol->next; 2477 2413 } 2478 2414 }
+7
scripts/mod/modpost.h
··· 109 109 void 110 110 buf_write(struct buffer *buf, const char *s, int len); 111 111 112 + struct namespace_list { 113 + struct namespace_list *next; 114 + char namespace[0]; 115 + }; 116 + 112 117 struct module { 113 118 struct module *next; 114 119 const char *name; ··· 126 121 struct buffer dev_table_buf; 127 122 char srcversion[25]; 128 123 int is_dot_o; 124 + // Actual imported namespaces 125 + struct namespace_list *imported_namespaces; 129 126 }; 130 127 131 128 struct elf_info {