[patch] modinfo: check for module tainting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Helge Hafting suggested on lkml on 2004-april-28 that some program
check for module taintedness (without having to load each module).

Here's version 1 of that (extending 'modinfo'), along with another
fix to modinfo.

I've only tested this on x86-32 as that's all that I have access to.
If someone would test it on some other arch(es)....


Patches for module-init-tools 3.1 and 3.2-pre7 are also available at:

http://www.xenotime.net/linux/modinfo/modinfo-taint-31.patch
http://www.xenotime.net/linux/modinfo/modinfo-taint-32pre7.patch

Here's the patch to 3.2-pre7.

Comments?

---
~Randy



From: Randy Dunlap <[email protected]>

a.  Fix --field to require an argument so that it works.

b.  Add 'taint' checking to modinfo.
Note:  symbol version checking is not implemented yet [compare
kernel/module.c::check_version()].

Signed-off-by: Randy Dunlap <[email protected]>

diffstat:=
 Makefile.am   |    2 
 Makefile.in   |    2 
 modinfo.8     |   11 +++
 modinfo.c     |  184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 modversions.h |    8 ++
 5 files changed, 200 insertions(+), 7 deletions(-)

diff -Naurp module-init-tools-3.2-pre7/modinfo.8~taint module-init-tools-3.2-pre7/modinfo.8
--- module-init-tools-3.2-pre7/modinfo.8~taint	2004-08-26 02:11:07.000000000 -0700
+++ module-init-tools-3.2-pre7/modinfo.8	2005-06-15 17:06:55.000000000 -0700
@@ -56,7 +56,7 @@
 modinfo \(em program to show information about a Linux Kernel module 
 .SH "SYNOPSIS" 
 .PP 
-\fBmodinfo\fR [\fB-0\fP]  [\fB-F \fIfield\fR\fP]  [modulename|filename \&...]  
+\fBmodinfo\fR [\fB-0\fP]  [\fB-F \fIfield\fR\fP]  [\fB-T \fIkernelfile\fR\fP]  [modulename|filename \&...]  
 .PP 
 \fBmodinfo -V\fR 
 .PP 
@@ -77,6 +77,11 @@ filename is listed the same way (althoug
 attribute). 
  
 .PP 
+\fBmodinfo\fR with \fB-T\fR checks for modules that would 'taint'
+the Linux kernel if the module were loaded.  A kernel image file
+must be specified to check against.
+ 
+.PP 
 This version of \fBmodinfo\fR can understand 
 modules of any Linux Kernel architecture. 
 .SH "OPTIONS" 
@@ -108,6 +113,10 @@ These are shortcuts for \fBauthor\fP, 
 transition from the old modutils 
 \fBmodinfo\fR. 
  
+.IP "\fB-T\fP \fB--taint\fP         " 10 
+Check the module(s) for characteristics that would taint the
+Linux kernel.
+ 
 .SH "BACKWARDS COMPATIBILITY" 
 .PP 
 This version of \fBmodinfo\fR is for kernel 
diff -Naurp module-init-tools-3.2-pre7/modinfo.c~taint module-init-tools-3.2-pre7/modinfo.c
--- module-init-tools-3.2-pre7/modinfo.c~taint	2005-01-17 19:25:23.000000000 -0800
+++ module-init-tools-3.2-pre7/modinfo.c	2005-06-15 17:06:55.000000000 -0700
@@ -14,6 +14,9 @@
 #include <sys/mman.h>
 #include "zlibsupport.h"
 #include "backwards_compat.c"
+#include "modversions.h"
+
+#define DEBUG_TAINT	0
 
 #define streq(a,b) (strcmp((a),(b)) == 0)
 #define strstarts(a,start) (strncmp((a),(start), strlen(start)) == 0)
@@ -24,6 +27,8 @@
 
 static int elf_endian;
 static int my_endian;
+static int elf_class_size;	/* 1 = 32-bit, 2 = 64-bit */
+static int elf_class_div;
 
 static inline void __endian(const void *src, void *dest, unsigned int size)
 {
@@ -47,6 +52,7 @@ static void *get_section32(void *file, u
 	const char *secnames;
 	unsigned int i;
 
+	*size = 0;
 	secnames = file
 		+ TO_NATIVE(sechdrs[TO_NATIVE(hdr->e_shstrndx)].sh_offset);
 	for (i = 1; i < TO_NATIVE(hdr->e_shnum); i++)
@@ -82,6 +88,14 @@ static int elf_ident(void *mod, unsigned
 	if (size < EI_CLASS || memcmp(mod, ELFMAG, SELFMAG) != 0)
 		return ELFCLASSNONE;
 	elf_endian = ident[EI_DATA];
+	if (!elf_class_size) {
+#if DEBUG_TAINT
+		fprintf(stderr, "*** init. elf_class_size to %d ***\n",
+			ident[EI_CLASS]);
+#endif
+		elf_class_div = ident[EI_CLASS] == 1 ? 4 : 8;
+	}
+	elf_class_size = ident[EI_CLASS];
 	return ident[EI_CLASS];
 }
 
@@ -220,7 +234,8 @@ static struct option options[] =
 	{"version", 0, 0, 'V'},
 	{"help", 0, 0, 'h'},
 	{"null", 0, 0, '0'},
-	{"field", 0, 0, 'F'},
+	{"field", 1, 0, 'F'},
+	{"taint", 1, 0, 'T'},
 	{0, 0, 0, 0}
 };
 
@@ -320,13 +335,113 @@ static void *grab_module(const char *nam
 	return NULL;
 }
 
+static char *get_modinfo(void *info,
+			 unsigned long infosize,
+			 const char *tag)
+{
+	char *p;
+	unsigned int taglen = strlen(tag);
+
+	for (p = (char *)info; p; p = (char *)next_string(p, &infosize)) {
+		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+			return p + taglen + 1;
+	}
+	return NULL;
+}
+
+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 MPL/GPL") == 0);
+}
+
+static void check_license(const char *filename, const char *license)
+{
+	int license_gplok;
+
+	if (!license)
+		license = "unspecified";
+
+	license_gplok = license_is_gpl_compatible(license);
+	if (!license_gplok) {
+		printf("%s: module license '%s' taints kernel.\n",
+		       filename, license);
+	}
+}
+
+static int same_magic_modversions(const char *modmag, const char *kernmag)
+{
+	modmag += strcspn(modmag, " ");
+	kernmag += strcspn(kernmag, " ");
+	return strcmp(modmag, kernmag) == 0;
+}
+
+static void check_magic(const char *kernel, const char *filename, char *modmagic)
+{
+	char *buf;
+	ssize_t actual;
+	size_t n = 1024;
+	FILE *fkernel;
+	char kernel_magic[1024] = {0};
+
+	if (!modmagic) {
+		printf("%s: taint: No version magic\n",
+			filename);
+		return;
+	}
+
+	// check modmagic == vermagic (aka kernel_magic);
+
+	buf = malloc(1024);
+	if (!buf) {
+		fprintf(stderr, "modinfo: cannot malloc kernel image memory\n");
+		return;
+	}
+	fkernel = fopen(kernel, "r");
+	if (!fkernel) {
+		fprintf(stderr, "modinfo: could not open %s\n", kernel);
+		free (buf);
+		return;
+	}
+
+	for (;;) {
+		actual = getdelim(&buf, &n, 0, fkernel);
+		if (actual < 0)
+			break;
+		// sample kernel vermagic line to search for:
+		// "2.6.12-rc6 SMP PENTIUM4 gcc-3.3"
+		if (strncmp(buf, "2.6.", 4))
+			continue;
+		if (strstr(buf, "gcc-") == NULL)
+			continue;
+		strcpy(kernel_magic, buf);
+		break;
+	}
+#if DEBUG_TAINT
+	printf("*** got kernel_magic = [%s]\n", kernel_magic);
+#endif
+
+	// for CONFIG_MODVERSIONS=n:
+	if (strcmp(modmagic, kernel_magic))
+		printf("%s: taint: [for CONFIG_MODVERSIONS=n] version magic '%s' should be '%s'\n",
+			filename, modmagic, kernel_magic);
+	// and for CONFIG_MODVERSIONS=y:
+	if (!same_magic_modversions(modmagic, kernel_magic))
+		printf("%s: taint: [for CONFIG_MODVERSIONS=y] version magic '%s' should be '%s'\n",
+			filename, modmagic, kernel_magic);
+}
+
 static void usage(const char *name)
 {
-	fprintf(stderr, "Usage: %s [-0][-F field] module...\n"
+	fprintf(stderr, "Usage: %s [-0][-F field] [-T vmlinux] module...\n"
 		" Prints out the information about one or more module(s).\n"
 		" If a fieldname is given, just print out that field (or nothing if not found).\n"
 		" Otherwise, print all information out in a readable form\n"
-		" If -0 is given, separate with nul, not newline.\n",
+		" If -0 is given, separate with nul, not newline.\n"
+		" If -T is given, check the module for tainting the 'vmlinux' kernel.\n",
 		name);
 }
 
@@ -337,6 +452,8 @@ int main(int argc, char *argv[])
 	char sep = '\n';
 	unsigned long infosize;
 	int opt, ret = 0;
+	int check_taint = 0;
+	char *kernel = NULL;
 
 	if (!getenv("NEW_MODINFO"))
 		try_old_version("modinfo", argv);
@@ -347,7 +464,7 @@ int main(int argc, char *argv[])
 	else
 		abort();
 
-	while ((opt = getopt_long(argc,argv,"adlpVhn0F:",options,NULL)) >= 0){
+	while ((opt = getopt_long(argc,argv,"adlpVT:hn0F:",options,NULL)) >= 0){
 		switch (opt) {
 		case 'a': field = "author"; break;
 		case 'd': field = "description"; break;
@@ -355,6 +472,7 @@ int main(int argc, char *argv[])
 		case 'p': field = "parm"; break;
 		case 'n': field = "filename"; break;
 		case 'V': printf(PACKAGE " version " VERSION "\n"); exit(0);
+		case 'T': check_taint = 1; kernel = optarg; break;
 		case 'F': field = optarg; break;
 		case '0': sep = '\0'; break;
 		default:
@@ -368,6 +486,12 @@ int main(int argc, char *argv[])
 		void *info, *mod;
 		unsigned long modulesize;
 		char *filename;
+		void *exports, *gpls, *crc, *gplcrc,
+			*setup, *obs_parm, *versions;
+		unsigned long exports_size, gpls_size, crc_size,
+			gplcrc_size, setup_size, obs_parm_size, versions_size;
+		char *modmagic, *license;
+		int num_export_syms, num_gpl_syms, num_versions;
 
 		mod = grab_module(argv[opt], &modulesize, &filename);
 		if (!mod) {
@@ -382,6 +506,58 @@ int main(int argc, char *argv[])
 			print_tag(field, info, infosize, filename, sep);
 		else
 			print_all(info, infosize, filename, sep);
+
+		if (check_taint) {
+			exports = get_section(mod, modulesize, &exports_size,
+					"__ksymtab");
+			gpls = get_section(mod, modulesize, &gpls_size,
+					"__ksymtab_gpl");
+			crc = get_section(mod, modulesize, &crc_size,
+					"__kcrctab");
+			gplcrc = get_section(mod, modulesize, &gplcrc_size,
+					"__kcrctab_gpl");
+			setup = get_section(mod, modulesize, &setup_size,
+					"__param");
+			obs_parm = get_section(mod, modulesize, &obs_parm_size,
+					"__obsparm");
+			versions = get_section(mod, modulesize, &versions_size,
+					"__versions");
+			modmagic = get_modinfo(info, infosize, "vermagic");
+			license = get_modinfo(info, infosize, "license");
+
+			num_export_syms = exports_size / elf_class_div;
+			num_gpl_syms = gpls_size / elf_class_div;
+			num_versions = versions_size /
+					sizeof(struct modversion_info);
+
+#if DEBUG_TAINT
+			printf("*** export: %p, gpls: %p, crc: %p, gplcrc: %p, setup: %p, obs_parm: %p, versions: %p, modmagic: %p\n",
+				exports, gpls, crc, gplcrc,
+				setup, obs_parm, versions, modmagic);
+			printf("*** modmagic = [%s]\n", modmagic);
+			printf("*** license = [%s]\n", license);
+			printf("*** num_export_syms = %d\n", num_export_syms);
+			printf("*** num_gpl_syms = %d\n", num_gpl_syms);
+			printf("*** num_versions = %d\n", num_versions);
+#endif
+
+			check_license(filename, license);
+			check_magic(kernel, filename, modmagic);
+
+			if ((num_export_syms && !crc) ||
+			    (num_gpl_syms && !gplcrc))
+				printf("*** %s: taint [if CONFIG_MODVERSIONS=y]: "
+					"No versions for exported symbols.\n",
+					filename);
+			if (setup && obs_parm)
+				printf("*** %s: warning: ignoring new-style "
+					"parameters in presence of obsolete "
+					"ones\n", filename);
+			// TBD: check for symbol versions (crcs) as in
+			// check_version() [if CONFIG_MODVERSIONS];
+			fprintf(stderr, "%s: not checking symbol versions\n",
+				filename);
+		}
 		free(filename);
 	}
 	return ret;
diff -Naurp module-init-tools-3.2-pre7/modversions.h~taint module-init-tools-3.2-pre7/modversions.h
--- module-init-tools-3.2-pre7/modversions.h~taint	2005-06-15 17:06:07.000000000 -0700
+++ module-init-tools-3.2-pre7/modversions.h	2005-06-15 17:06:55.000000000 -0700
@@ -0,0 +1,8 @@
+
+#define MODULE_NAME_LEN (64 - sizeof(unsigned long))
+
+struct modversion_info
+{
+	unsigned long crc;
+	char name[MODULE_NAME_LEN];
+};
diff -Naurp module-init-tools-3.2-pre7/Makefile.am~taint module-init-tools-3.2-pre7/Makefile.am
--- module-init-tools-3.2-pre7/Makefile.am~taint	2005-05-26 19:32:55.000000000 -0700
+++ module-init-tools-3.2-pre7/Makefile.am	2005-06-15 17:06:55.000000000 -0700
@@ -3,7 +3,7 @@ lsmod_SOURCES = lsmod.c testing.h
 modprobe_SOURCES = modprobe.c zlibsupport.c testing.h zlibsupport.h
 rmmod_SOURCES = rmmod.c testing.h
 depmod_SOURCES = depmod.c moduleops.c tables.c zlibsupport.c depmod.h moduleops.h tables.h list.h testing.h  zlibsupport.h
-modinfo_SOURCES = modinfo.c zlibsupport.c testing.h zlibsupport.h
+modinfo_SOURCES = modinfo.c zlibsupport.c testing.h zlibsupport.h modversions.h
 
 insmod_static_SOURCES = insmod.c
 insmod_static_LDFLAGS = -static
diff -Naurp module-init-tools-3.2-pre7/Makefile.in~taint module-init-tools-3.2-pre7/Makefile.in
--- module-init-tools-3.2-pre7/Makefile.in~taint	2005-05-26 19:33:02.000000000 -0700
+++ module-init-tools-3.2-pre7/Makefile.in	2005-06-15 17:06:55.000000000 -0700
@@ -88,7 +88,7 @@ lsmod_SOURCES = lsmod.c testing.h
 modprobe_SOURCES = modprobe.c zlibsupport.c testing.h zlibsupport.h
 rmmod_SOURCES = rmmod.c testing.h
 depmod_SOURCES = depmod.c moduleops.c tables.c zlibsupport.c depmod.h moduleops.h tables.h list.h testing.h  zlibsupport.h
-modinfo_SOURCES = modinfo.c zlibsupport.c testing.h zlibsupport.h
+modinfo_SOURCES = modinfo.c zlibsupport.c testing.h zlibsupport.h modversions.h
 
 insmod_static_SOURCES = insmod.c
 insmod_static_LDFLAGS = -static
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux