Read kflagstab section for vmlinux and modules to determine whether
kernel symbols are GPL only.

This patch eliminates the need for fragmenting the ksymtab for infering
the value of GPL-only symbol flag, henceforth stop populating *_gpl
versions of the ksymtab and kcrctab in modpost.

Signed-off-by: Siddharth Nayyar <[email protected]>
Reviewed-by: Petr Pavlu <[email protected]>
---
 include/linux/export-internal.h | 21 ++++++++--------
 include/linux/module.h          |  1 +
 kernel/module/internal.h        |  1 +
 kernel/module/main.c            | 55 ++++++++++++++++++++++-------------------
 scripts/mod/modpost.c           |  8 +++---
 5 files changed, 46 insertions(+), 40 deletions(-)

diff --git a/include/linux/export-internal.h b/include/linux/export-internal.h
index 4123c7592404..726054614752 100644
--- a/include/linux/export-internal.h
+++ b/include/linux/export-internal.h
@@ -37,14 +37,14 @@
  * section flag requires it. Use '%progbits' instead of '@progbits' since the
  * former apparently works on all arches according to the binutils source.
  */
-#define __KSYMTAB(name, sym, sec, ns)                                          
\
+#define __KSYMTAB(name, sym, ns)                                               
\
        asm("   .section \"__ksymtab_strings\",\"aMS\",%progbits,1"     "\n"    
\
            "__kstrtab_" #name ":"                                      "\n"    
\
            "   .asciz \"" #name "\""                                   "\n"    
\
            "__kstrtabns_" #name ":"                                    "\n"    
\
            "   .asciz \"" ns "\""                                      "\n"    
\
            "   .previous"                                              "\n"    
\
-           "   .section \"___ksymtab" sec "+" #name "\", \"a\""        "\n"    
\
+           "   .section \"___ksymtab+" #name "\", \"a\""               "\n"    
\
                __KSYM_ALIGN                                            "\n"    
\
            "__ksymtab_" #name ":"                                      "\n"    
\
                __KSYM_REF(sym)                                         "\n"    
\
@@ -59,15 +59,16 @@
 #define KSYM_FUNC(name)                name
 #endif
 
-#define KSYMTAB_FUNC(name, sec, ns)    __KSYMTAB(name, KSYM_FUNC(name), sec, 
ns)
-#define KSYMTAB_DATA(name, sec, ns)    __KSYMTAB(name, name, sec, ns)
+#define KSYMTAB_FUNC(name, ns) __KSYMTAB(name, KSYM_FUNC(name), ns)
+#define KSYMTAB_DATA(name, ns) __KSYMTAB(name, name, ns)
 
