From: Andreas Gruenbacher Implements license compliance testing in modpost. This prevents kbuild from producing modules that won't load. Signed-off-by: Ram Pai Signed-off-by: Andreas Gruenbacher Cc: Sam Ravnborg Signed-off-by: Andrew Morton --- include/linux/license.h | 14 ++++++++ kernel/module.c | 11 ------ scripts/mod/modpost.c | 62 ++++++++++++++++++++++++++++++++++++-- scripts/mod/modpost.h | 1 4 files changed, 76 insertions(+), 12 deletions(-) diff -puN /dev/null include/linux/license.h --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/include/linux/license.h Thu May 11 11:30:14 2006 @@ -0,0 +1,14 @@ +#ifndef __LICENSE_H +#define __LICENSE_H + +static inline int license_is_gpl_compatible(const char *license) +{ + return (strcmp(license, "GPL") == 0 + || strcmp(license, "GPL v2") == 0 + || strcmp(license, "GPL and additional rights") == 0 + || strcmp(license, "Dual BSD/GPL") == 0 + || strcmp(license, "Dual MIT/GPL") == 0 + || strcmp(license, "Dual MPL/GPL") == 0); +} + +#endif diff -puN kernel/module.c~kbuild-prevent-building-modules-that-wont-load kernel/module.c --- 25/kernel/module.c~kbuild-prevent-building-modules-that-wont-load Thu May 11 11:30:14 2006 +++ 25-akpm/kernel/module.c Thu May 11 11:30:14 2006 @@ -43,6 +43,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -1248,16 +1249,6 @@ static void layout_sections(struct modul } } -static inline int license_is_gpl_compatible(const char *license) -{ - return (strcmp(license, "GPL") == 0 - || strcmp(license, "GPL v2") == 0 - || strcmp(license, "GPL and additional rights") == 0 - || strcmp(license, "Dual BSD/GPL") == 0 - || strcmp(license, "Dual MIT/GPL") == 0 - || strcmp(license, "Dual MPL/GPL") == 0); -} - static void set_license(struct module *mod, const char *license) { if (!license) diff -puN scripts/mod/modpost.c~kbuild-prevent-building-modules-that-wont-load scripts/mod/modpost.c --- 25/scripts/mod/modpost.c~kbuild-prevent-building-modules-that-wont-load Thu May 11 11:30:14 2006 +++ 25-akpm/scripts/mod/modpost.c Thu May 11 11:30:14 2006 @@ -13,6 +13,7 @@ #include #include "modpost.h" +#include "../../include/linux/license.h" /* Are we using CONFIG_MODVERSIONS? */ int modversions = 0; @@ -101,6 +102,7 @@ static struct module *new_module(char *m /* add to list */ mod->name = p; + mod->gpl_compatible = -1; mod->next = modules; modules = mod; @@ -454,13 +456,18 @@ static char *next_string(char *string, u return string; } -static char *get_modinfo(void *modinfo, unsigned long modinfo_len, - const char *tag) +static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, + const char *tag, char *info) { char *p; unsigned int taglen = strlen(tag); unsigned long size = modinfo_len; + if (info) { + size -= info - (char *)modinfo; + modinfo = next_string(info, &size); + } + for (p = modinfo; p; p = next_string(p, &size)) { if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') return p + taglen + 1; @@ -468,6 +475,13 @@ static char *get_modinfo(void *modinfo, return NULL; } +static char *get_modinfo(void *modinfo, unsigned long modinfo_len, + const char *tag) + +{ + return get_next_modinfo(modinfo, modinfo_len, tag, NULL); +} + /** * Test if string s ends in string sub * return 0 if match @@ -888,6 +902,7 @@ static void read_symbols(char *modname) { const char *symname; char *version; + char *license; struct module *mod; struct elf_info info = { }; Elf_Sym *sym; @@ -903,6 +918,18 @@ static void read_symbols(char *modname) mod->skip = 1; } + license = get_modinfo(info.modinfo, info.modinfo_len, "license"); + while (license) { + if (license_is_gpl_compatible(license)) + mod->gpl_compatible = 1; + else { + mod->gpl_compatible = 0; + break; + } + license = get_next_modinfo(info.modinfo, info.modinfo_len, + "license", license); + } + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { symname = info.strtab + sym->st_name; @@ -959,6 +986,31 @@ void buf_write(struct buffer *buf, const buf->pos += len; } +void check_license(struct module *mod) +{ + struct symbol *s, *exp; + + for (s = mod->unres; s; s = s->next) { + if (mod->gpl_compatible == 1) { + /* GPL-compatible modules may use all symbols */ + continue; + } + exp = find_symbol(s->name); + if (!exp || exp->module == mod) + continue; + if (exp->export_type == 1) { + const char *basename = strrchr(mod->name, '/'); + if (basename) + basename++; + + fatal("modpost: GPL-incompatible module %s uses the " + "GPL-only symbol %s\n", + basename ? basename : mod->name, + exp->name); + } + } +} + /** * Header for the generated file **/ @@ -1242,6 +1294,12 @@ int main(int argc, char **argv) } for (mod = modules; mod; mod = mod->next) { + if (mod->skip) + continue; + check_license(mod); + } + + for (mod = modules; mod; mod = mod->next) { if (mod->skip) continue; diff -puN scripts/mod/modpost.h~kbuild-prevent-building-modules-that-wont-load scripts/mod/modpost.h --- 25/scripts/mod/modpost.h~kbuild-prevent-building-modules-that-wont-load Thu May 11 11:30:14 2006 +++ 25-akpm/scripts/mod/modpost.h Thu May 11 11:30:14 2006 @@ -81,6 +81,7 @@ buf_write(struct buffer *buf, const char struct module { struct module *next; const char *name; + int gpl_compatible; struct symbol *unres; int seen; int skip; _