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

Signed-off-by: Siddharth Nayyar <sidnay...@google.com>
---
 include/linux/module.h   |  1 +
 kernel/module/internal.h |  1 +
 kernel/module/main.c     | 47 ++++++++++++++++++++--------------------
 3 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/include/linux/module.h b/include/linux/module.h
index 3319a5269d28..9ba6ce433ac3 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -415,6 +415,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 c66b26184936..400d59a7f44b 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);
@@ -2607,6 +2605,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",
-- 
2.51.0.338.gd7d06c2dae-goog


Reply via email to