-#define SYMBOL_CRC(sym, crc, sec)   \
-       asm(".section \"___kcrctab" sec "+" #sym "\",\"a\""     "\n" \
-           ".balign 4"                                         "\n" \
-           "__crc_" #sym ":"                                   "\n" \
-           ".long " #crc                                       "\n" \
-           ".previous"                                         "\n")
+#define SYMBOL_CRC(sym, crc)                                   \
+       asm("   .section \"___kcrctab+" #sym "\",\"a\"" "\n"    \
+           "   .balign 4"                              "\n"    \
+           "__crc_" #sym ":"                           "\n"    \
+           "   .long " #crc                            "\n"    \
+           "   .previous"                              "\n"    \
+       )
 
 #define SYMBOL_FLAGS(sym, flags)                                       \
        asm("   .section \"___kflagstab+" #sym "\",\"a\""       "\n"    \
diff --git a/include/linux/module.h b/include/linux/module.h
index 14f391b186c6..aee3accba73c 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -418,6 +418,7 @@ struct module {
        /* Exported symbols */
        const struct kernel_symbol *syms;
        const u32 *crcs;
+       const u8 *flagstab;
        unsigned int num_syms;
 
 #ifdef CONFIG_ARCH_USES_CFI_TRAPS
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 618202578b42..69b84510e097 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -57,6 +57,7 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
 extern const u32 __start___kcrctab[];
 extern const u32 __start___kcrctab_gpl[];
+extern const u8 __start___kflagstab[];
 
 #define KMOD_PATH_LEN 256
 extern char modprobe_path[];
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c3ce106c70af..d237fa4e0737 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -11,6 +11,7 @@
 #include <linux/extable.h>
 #include <linux/moduleloader.h>
 #include <linux/module_signature.h>
+#include <linux/module_symbol.h>
 #include <linux/trace_events.h>
 #include <linux/init.h>
 #include <linux/kallsyms.h>
@@ -87,7 +88,7 @@ struct mod_tree_root mod_tree __cacheline_aligned = {
 struct symsearch {
        const struct kernel_symbol *start, *stop;
        const u32 *crcs;
-       enum mod_license license;
+       const u8 *flagstab;
 };
 
 /*
@@ -364,19 +365,21 @@ static bool find_exported_symbol_in_section(const struct 
symsearch *syms,
                                            struct find_symbol_arg *fsa)
 {
        struct kernel_symbol *sym;
-
-       if (!fsa->gplok && syms->license == GPL_ONLY)
-               return false;
+       u8 sym_flags;
 
        sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
                        sizeof(struct kernel_symbol), cmp_name);
        if (!sym)
                return false;
 
+       sym_flags = *(syms->flagstab + (sym - syms->start));
+       if (!fsa->gplok && (sym_flags & KSYM_FLAG_GPL_ONLY))
+               return false;
+
        fsa->owner = owner;
        fsa->crc = symversion(syms->crcs, sym - syms->start);
        fsa->sym = sym;
-       fsa->license = syms->license;
+       fsa->license = (sym_flags & KSYM_FLAG_GPL_ONLY) ? GPL_ONLY : 
NOT_GPL_ONLY;
 
        return true;
 }
@@ -387,36 +390,31 @@ static bool find_exported_symbol_in_section(const struct 
symsearch *syms,
  */
 bool find_symbol(struct find_symbol_arg *fsa)
 {
-       static const struct symsearch arr[] = {
-               { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
-                 NOT_GPL_ONLY },
-               { __start___ksymtab_gpl, __stop___ksymtab_gpl,
-                 __start___kcrctab_gpl,
-                 GPL_ONLY },
+       const struct symsearch syms = {
+               .start          = __start___ksymtab,
+               .stop           = __stop___ksymtab,
+               .crcs           = __start___kcrctab,
+               .flagstab       = __start___kflagstab,
        };
        struct module *mod;
-       unsigned int i;
 
-       for (i = 0; i < ARRAY_SIZE(arr); i++)
-               if (find_exported_symbol_in_section(&arr[i], NULL, fsa))
-                       return true;
+       if (find_exported_symbol_in_section(&syms, NULL, fsa))
+               return true;
 
        list_for_each_entry_rcu(mod, &modules, list,
                                lockdep_is_held(&module_mutex)) {
-               struct symsearch arr[] = {
-                       { mod->syms, mod->syms + mod->num_syms, mod->crcs,
-                         NOT_GPL_ONLY },
-                       { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
-                         mod->gpl_crcs,
-                         GPL_ONLY },
+               const struct symsearch syms = {
+                       .start          = mod->syms,
+                       .stop           = mod->syms + mod->num_syms,
+                       .crcs           = mod->crcs,
+                       .flagstab       = mod->flagstab,
                };
 
                if (mod->state == MODULE_STATE_UNFORMED)
                        continue;
 
-               for (i = 0; i < ARRAY_SIZE(arr); i++)
-                       if (find_exported_symbol_in_section(&arr[i], mod, fsa))
-                               return true;
+               if (find_exported_symbol_in_section(&syms, mod, fsa))
+                       return true;
        }
 
        pr_debug("Failed to find symbol %s\n", fsa->name);
@@ -2614,6 +2612,7 @@ static int find_module_sections(struct module *mod, 
struct load_info *info)
                                     sizeof(*mod->gpl_syms),
                                     &mod->num_gpl_syms);
        mod->gpl_crcs = section_addr(info, "__kcrctab_gpl");
+       mod->flagstab = section_addr(info, "__kflagstab");
 
 #ifdef CONFIG_CONSTRUCTORS
        mod->ctors = section_objs(info, ".ctors",
@@ -2817,8 +2816,12 @@ static int move_module(struct module *mod, struct 
load_info *info)
        return ret;
 }
 
-static int check_export_symbol_versions(struct module *mod)
+static int check_export_symbol_sections(struct module *mod)
 {
+       if (mod->num_syms && !mod->flagstab) {
+               pr_err("%s: no flags for exported symbols\n", mod->name);
+               return -ENOEXEC;
+       }
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !mod->crcs) ||
            (mod->num_gpl_syms && !mod->gpl_crcs)) {
@@ -3434,7 +3437,7 @@ static int load_module(struct load_info *info, const char 
__user *uargs,
        if (err)
                goto free_unload;
 
-       err = check_export_symbol_versions(mod);
+       err = check_export_symbol_sections(mod);
        if (err)
                goto free_unload;
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 1d721fe67caf..9d96acce60a8 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1876,9 +1876,9 @@ static void add_exported_symbols(struct buffer *buf, 
struct module *mod)
                if (trim_unused_exports && !sym->used)
                        continue;
 
-               buf_printf(buf, "KSYMTAB_%s(%s, \"%s\", \"%s\");\n",
+               buf_printf(buf, "KSYMTAB_%s(%s, \"%s\");\n",
                           sym->is_func ? "FUNC" : "DATA", sym->name,
-                          sym->is_gpl_only ? "_gpl" : "", sym->namespace);
+                          sym->namespace);
 
                buf_printf(buf, "SYMBOL_FLAGS(%s, 0x%02x);\n",
                           sym->name, get_symbol_flags(sym));
@@ -1899,8 +1899,8 @@ static void add_exported_symbols(struct buffer *buf, 
struct module *mod)
                             sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
                             sym->name);
 
-               buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
-                          sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
+               buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x);\n",
+                          sym->name, sym->crc);
        }
 }
 

-- 
2.53.0.1018.g2bb0e51243-goog


Reply via email to