Commit 1184aeda authored by Matt Domsch's avatar Matt Domsch Committed by Linus Torvalds

[PATCH] modules: put srcversion checksum in each modinfo section

Separate the module source and header checksum into a separate modinfo
field srcversion.

With CONFIG_MODULE_SRCVERSION_ALL=y, put srcversion into every module, not
just those with MODULE_VERSION("something").

Patch by Rusty Russell, trivial merging and testing by Matt Domsch
Signed-off-by: default avatarMatt Domsch <Matt_Domsch@dell.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 77bcf0fa
...@@ -141,11 +141,9 @@ extern struct module __this_module; ...@@ -141,11 +141,9 @@ extern struct module __this_module;
customizations, eg "rh3" or "rusty1". customizations, eg "rh3" or "rusty1".
Using this automatically adds a checksum of the .c files and the Using this automatically adds a checksum of the .c files and the
local headers to the end. Use MODULE_VERSION("") if you want just local headers in "srcversion".
this. Macro includes room for this.
*/ */
#define MODULE_VERSION(_version) \ #define MODULE_VERSION(_version) MODULE_INFO(version, _version)
MODULE_INFO(version, _version "\0xxxxxxxxxxxxxxxxxxxxxxxx")
/* Given an address, look for it in the exception tables */ /* Given an address, look for it in the exception tables */
const struct exception_table_entry *search_exception_tables(unsigned long add); const struct exception_table_entry *search_exception_tables(unsigned long add);
......
...@@ -389,6 +389,18 @@ config MODVERSIONS ...@@ -389,6 +389,18 @@ config MODVERSIONS
make them incompatible with the kernel you are running. If make them incompatible with the kernel you are running. If
unsure, say N. unsure, say N.
config MODULE_SRCVERSION_ALL
bool "Source checksum for all modules"
depends on MODULES
help
Modules which contain a MODULE_VERSION get an extra "srcversion"
field inserting into their modinfo section, which contains a
sum of the source files which made it. This helps maintainers
see exactly which source was used to build a module (since
others sometimes change the module source without updating
the version). With this option, such a "srcversion" field
will be created for all modules. If unsure, say N.
config KMOD config KMOD
bool "Automatic kernel module loading" bool "Automatic kernel module loading"
depends on MODULES depends on MODULES
......
...@@ -52,6 +52,7 @@ _modpost: $(modules) ...@@ -52,6 +52,7 @@ _modpost: $(modules)
quiet_cmd_modpost = MODPOST quiet_cmd_modpost = MODPOST
cmd_modpost = scripts/mod/modpost \ cmd_modpost = scripts/mod/modpost \
$(if $(CONFIG_MODVERSIONS),-m) \ $(if $(CONFIG_MODVERSIONS),-m) \
$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \
$(if $(KBUILD_EXTMOD),-i,-o) $(symverfile) \ $(if $(KBUILD_EXTMOD),-i,-o) $(symverfile) \
$(filter-out FORCE,$^) $(filter-out FORCE,$^)
......
/* Postprocess module symbol versions /* Postprocess module symbol versions
* *
* Copyright 2003 Kai Germaschewski * Copyright 2003 Kai Germaschewski
* 2002-2003 Rusty Russell, IBM Corporation * Copyright 2002-2004 Rusty Russell, IBM Corporation
* *
* Based in part on module-init-tools/depmod.c,file2alias * Based in part on module-init-tools/depmod.c,file2alias
* *
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
int modversions = 0; int modversions = 0;
/* Warn about undefined symbols? (do so if we have vmlinux) */ /* Warn about undefined symbols? (do so if we have vmlinux) */
int have_vmlinux = 0; int have_vmlinux = 0;
/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
static int all_versions = 0;
void void
fatal(const char *fmt, ...) fatal(const char *fmt, ...)
...@@ -397,10 +399,44 @@ is_vmlinux(const char *modname) ...@@ -397,10 +399,44 @@ is_vmlinux(const char *modname)
return strcmp(myname, "vmlinux") == 0; return strcmp(myname, "vmlinux") == 0;
} }
/* Parse tag=value strings from .modinfo section */
static char *next_string(char *string, unsigned long *secsize)
{
/* Skip non-zero chars */
while (string[0]) {
string++;
if ((*secsize)-- <= 1)
return NULL;
}
/* Skip any zero padding. */
while (!string[0]) {
string++;
if ((*secsize)-- <= 1)
return NULL;
}
return string;
}
static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
const char *tag)
{
char *p;
unsigned int taglen = strlen(tag);
unsigned long size = modinfo_len;
for (p = modinfo; p; p = next_string(p, &size)) {
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
return p + taglen + 1;
}
return NULL;
}
void void
read_symbols(char *modname) read_symbols(char *modname)
{ {
const char *symname; const char *symname;
char *version;
struct module *mod; struct module *mod;
struct elf_info info = { }; struct elf_info info = { };
Elf_Sym *sym; Elf_Sym *sym;
...@@ -424,8 +460,15 @@ read_symbols(char *modname) ...@@ -424,8 +460,15 @@ read_symbols(char *modname)
handle_modversions(mod, &info, sym, symname); handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname); handle_moddevtable(mod, &info, sym, symname);
} }
maybe_frob_version(modname, info.modinfo, info.modinfo_len,
(void *)info.modinfo - (void *)info.hdr); version = get_modinfo(info.modinfo, info.modinfo_len, "version");
if (version)
maybe_frob_rcs_version(modname, version, info.modinfo,
version - (char *)info.hdr);
if (version || (all_versions && !is_vmlinux(modname)))
get_src_version(modname, mod->srcversion,
sizeof(mod->srcversion)-1);
parse_elf_finish(&info); parse_elf_finish(&info);
/* Our trick to get versioning for struct_module - it's /* Our trick to get versioning for struct_module - it's
...@@ -570,6 +613,16 @@ add_depends(struct buffer *b, struct module *mod, struct module *modules) ...@@ -570,6 +613,16 @@ add_depends(struct buffer *b, struct module *mod, struct module *modules)
buf_printf(b, "\";\n"); buf_printf(b, "\";\n");
} }
void
add_srcversion(struct buffer *b, struct module *mod)
{
if (mod->srcversion[0]) {
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
mod->srcversion);
}
}
void void
write_if_changed(struct buffer *b, const char *fname) write_if_changed(struct buffer *b, const char *fname)
{ {
...@@ -691,7 +744,7 @@ main(int argc, char **argv) ...@@ -691,7 +744,7 @@ main(int argc, char **argv)
char *dump_read = NULL, *dump_write = NULL; char *dump_read = NULL, *dump_write = NULL;
int opt; int opt;
while ((opt = getopt(argc, argv, "i:mo:")) != -1) { while ((opt = getopt(argc, argv, "i:mo:a")) != -1) {
switch(opt) { switch(opt) {
case 'i': case 'i':
dump_read = optarg; dump_read = optarg;
...@@ -702,6 +755,9 @@ main(int argc, char **argv) ...@@ -702,6 +755,9 @@ main(int argc, char **argv)
case 'o': case 'o':
dump_write = optarg; dump_write = optarg;
break; break;
case 'a':
all_versions = 1;
break;
default: default:
exit(1); exit(1);
} }
...@@ -724,6 +780,7 @@ main(int argc, char **argv) ...@@ -724,6 +780,7 @@ main(int argc, char **argv)
add_versions(&buf, mod); add_versions(&buf, mod);
add_depends(&buf, mod, modules); add_depends(&buf, mod, modules);
add_moddevtable(&buf, mod); add_moddevtable(&buf, mod);
add_srcversion(&buf, mod);
sprintf(fname, "%s.mod.c", mod->name); sprintf(fname, "%s.mod.c", mod->name);
write_if_changed(&buf, fname); write_if_changed(&buf, fname);
......
...@@ -77,6 +77,7 @@ struct module { ...@@ -77,6 +77,7 @@ struct module {
int has_init; int has_init;
int has_cleanup; int has_cleanup;
struct buffer dev_table_buf; struct buffer dev_table_buf;
char srcversion[25];
}; };
struct elf_info { struct elf_info {
...@@ -95,10 +96,11 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, ...@@ -95,10 +96,11 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
void add_moddevtable(struct buffer *buf, struct module *mod); void add_moddevtable(struct buffer *buf, struct module *mod);
void maybe_frob_version(const char *modfilename, void maybe_frob_rcs_version(const char *modfilename,
char *version,
void *modinfo, void *modinfo,
unsigned long modinfo_len,
unsigned long modinfo_offset); unsigned long modinfo_offset);
void get_src_version(const char *modname, char sum[], unsigned sumlen);
void *grab_file(const char *filename, unsigned long *size); void *grab_file(const char *filename, unsigned long *size);
char* get_next_line(unsigned long *pos, void *file, unsigned long size); char* get_next_line(unsigned long *pos, void *file, unsigned long size);
......
...@@ -9,39 +9,6 @@ ...@@ -9,39 +9,6 @@
#include <string.h> #include <string.h>
#include "modpost.h" #include "modpost.h"
/* Parse tag=value strings from .modinfo section */
static char *next_string(char *string, unsigned long *secsize)
{
/* Skip non-zero chars */
while (string[0]) {
string++;
if ((*secsize)-- <= 1)
return NULL;
}
/* Skip any zero padding. */
while (!string[0]) {
string++;
if ((*secsize)-- <= 1)
return NULL;
}
return string;
}
static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
const char *tag)
{
char *p;
unsigned int taglen = strlen(tag);
unsigned long size = modinfo_len;
for (p = modinfo; p; p = next_string(p, &size)) {
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
return p + taglen + 1;
}
return NULL;
}
/* /*
* Stolen form Cryptographic API. * Stolen form Cryptographic API.
* *
...@@ -408,11 +375,11 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) ...@@ -408,11 +375,11 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
return ret; return ret;
} }
static int get_version(const char *modname, char sum[]) /* Calc and record src checksum. */
void get_src_version(const char *modname, char sum[], unsigned sumlen)
{ {
void *file; void *file;
unsigned long len; unsigned long len;
int ret = 0;
struct md4_ctx md; struct md4_ctx md;
char *sources, *end, *fname; char *sources, *end, *fname;
const char *basename; const char *basename;
...@@ -432,7 +399,7 @@ static int get_version(const char *modname, char sum[]) ...@@ -432,7 +399,7 @@ static int get_version(const char *modname, char sum[])
if (!file) { if (!file) {
fprintf(stderr, "Warning: could not find versions for %s\n", fprintf(stderr, "Warning: could not find versions for %s\n",
filelist); filelist);
return 0; return;
} }
sources = strchr(file, '\n'); sources = strchr(file, '\n');
...@@ -457,12 +424,9 @@ static int get_version(const char *modname, char sum[]) ...@@ -457,12 +424,9 @@ static int get_version(const char *modname, char sum[])
goto release; goto release;
} }
/* sum is of form \0<padding>. */ md4_final_ascii(&md, sum, sumlen);
md4_final_ascii(&md, sum, 1 + strlen(sum+1));
ret = 1;
release: release:
release_file(file, len); release_file(file, len);
return ret;
} }
static void write_version(const char *filename, const char *sum, static void write_version(const char *filename, const char *sum,
...@@ -492,12 +456,12 @@ static void write_version(const char *filename, const char *sum, ...@@ -492,12 +456,12 @@ static void write_version(const char *filename, const char *sum,
close(fd); close(fd);
} }
void strip_rcs_crap(char *version) static int strip_rcs_crap(char *version)
{ {
unsigned int len, full_len; unsigned int len, full_len;
if (strncmp(version, "$Revision", strlen("$Revision")) != 0) if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
return; return 0;
/* Space for version string follows. */ /* Space for version string follows. */
full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2; full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
...@@ -518,31 +482,15 @@ void strip_rcs_crap(char *version) ...@@ -518,31 +482,15 @@ void strip_rcs_crap(char *version)
len++; len++;
memmove(version + len, version + strlen(version), memmove(version + len, version + strlen(version),
full_len - strlen(version)); full_len - strlen(version));
return 1;
} }
/* If the modinfo contains a "version" value, then set this. */ /* Clean up RCS-style version numbers. */
void maybe_frob_version(const char *modfilename, void maybe_frob_rcs_version(const char *modfilename,
char *version,
void *modinfo, void *modinfo,
unsigned long modinfo_len, unsigned long version_offset)
unsigned long modinfo_offset)
{ {
char *version, *csum; if (strip_rcs_crap(version))
write_version(modfilename, version, version_offset);
version = get_modinfo(modinfo, modinfo_len, "version");
if (!version)
return;
/* RCS $Revision gets stripped out. */
strip_rcs_crap(version);
/* Check against double sumversion */
if (strchr(version, ' '))
return;
/* Version contains embedded NUL: second half has space for checksum */
csum = version + strlen(version);
*(csum++) = ' ';
if (get_version(modfilename, csum))
write_version(modfilename, version,
modinfo_offset + (version - (char *)modinfo));
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment