return memcmp(s + slen - sublen, sub, sublen);
}
+/* if sym is empty or point to a string
+ * like ".[0-9]+" then return 1.
+ * This is the optional prefix added by ld to some sections
+ */
+static int number_prefix(const char *sym)
+{
+ if (*sym++ == '\0')
+ return 1;
+ if (*sym != '.')
+ return 0;
+ do {
+ char c = *sym++;
+ if (c < '0' || c > '9')
+ return 0;
+ } while (*sym);
+ return 1;
+}
+
+/* The pattern is an array of simple patterns.
+ * "foo" will match an exact string equal to "foo"
+ * "foo*" will match a string that begins with "foo"
+ * "foo$" will match a string equal to "foo" or "foo.1"
+ * where the '1' can be any number including several digits.
+ * The $ syntax is for sections where ld append a dot number
+ * to make section name unique.
+ */
+int match(const char *sym, const char * const pat[])
+{
+ const char *p;
+ while (*pat) {
+ p = *pat++;
+ const char *endp = p + strlen(p) - 1;
+
+ /* "foo*" */
+ if (*endp == '*') {
+ if (strncmp(sym, p, strlen(p) - 1) == 0)
+ return 1;
+ }
+ /* "foo$" */
+ else if (*endp == '$') {
+ if (strncmp(sym, p, strlen(p) - 1) == 0) {
+ if (number_prefix(sym + strlen(p) - 1))
+ return 1;
+ }
+ }
+ /* no wildcards */
+ else {
+ if (strcmp(p, sym) == 0)
+ return 1;
+ }
+ }
+ /* no match */
+ return 0;
+}
+
/*
* Functions used only during module init is marked __init and is stored in
* a .init.text section. Likewise data is marked __initdata and stored in
return 0;
}
+/* sections that we do not want to do full section mismatch check on */
+static const char *section_white_list[] =
+ { ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL };
+
+#define INIT_DATA_SECTIONS ".init.data$"
+#define EXIT_DATA_SECTIONS ".exit.data$"
+
+#define INIT_TEXT_SECTIONS ".init.text$"
+#define EXIT_TEXT_SECTIONS ".exit.text$"
+
+#define INIT_SECTIONS INIT_DATA_SECTIONS, INIT_TEXT_SECTIONS
+#define EXIT_SECTIONS EXIT_DATA_SECTIONS, EXIT_TEXT_SECTIONS
+
+#define DATA_SECTIONS ".data$"
+#define TEXT_SECTIONS ".text$"
+
+struct sectioncheck {
+ const char *fromsec[20];
+ const char *tosec[20];
+};
+
+const struct sectioncheck sectioncheck[] = {
+/* Do not reference init/exit code/data from
+ * normal code and data
+ */
+{
+ .fromsec = { TEXT_SECTIONS, DATA_SECTIONS, NULL },
+ .tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }
+},
+/* Do not use exit code/data from init code */
+{
+ .fromsec = { INIT_SECTIONS, NULL },
+ .tosec = { EXIT_SECTIONS, NULL },
+},
+/* Do not use init code/data from exit code */
+{
+ .fromsec = { EXIT_SECTIONS, NULL },
+ .tosec = { INIT_SECTIONS, NULL }
+},
+/* Do not export init/exit functions or data */
+{
+ .fromsec = { "__ksymtab*", NULL },
+ .tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }
+}
+};
+
+static int section_mismatch(const char *fromsec, const char *tosec)
+{
+ int i;
+ int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
+ const struct sectioncheck *check = §ioncheck[0];
+
+ for (i = 0; i < elems; i++) {
+ if (match(fromsec, check->fromsec) &&
+ match(tosec, check->tosec))
+ return 1;
+ check++;
+ }
+ return 0;
+}
+
+
/**
* Whitelist to allow certain references to pass with no warning.
*
* This pattern is identified by
* refsymname = __init_begin, _sinittext, _einittext
*
- * Pattern 5:
- * Xtensa uses literal sections for constants that are accessed PC-relative.
- * Literal sections may safely reference their text sections.
- * (Note that the name for the literal section omits any trailing '.text')
- * tosec = <section>[.text]
- * fromsec = <section>.literal
**/
static int secref_whitelist(const char *modname, const char *tosec,
const char *fromsec, const char *atsym,
const char *refsymname)
{
- int len;
const char **s;
const char *pat2sym[] = {
"driver",
if (strcmp(refsymname, *s) == 0)
return 1;
- /* Check for pattern 5 */
- if (strrcmp(tosec, ".text") == 0)
- len = strlen(tosec) - strlen(".text");
- else
- len = strlen(tosec);
- if ((strncmp(tosec, fromsec, len) == 0) && (strlen(fromsec) > len) &&
- (strcmp(fromsec + len, ".literal") == 0))
- return 1;
-
return 0;
}
}
static void section_rela(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr, int section(const char *),
- int section_ref_ok(const char *))
+ Elf_Shdr *sechdr)
{
Elf_Sym *sym;
Elf_Rela *rela;
fromsec = secstrings + sechdr->sh_name;
fromsec += strlen(".rela");
/* if from section (name) is know good then skip it */
- if (section_ref_ok(fromsec))
+ if (match(fromsec, section_white_list))
return;
for (rela = start; rela < stop; rela++) {
tosec = secstrings +
elf->sechdrs[sym->st_shndx].sh_name;
- if (section(tosec))
+ if (section_mismatch(fromsec, tosec))
warn_sec_mismatch(modname, fromsec, elf, sym, r);
}
}
static void section_rel(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr, int section(const char *),
- int section_ref_ok(const char *))
+ Elf_Shdr *sechdr)
{
Elf_Sym *sym;
Elf_Rel *rel;
fromsec = secstrings + sechdr->sh_name;
fromsec += strlen(".rel");
/* if from section (name) is know good then skip it */
- if (section_ref_ok(fromsec))
+ if (match(fromsec, section_white_list))
return;
for (rel = start; rel < stop; rel++) {
tosec = secstrings +
elf->sechdrs[sym->st_shndx].sh_name;
- if (section(tosec))
+ if (section_mismatch(fromsec, tosec))
warn_sec_mismatch(modname, fromsec, elf, sym, r);
}
}
* be discarded and warns about it.
**/
static void check_sec_ref(struct module *mod, const char *modname,
- struct elf_info *elf,
- int section(const char *),
- int section_ref_ok(const char *))
+ struct elf_info *elf)
{
int i;
Elf_Ehdr *hdr = elf->hdr;
for (i = 0; i < hdr->e_shnum; i++) {
/* We want to process only relocation sections and not .init */
if (sechdrs[i].sh_type == SHT_RELA)
- section_rela(modname, elf, &elf->sechdrs[i],
- section, section_ref_ok);
+ section_rela(modname, elf, &elf->sechdrs[i]);
else if (sechdrs[i].sh_type == SHT_REL)
- section_rel(modname, elf, &elf->sechdrs[i],
- section, section_ref_ok);
+ section_rel(modname, elf, &elf->sechdrs[i]);
}
}
-/*
- * Identify sections from which references to either a
- * .init or a .exit section is OK.
- *
- * [OPD] Keith Ownes <kaos@sgi.com> commented:
- * For our future {in}sanity, add a comment that this is the ppc .opd
- * section, not the ia64 .opd section.
- * ia64 .opd should not point to discarded sections.
- * [.rodata] like for .init.text we ignore .rodata references -same reason
- */
-static int initexit_section_ref_ok(const char *name)
-{
- const char **s;
- /* Absolute section names */
- const char *namelist1[] = {
- "__bug_table", /* used by powerpc for BUG() */
- "__ex_table",
- ".altinstructions",
- ".cranges", /* used by sh64 */
- ".fixup",
- ".machvec", /* ia64 + powerpc uses these */
- ".machine.desc",
- ".opd", /* See comment [OPD] */
- "__dbe_table",
- ".parainstructions",
- ".pdr",
- ".plt", /* seen on ARCH=um build on x86_64. Harmless */
- ".smp_locks",
- ".stab",
- ".m68k_fixup",
- ".xt.prop", /* xtensa informational section */
- ".xt.lit", /* xtensa informational section */
- NULL
- };
- /* Start of section names */
- const char *namelist2[] = {
- ".debug",
- ".eh_frame",
- ".note", /* ignore ELF notes - may contain anything */
- ".got", /* powerpc - global offset table */
- ".toc", /* powerpc - table of contents */
- NULL
- };
- /* part of section name */
- const char *namelist3 [] = {
- ".unwind", /* Sample: IA_64.unwind.exit.text */
- NULL
- };
-
- for (s = namelist1; *s; s++)
- if (strcmp(*s, name) == 0)
- return 1;
- for (s = namelist2; *s; s++)
- if (strncmp(*s, name, strlen(*s)) == 0)
- return 1;
- for (s = namelist3; *s; s++)
- if (strstr(name, *s) != NULL)
- return 1;
- return 0;
-}
-
-
-/*
- * Identify sections from which references to a .init section is OK.
- *
- * Unfortunately references to read only data that referenced .init
- * sections had to be excluded. Almost all of these are false
- * positives, they are created by gcc. The downside of excluding rodata
- * is that there really are some user references from rodata to
- * init code, e.g. drivers/video/vgacon.c:
- *
- * const struct consw vga_con = {
- * con_startup: vgacon_startup,
- *
- * where vgacon_startup is __init. If you want to wade through the false
- * positives, take out the check for rodata.
- */
-static int init_section_ref_ok(const char *name)
-{
- const char **s;
- /* Absolute section names */
- const char *namelist1[] = {
- "__dbe_table", /* MIPS generate these */
- "__ftr_fixup", /* powerpc cpu feature fixup */
- "__fw_ftr_fixup", /* powerpc firmware feature fixup */
- "__param",
- ".data.rel.ro", /* used by parisc64 */
- ".init",
- ".text.lock",
- NULL
- };
- /* Start of section names */
- const char *namelist2[] = {
- ".init.",
- ".pci_fixup",
- ".rodata",
- NULL
- };
-
- if (initexit_section_ref_ok(name))
- return 1;
-
- for (s = namelist1; *s; s++)
- if (strcmp(*s, name) == 0)
- return 1;
- for (s = namelist2; *s; s++)
- if (strncmp(*s, name, strlen(*s)) == 0)
- return 1;
-
- /* If section name ends with ".init" we allow references
- * as is the case with .initcallN.init, .early_param.init,
- * .taglist.init etc
- */
- if (strrcmp(name, ".init") == 0)
- return 1;
- return 0;
-}
-
-/*
- * Identify sections from which references to a .exit section is OK.
- */
-static int exit_section_ref_ok(const char *name)
-{
- const char **s;
- /* Absolute section names */
- const char *namelist1[] = {
- ".exit.data",
- ".exit.text",
- ".exitcall.exit",
- ".rodata",
- NULL
- };
-
- if (initexit_section_ref_ok(name))
- return 1;
-
- for (s = namelist1; *s; s++)
- if (strcmp(*s, name) == 0)
- return 1;
- return 0;
-}
-
static void read_symbols(char *modname)
{
const char *symname;
handle_moddevtable(mod, &info, sym, symname);
}
if (!is_vmlinux(modname) ||
- (is_vmlinux(modname) && vmlinux_section_warnings)) {
- check_sec_ref(mod, modname, &info, init_section, init_section_ref_ok);
- check_sec_ref(mod, modname, &info, exit_section, exit_section_ref_ok);
- }
+ (is_vmlinux(modname) && vmlinux_section_warnings))
+ check_sec_ref(mod, modname, &info);
version = get_modinfo(info.modinfo, info.modinfo_len, "version");
if (version)