From 166fa4684f33579277f34d887537c2abefc9deb0 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Mon, 16 Sep 2002 05:30:24 +0000 Subject: Support module tainting -Erik --- modutils/insmod.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++- modutils/lsmod.c | 34 +++++++++++++++- 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/modutils/insmod.c b/modutils/insmod.c index 856c12a..b246d90 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c @@ -71,6 +71,7 @@ #include #include #include +#include #include #include "busybox.h" @@ -233,7 +234,7 @@ #ifndef MODUTILS_MODULE_H static const int MODUTILS_MODULE_H = 1; -#ident "$Id: insmod.c,v 1.89 2002/07/21 17:33:26 sandman Exp $" +#ident "$Id: insmod.c,v 1.90 2002/09/16 05:30:24 andersen Exp $" /* This file contains the structures used by the 2.0 and 2.1 kernels. We do not use the kernel headers directly because we do not wish @@ -454,7 +455,7 @@ int delete_module(const char *); #ifndef MODUTILS_OBJ_H static const int MODUTILS_OBJ_H = 1; -#ident "$Id: insmod.c,v 1.89 2002/07/21 17:33:26 sandman Exp $" +#ident "$Id: insmod.c,v 1.90 2002/09/16 05:30:24 andersen Exp $" /* The relocatable object is manipulated using elfin types. */ @@ -3421,7 +3422,117 @@ static void hide_special_symbols(struct obj_file *f) ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); } +static int obj_gpl_license(struct obj_file *f, const char **license) +{ + struct obj_section *sec; + /* This list must match *exactly* the list of allowable licenses in + * linux/include/linux/module.h. Checking for leading "GPL" will not + * work, somebody will use "GPL sucks, this is proprietary". + */ + static const char *gpl_licenses[] = { + "GPL", + "GPL v2", + "GPL and additional rights", + "Dual BSD/GPL", + "Dual MPL/GPL", + }; + + if ((sec = obj_find_section(f, ".modinfo"))) { + const char *value, *ptr, *endptr; + ptr = sec->contents; + endptr = ptr + sec->header.sh_size; + while (ptr < endptr) { + if ((value = strchr(ptr, '=')) && strncmp(ptr, "license", value-ptr) == 0) { + int i; + if (license) + *license = value+1; + for (i = 0; i < sizeof(gpl_licenses)/sizeof(gpl_licenses[0]); ++i) { + if (strcmp(value+1, gpl_licenses[i]) == 0) + return(0); + } + return(2); + } + if (strchr(ptr, '\0')) + ptr = strchr(ptr, '\0') + 1; + else + ptr = endptr; + } + } + return(1); +} + +#define TAINT_FILENAME "/proc/sys/kernel/tainted" +#define TAINT_PROPRIETORY_MODULE (1<<0) +#define TAINT_FORCED_MODULE (1<<1) +#define TAINT_UNSAFE_SMP (1<<2) +#define TAINT_URL "http://www.tux.org/lkml/#export-tainted" + +static void set_tainted(struct obj_file *f, int fd, char *m_name, + int kernel_has_tainted, int taint, const char *text1, const char *text2) +{ + char buf[80]; + int oldval; + static int first = 1; + if (fd < 0 && !kernel_has_tainted) + return; /* New modutils on old kernel */ + printf("Warning: loading %s will taint the kernel: %s%s\n", + m_name, text1, text2); + if (first) { + printf(" See %s for information about tainted modules\n", TAINT_URL); + first = 0; + } + if (fd >= 0) { + read(fd, buf, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + oldval = strtoul(buf, NULL, 10); + sprintf(buf, "%d\n", oldval | taint); + write(fd, buf, strlen(buf)); + } +} + +/* Check if loading this module will taint the kernel. */ +static void check_tainted_module(struct obj_file *f, char *m_name) +{ + static const char tainted_file[] = TAINT_FILENAME; + int fd, kernel_has_tainted; + const char *ptr; + + kernel_has_tainted = 1; + if ((fd = open(tainted_file, O_RDWR)) < 0) { + if (errno == ENOENT) + kernel_has_tainted = 0; + else if (errno == EACCES) + kernel_has_tainted = 1; + else { + perror(tainted_file); + kernel_has_tainted = 0; + } + } + switch (obj_gpl_license(f, &ptr)) { + case 0: + break; + case 1: + set_tainted(f, fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", ""); + break; + case 2: + /* The module has a non-GPL license so we pretend that the + * kernel always has a taint flag to get a warning even on + * kernels without the proc flag. + */ + set_tainted(f, fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr); + break; + default: + set_tainted(f, fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", ""); + break; + } + + if (flag_force_load) + set_tainted(f, fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", ""); + + if (fd >= 0) + close(fd); +} extern int insmod_main( int argc, char **argv) { @@ -3657,6 +3768,7 @@ extern int insmod_main( int argc, char **argv) goto out; } obj_allocate_commons(f); + check_tainted_module(f, m_name); /* done with the module name, on to the optional var=value arguments */ ++optind; diff --git a/modutils/lsmod.c b/modutils/lsmod.c index 5cb585b..3618ebe 100644 --- a/modutils/lsmod.c +++ b/modutils/lsmod.c @@ -41,6 +41,32 @@ +#define TAINT_FILENAME "/proc/sys/kernel/tainted" +#define TAINT_PROPRIETORY_MODULE (1<<0) +#define TAINT_FORCED_MODULE (1<<1) +#define TAINT_UNSAFE_SMP (1<<2) + +void check_tainted(void) +{ + int tainted; + FILE *f; + + tainted = 0; + if ((f = fopen(TAINT_FILENAME, "r"))) { + fscanf(f, "%d", &tainted); + fclose(f); + } + if (f && tainted) { + printf(" Tainted: %c%c%c", + tainted & TAINT_PROPRIETORY_MODULE ? 'P' : 'G', + tainted & TAINT_FORCED_MODULE ? 'F' : ' ', + tainted & TAINT_UNSAFE_SMP ? 'S' : ' '); + } + else { + printf(" Not tainted"); + } +} + #ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE struct module_info @@ -99,7 +125,10 @@ extern int lsmod_main(int argc, char **argv) } deps = xmalloc(depsize = 256); - printf("Module Size Used by\n"); + printf("Module Size Used by"); + check_tainted(); + printf("\n"); + for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) { if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) { if (errno == ENOENT) { @@ -149,7 +178,8 @@ extern int lsmod_main(int argc, char **argv) int fd, i; char line[128]; - puts("Module Size Used by"); + printf("Module Size Used by"); + check_tainted(); fflush(stdout); if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) { -- cgit v1.1