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;
customizations, eg "rh3" or "rusty1".
Using this automatically adds a checksum of the .c files and the
local headers to the end. Use MODULE_VERSION("") if you want just
this. Macro includes room for this.
local headers in "srcversion".
*/
#define MODULE_VERSION(_version) \
MODULE_INFO(version, _version "\0xxxxxxxxxxxxxxxxxxxxxxxx")
#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
/* Given an address, look for it in the exception tables */
const struct exception_table_entry *search_exception_tables(unsigned long add);
......
......@@ -389,6 +389,18 @@ config MODVERSIONS
make them incompatible with the kernel you are running. If
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
bool "Automatic kernel module loading"
depends on MODULES
......
......@@ -52,6 +52,7 @@ _modpost: $(modules)
quiet_cmd_modpost = MODPOST
cmd_modpost = scripts/mod/modpost \
$(if $(CONFIG_MODVERSIONS),-m) \
$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \
$(if $(KBUILD_EXTMOD),-i,-o) $(symverfile) \
$(filter-out FORCE,$^)
......
/* Postprocess module symbol versions
*
* 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
*
......@@ -18,6 +18,8 @@
int modversions = 0;
/* Warn about undefined symbols? (do so if we have vmlinux) */
int have_vmlinux = 0;
/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
static int all_versions = 0;
void
fatal(const char *fmt, ...)
......@@ -397,10 +399,44 @@ is_vmlinux(const char *modname)
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
read_symbols(char *modname)
{
const char *symname;
char *version;
struct module *mod;
struct elf_info info = { };
Elf_Sym *sym;
......@@ -424,8 +460,15 @@ read_symbols(char *modname)
handle_modversions(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);
/* 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)
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
write_if_changed(struct buffer *b, const char *fname)
{
......@@ -691,7 +744,7 @@ main(int argc, char **argv)
char *dump_read = NULL, *dump_write = NULL;
int opt;
while ((opt = getopt(argc, argv, "i:mo:")) != -1) {
while ((opt = getopt(argc, argv, "i:mo:a")) != -1) {
switch(opt) {
case 'i':
dump_read = optarg;
......@@ -702,6 +755,9 @@ main(int argc, char **argv)
case 'o':
dump_write = optarg;
break;
case 'a':
all_versions = 1;
break;
default:
exit(1);
}
......@@ -724,6 +780,7 @@ main(int argc, char **argv)
add_versions(&buf, mod);
add_depends(&buf, mod, modules);
add_moddevtable(&buf, mod);
add_srcversion(&buf, mod);
sprintf(fname, "%s.mod.c", mod->name);
write_if_changed(&buf, fname);
......
......@@ -77,6 +77,7 @@ struct module {
int has_init;
int has_cleanup;
struct buffer dev_table_buf;
char srcversion[25];
};
struct elf_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 maybe_frob_version(const char *modfilename,
void *modinfo,
unsigned long modinfo_len,
unsigned long modinfo_offset);
void maybe_frob_rcs_version(const char *modfilename,
char *version,
void *modinfo,
unsigned long modinfo_offset);
void get_src_version(const char *modname, char sum[], unsigned sumlen);
void *grab_file(const char *filename, unsigned long *size);
char* get_next_line(unsigned long *pos, void *file, unsigned long size);
......
......@@ -9,39 +9,6 @@
#include <string.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.
*
......@@ -408,11 +375,11 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
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;
unsigned long len;
int ret = 0;
struct md4_ctx md;
char *sources, *end, *fname;
const char *basename;
......@@ -432,7 +399,7 @@ static int get_version(const char *modname, char sum[])
if (!file) {
fprintf(stderr, "Warning: could not find versions for %s\n",
filelist);
return 0;
return;
}
sources = strchr(file, '\n');
......@@ -457,12 +424,9 @@ static int get_version(const char *modname, char sum[])
goto release;
}
/* sum is of form \0<padding>. */
md4_final_ascii(&md, sum, 1 + strlen(sum+1));
ret = 1;
md4_final_ascii(&md, sum, sumlen);
release:
release_file(file, len);
return ret;
}
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);
}
void strip_rcs_crap(char *version)
static int strip_rcs_crap(char *version)
{
unsigned int len, full_len;
if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
return;
return 0;
/* Space for version string follows. */
full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
......@@ -518,31 +482,15 @@ void strip_rcs_crap(char *version)
len++;
memmove(version + len, version + strlen(version),
full_len - strlen(version));
return 1;
}
/* If the modinfo contains a "version" value, then set this. */
void maybe_frob_version(const char *modfilename,
void *modinfo,
unsigned long modinfo_len,
unsigned long modinfo_offset)
/* Clean up RCS-style version numbers. */
void maybe_frob_rcs_version(const char *modfilename,
char *version,
void *modinfo,
unsigned long version_offset)
{
char *version, *csum;
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));
if (strip_rcs_crap(version))
write_version(modfilename, version, version_offset);
}
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