From fa40f30b4253b1e05c46cc5e0c111176825b7623 Mon Sep 17 00:00:00 2001 From: Mystery Man Date: Wed, 29 Oct 2003 16:07:11 +0000 Subject: This commit was manufactured by cvs2svn to create tag 'Corpo_2_1_1'. --- mdk-stage1/insmod-modutils/insmod.c | 255 ++++++++++++++++++++++++++++++------ 1 file changed, 216 insertions(+), 39 deletions(-) (limited to 'mdk-stage1/insmod-modutils/insmod.c') diff --git a/mdk-stage1/insmod-modutils/insmod.c b/mdk-stage1/insmod-modutils/insmod.c index 359b28837..b0b7c2a0d 100644 --- a/mdk-stage1/insmod-modutils/insmod.c +++ b/mdk-stage1/insmod-modutils/insmod.c @@ -54,16 +54,15 @@ Keith Owens November 2000. Add persistent data support. Keith Owens November 2000. + Add tainted module support. + Keith Owens September 2001. */ -#ident "$Id$" - #include "../insmod.h" #include #include #include #include -//#include provided by stdlib #include #include #include @@ -71,6 +70,7 @@ #include #include #include +#include #include "module.h" #include "obj.h" @@ -90,9 +90,12 @@ static int flag_silent_probe = 0; static int flag_export = 1; static int flag_load_map = 0; static int flag_ksymoops = 1; +static int flag_numeric_only = 0; static int n_ext_modules_used; static int m_has_modinfo; +static int gplonly_seen; +static int warnings; extern int insmod_main(int argc, char **argv); extern int insmod_main_32(int argc, char **argv); @@ -105,6 +108,15 @@ extern int kallsyms_main(int argc, char **argv); /*======================================================================*/ +/* Only use the numeric part of the version string? */ + +static void use_numeric_only(int major, int minor, char *str) +{ + if (((major << 8) + minor) >= 0x0205 /* kernel 2.5 */ + || flag_numeric_only) + *str = '\0'; +} + /* Get the kernel version in the canonical integer form. */ static int get_kernel_version(char str[STRVERSIONLEN]) @@ -112,8 +124,9 @@ static int get_kernel_version(char str[STRVERSIONLEN]) char *p, *q; int a, b, c; - strncpy(str, uts_info.release, STRVERSIONLEN); - p = uts_info.release; + strncpy(str, uts_info.release, STRVERSIONLEN-1); + str[STRVERSIONLEN-1] = '\0'; + p = str; a = strtoul(p, &p, 10); if (*p != '.') @@ -124,6 +137,7 @@ static int get_kernel_version(char str[STRVERSIONLEN]) c = strtoul(p + 1, &q, 10); if (p + 1 == q) return -1; + use_numeric_only(a, b, q); return a << 16 | b << 8 | c; } @@ -232,7 +246,7 @@ static unsigned long ncv_symbol_hash(const char *str) * to the new module. */ static int add_symbols_from(struct obj_file *f, int idx, - struct module_symbol *syms, size_t nsyms) + struct module_symbol *syms, size_t nsyms, int gpl) { struct module_symbol *s; size_t i; @@ -247,8 +261,57 @@ static int add_symbols_from(struct obj_file *f, int idx, */ struct obj_symbol *sym; + /* GPL licensed modules can use symbols exported with + * EXPORT_SYMBOL_GPL, so ignore any GPLONLY_ prefix on the + * exported names. Non-GPL modules never see any GPLONLY_ + * symbols so they cannot fudge it by adding the prefix on + * their references. + */ + if (strncmp((char *)s->name, "GPLONLY_", 8) == 0) { + gplonly_seen = 1; + if (gpl) + ((char *)s->name) += 8; + else + continue; + } + sym = obj_find_symbol(f, (char *) s->name); - if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) { +#ifdef ARCH_ppc64 + if (!sym) + { + static size_t buflen = 0; + static char *buf = 0; + int len; + + /* ppc64 is one of those architectures with + function descriptors. A function is exported + and accessed across object boundaries via its + function descriptor. The function code symbol + happens to be the function name, prefixed with + '.', and a function call is a branch to the + code symbol. The linker recognises when a call + crosses object boundaries, and inserts a stub + to call via the function descriptor. + obj_ppc64.c of course does the same thing, so + here we recognise that an undefined code symbol + can be satisfied by the corresponding function + descriptor symbol. */ + + len = strlen ((char *) s->name) + 2; + if (buflen < len) + { + buflen = len + (len >> 1); + if (buf) + free (buf); + buf = malloc (buflen); + } + buf[0] = '.'; + strcpy (buf + 1, (char *) s->name); + sym = obj_find_symbol(f, buf); + } +#endif /* ARCH_ppc64 */ + + if (sym && ELFW(ST_BIND) (sym->info) != STB_LOCAL) { sym = obj_add_symbol(f, (char *) s->name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), idx, s->value, 0); @@ -264,7 +327,7 @@ static int add_symbols_from(struct obj_file *f, int idx, return used; } -static void add_kernel_symbols(struct obj_file *f) +static void add_kernel_symbols(struct obj_file *f, int gpl) { struct module_stat *m; size_t i, nused = 0; @@ -272,13 +335,13 @@ static void add_kernel_symbols(struct obj_file *f) /* Add module symbols first. */ for (i = 0, m = module_stat; i < n_module_stat; ++i, ++m) if (m->nsyms && - add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms)) + add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms, gpl)) m->status = 1 /* used */, ++nused; n_ext_modules_used = nused; /* And finally the symbols from the kernel proper. */ if (nksyms) - add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); + add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms, gpl); } static void hide_special_symbols(struct obj_file *f) @@ -326,7 +389,7 @@ static void print_load_map(struct obj_file *f) if (a == -1) a = 0; - lprintf("%-16s%08lx %0*lx 2**%d", + lprintf("%-15s %08lx %0*lx 2**%d", sec->name, (long)sec->header.sh_size, (int) (2 * sizeof(void *)), @@ -465,9 +528,10 @@ static int old_create_mod_use_count(struct obj_file *f) */ got = obj_find_symbol(f, "_GLOBAL_OFFSET_TABLE_"); if (got) -{ + { sec = obj_create_alloced_section(f, ".got", - sizeof(long), sizeof(long)); + sizeof(long), sizeof(long), + SHF_WRITE); got->secidx = sec->idx; /* mark the symbol as defined */ } return 1; @@ -491,7 +555,8 @@ static void add_ksymtab(struct obj_file *f, struct obj_symbol *sym) sec = NULL; } if (!sec) - sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0); + sec = obj_create_alloced_section(f, "__ksymtab", + tgt_sizeof_void_p, 0, 0); if (!sec) return; sec->header.sh_flags |= SHF_ALLOC; @@ -513,9 +578,9 @@ static int create_module_ksymtab(struct obj_file *f) struct module_ref *dep; struct obj_symbol *tm; - sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, - (sizeof(struct module_ref) - * n_ext_modules_used)); + sec = obj_create_alloced_section(f, ".kmodtab", + tgt_sizeof_void_p, + sizeof(struct module_ref) * n_ext_modules_used, 0); if (!sec) return 0; @@ -524,6 +589,9 @@ static int create_module_ksymtab(struct obj_file *f) for (i = 0; i < n_module_stat; ++i) if (module_stat[i].status /* used */) { dep->dep = module_stat[i].addr; +#ifdef ARCH_ppc64 + dep->dep |= ppc64_module_base (f); +#endif obj_symbol_patch(f, sec->idx, (char *) &dep->ref - sec->contents, tm); dep->next_ref = 0; ++dep; @@ -573,7 +641,9 @@ static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) } else m_has_modinfo = 1; - strncpy(str, p, STRVERSIONLEN); + strncpy(str, p, STRVERSIONLEN-1); + str[STRVERSIONLEN-1] = '\0'; + p = str; a = strtoul(p, &p, 10); if (*p != '.') @@ -584,6 +654,7 @@ static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) c = strtoul(p + 1, &q, 10); if (p + 1 == q) return -1; + use_numeric_only(a, b, q); return a << 16 | b << 8 | c; } @@ -645,6 +716,7 @@ static void add_ksymoops_symbols(struct obj_file *f, const char *filename, int save_errno = errno; error("cannot get realpath for %s", filename); errno = save_errno; + perror(""); absolute_filename = xstrdup(filename); } @@ -679,7 +751,7 @@ static void add_ksymoops_symbols(struct obj_file *f, const char *filename, version = get_module_version(f, str); /* -1 if not found */ snprintf(name, l, "%s%s_O%s_M%0*lX_V%d", symprefix, m_name, absolute_filename, - 2*sizeof(statbuf.st_mtime), statbuf.st_mtime, + (int)(2*sizeof(statbuf.st_mtime)), statbuf.st_mtime, version); sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), @@ -756,14 +828,10 @@ static int process_module_arguments(struct obj_file *f, int argc, char **argv, i memcpy(key + 5, *argv, n); key[n + 5] = '\0'; if ((fmt = get_modinfo_value(f, key)) == NULL) { - if (required) { - error("invalid parameter %s", key); - return 0; - } - else { - if (flag_verbose) - lprintf("ignoring %s", *argv); - continue; /* silently ignore optional parameters */ + if (required || flag_verbose) { + lprintf("Warning: ignoring %s, no such parameter in this module", *argv); + ++warnings; + continue; } } key += 5; @@ -1014,7 +1082,7 @@ static int add_kallsyms(struct obj_file *f, } } if (!*module_kallsyms) - *module_kallsyms = obj_create_alloced_section(f, KALLSYMS_SEC_NAME, 0, 0); + *module_kallsyms = obj_create_alloced_section(f, KALLSYMS_SEC_NAME, 0, 0, 0); /* Size and populate kallsyms */ if (obj_kallsyms(f, &f_kallsyms)) @@ -1046,7 +1114,7 @@ static int add_archdata(struct obj_file *f, } } if (!*sec) - *sec = obj_create_alloced_section(f, ARCHDATA_SEC_NAME, 16, 0); + *sec = obj_create_alloced_section(f, ARCHDATA_SEC_NAME, 16, 0, 0); /* Size and populate archdata */ if (arch_archdata(f, *sec)) @@ -1147,7 +1215,8 @@ static int init_module(const char *m_name, struct obj_file *f, if (ret) { error("init_module: %m"); lprintf("Hint: insmod errors can be caused by incorrect module parameters, " - "including invalid IO or IRQ parameters"); + "including invalid IO or IRQ parameters.\n" + " You may find more information in syslog or the output from dmesg"); } } @@ -1276,6 +1345,7 @@ static int check_module_parameter(struct obj_file *f, char *key, char *value, in * most error conditions. Make these all errors in 2.5. */ lprintf("Warning: %s symbol for parameter %s not found", error_file, key); + ++warnings; return(1); } @@ -1290,6 +1360,7 @@ static int check_module_parameter(struct obj_file *f, char *key, char *value, in if (max < min) { lprintf("Warning: %s parameter %s has max < min!", error_file, key); + ++warnings; return(1); } @@ -1297,6 +1368,7 @@ static int check_module_parameter(struct obj_file *f, char *key, char *value, in case 'c': if (!isdigit(p[1])) { lprintf("%s parameter %s has no size after 'c'!", error_file, key); + ++warnings; return(1); } while (isdigit(p[1])) @@ -1310,9 +1382,11 @@ static int check_module_parameter(struct obj_file *f, char *key, char *value, in break; case '\0': lprintf("%s parameter %s has no format character!", error_file, key); + ++warnings; return(1); default: lprintf("%s parameter %s has unknown format character '%c'", error_file, key, *p); + ++warnings; return(1); } switch (*++p) { @@ -1327,6 +1401,7 @@ static int check_module_parameter(struct obj_file *f, char *key, char *value, in break; default: lprintf("%s parameter %s has unknown format modifier '%c'", error_file, key, *p); + ++warnings; return(1); } return(0); @@ -1374,6 +1449,74 @@ static void check_module_parameters(struct obj_file *f, int *persist_flag) return; } +static void set_tainted(struct obj_file *f, int fd, int kernel_has_tainted, + int noload, 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 */ + lprintf("Warning: loading %s will taint the kernel: %s%s", + f->filename, text1, text2); + ++warnings; + if (first) { + lprintf(" See %s for information about tainted modules", TAINT_URL); + first = 0; + } + if (fd >= 0 && !noload) { + 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, int noload) +{ + static const char tainted_file[] = TAINT_FILENAME; + int fd, kernel_has_tainted; + const char *ptr; + + 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; + } + } + else + kernel_has_tainted = 1; + + switch (obj_gpl_license(f, &ptr)) { + case 0: + break; + case 1: + set_tainted(f, fd, kernel_has_tainted, noload, 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, 1, noload, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr); + break; + default: + set_tainted(f, fd, 1, noload, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", ""); + break; + } + + if (flag_force_load) + set_tainted(f, fd, 1, noload, TAINT_FORCED_MODULE, "forced load", ""); + if (fd >= 0) + close(fd); +} /* For common 3264 code, only compile the usage message once, in the 64 bit version */ #if defined(COMMON_3264) && defined(ONLY_32) @@ -1382,7 +1525,7 @@ extern void insmod_usage(void); /* Use the copy in the 64 bit version */ void insmod_usage(void) { fputs("Usage:\n" - "insmod [-fhkLmnpqrsSvVxXyY] [-e persist_name] [-o module_name] [-O blob_name] [-P prefix] module [ symbol=value ... ]\n" + "insmod [-fhkLmnpqrsSvVxXyYN] [-e persist_name] [-o module_name] [-O blob_name] [-P prefix] module [ symbol=value ... ]\n" "\n" " module Name of a loadable kernel module ('.o' can be omitted)\n" " -f, --force Force loading under wrong kernel version\n" @@ -1402,6 +1545,7 @@ void insmod_usage(void) " -X, --export Do export externs (default)\n" " -y, --noksymoops Do not add ksymoops symbols\n" " -Y, --ksymoops Do add ksymoops symbols (default)\n" + " -N, --numeric-only Only check the numeric part of the kernel version\n" " -e persist_name\n" " --persist=persist_name Filename to hold any persistent data from the module\n" " -o NAME, --name=NAME Set internal module name to NAME\n" @@ -1445,8 +1589,8 @@ int INSMOD_MAIN(int argc, char **argv) {"export", 0, 0, 'X'}, {"noksymoops", 0, 0, 'y'}, {"ksymoops", 0, 0, 'Y'}, - {"persist", 1, 0, 'e'}, + {"numeric-only", 1, 0, 'N'}, {"name", 1, 0, 'o'}, {"blob", 1, 0, 'O'}, {"prefix", 1, 0, 'P'}, @@ -1472,6 +1616,7 @@ int INSMOD_MAIN(int argc, char **argv) int force_kallsyms = 0; int persist_parms = 0; /* does module have persistent parms? */ int i; + int gpl; error_file = "insmod"; @@ -1479,7 +1624,7 @@ int INSMOD_MAIN(int argc, char **argv) errors = optind = 0; /* Process the command line. */ - while ((o = getopt_long(argc, argv, "fhkLmnpqrsSvVxXyYe:o:O:P:R:", + while ((o = getopt_long(argc, argv, "fhkLmnpqrsSvVxXyYNe:o:O:P:R:", &long_opts[0], NULL)) != EOF) switch (o) { case 'f': /* force loading */ @@ -1533,6 +1678,9 @@ int INSMOD_MAIN(int argc, char **argv) case 'Y': /* do define ksymoops symbols */ flag_ksymoops = 1; break; + case 'N': /* only check numeric part of kernel version */ + flag_numeric_only = 1; + break; case 'e': /* persistent data filename */ free(persist_name); @@ -1566,8 +1714,10 @@ int INSMOD_MAIN(int argc, char **argv) (!persistdir || !*persistdir)) { free(persist_name); persist_name = NULL; - if (flag_verbose) + if (flag_verbose) { lprintf("insmod: -e \"\" ignored, no persistdir"); + ++warnings; + } } if (m_name == NULL) { @@ -1624,7 +1774,7 @@ int INSMOD_MAIN(int argc, char **argv) */ set_ncv_prefix(NULL); - for (i = 0; i < n_module_stat; ++i) { + for (i = 0; !noload && i < n_module_stat; ++i) { if (strcmp(module_stat[i].name, m_name) == 0) { error("a module named %s already exists", m_name); goto out; @@ -1652,6 +1802,7 @@ int INSMOD_MAIN(int argc, char **argv) "\t%s was compiled for kernel version %s\n" "\twhile this kernel is version %s", filename, m_strversion, k_strversion); + ++warnings; } else { if (!quiet) error("kernel-module version mismatch\n" @@ -1665,7 +1816,13 @@ int INSMOD_MAIN(int argc, char **argv) obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); /* Let the module know about the kernel symbols. */ - add_kernel_symbols(f); + gpl = obj_gpl_license(f, NULL) == 0; + add_kernel_symbols(f, gpl); + +#ifdef ARCH_ppc64 + if (!ppc64_process_syms (f)) + goto out; +#endif /* Allocate common symbols, symbol tables, and string tables. * @@ -1684,17 +1841,33 @@ int INSMOD_MAIN(int argc, char **argv) goto out; #endif - if (!obj_check_undefineds(f, quiet)) /* DEPMOD, obj_clear_undefineds */ + arch_create_got(f); /* DEPMOD */ + if (!obj_check_undefineds(f, quiet)) { /* DEPMOD, obj_clear_undefineds */ + if (!gpl && !quiet) { + if (gplonly_seen) + error("\n" + "Hint: You are trying to load a module without a GPL compatible license\n" + " and it has unresolved symbols. The module may be trying to access\n" + " GPLONLY symbols but the problem is more likely to be a coding or\n" + " user error. Contact the module supplier for assistance, only they\n" + " can help you.\n"); + else + error("\n" + "Hint: You are trying to load a module without a GPL compatible license\n" + " and it has unresolved symbols. Contact the module supplier for\n" + " assistance, only they can help you.\n"); + } goto out; + } obj_allocate_commons(f); /* DEPMOD */ check_module_parameters(f, &persist_parms); + check_tainted_module(f, noload); if (optind < argc) { if (!process_module_arguments(f, argc - optind, argv + optind, 1)) goto out; } - arch_create_got(f); /* DEPMOD */ hide_special_symbols(f); if (persist_parms && persist_name && *persist_name) { @@ -1842,6 +2015,9 @@ int INSMOD_MAIN(int argc, char **argv) } else { errno = 0; m_addr = create_module(m_name, m_size); +#ifdef ARCH_ppc64 + m_addr |= ppc64_module_base (f); +#endif switch (errno) { case 0: break; @@ -1917,6 +2093,8 @@ int INSMOD_MAIN(int argc, char **argv) delete_module(m_name); goto out; } + if (warnings && !noload) + lprintf("Module %s loaded, with warnings", m_name); exit_status = 0; out: @@ -1941,7 +2119,6 @@ int insmod_main(int argc, char **argv) #endif /* defined(COMMON_3264) && defined(ONLY_64) */ - int insmod_call(char * full_filename, char * params) { int argc = 2; -- cgit v1.2.1