Re: [PATCH] Check for license compliance at build time

From: Ram Pai
Date: Tue May 09 2006 - 16:57:30 EST


On Tue, 2006-05-09 at 19:31 +0200, Andreas Gruenbacher wrote:
> This patch on to of Ram Pai's modpost.diff patch at
> http://sudhaa.com/~ram/misc/kernelpatch implements license compliance testing
> in modpost. This prevents kbuild from producing modules that won't load.

Yes, I like this patch. Its a early warning system for a module having
no chance of getting inserted into the kernel.

Sam : do you want all these patches submitted togather?

RP


>
> Signed-off-by: Andreas Gruenbacher <agruen@xxxxxxx>
>
> Index: linux-2.6.16/include/linux/license.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6.16/include/linux/license.h
> @@ -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
> Index: linux-2.6.16/kernel/module.c
> ===================================================================
> --- linux-2.6.16.orig/kernel/module.c
> +++ linux-2.6.16/kernel/module.c
> @@ -43,6 +43,7 @@
> #include <asm/uaccess.h>
> #include <asm/semaphore.h>
> #include <asm/cacheflush.h>
> +#include <linux/license.h>
>
> #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)
> Index: linux-2.6.16/scripts/mod/modpost.c
> ===================================================================
> --- linux-2.6.16.orig/scripts/mod/modpost.c
> +++ linux-2.6.16/scripts/mod/modpost.c
> @@ -13,6 +13,7 @@
>
> #include <ctype.h>
> #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
> **/
> @@ -1244,6 +1296,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;
>
> buf.pos = 0;
>
> Index: linux-2.6.16/scripts/mod/modpost.h
> ===================================================================
> --- linux-2.6.16.orig/scripts/mod/modpost.h
> +++ linux-2.6.16/scripts/mod/modpost.h
> @@ -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;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/