Support module tainting
authorEric Andersen <andersen@codepoet.org>
Mon, 16 Sep 2002 05:30:24 +0000 (05:30 -0000)
committerEric Andersen <andersen@codepoet.org>
Mon, 16 Sep 2002 05:30:24 +0000 (05:30 -0000)
 -Erik

modutils/insmod.c
modutils/lsmod.c

index 856c12a63fbc6c809d3d6d882b0a3650fe33086f..b246d90afef2d75ff7e794600410ce530a18291f 100644 (file)
@@ -71,6 +71,7 @@
 #include <assert.h>
 #include <string.h>
 #include <getopt.h>
+#include <fcntl.h>
 #include <sys/utsname.h>
 #include "busybox.h"
 
 #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;
index 5cb585babc50bdf734470dbc55685c4db86d10a5..3618ebe0bba9b5d6e6402525d87baa297e99a972 100644 (file)
 
 
 
+#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 ) {