Hi folks The attached patch inplements 2.6 support in busybox insmod. Please test them.
Bastian -- Without freedom of choice there is no creativity. -- Kirk, "The return of the Archons", stardate 3157.4
Index: debian/config-udeb-linux =================================================================== --- debian/config-udeb-linux (revision 284) +++ debian/config-udeb-linux (working copy) @@ -367,7 +367,6 @@ # # CONFIG_FEATURE_SH_EXTRA_QUIET is not set CONFIG_FEATURE_SH_STANDALONE_SHELL=y -# CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN is not set CONFIG_FEATURE_COMMAND_EDITING=y CONFIG_FEATURE_COMMAND_HISTORY=15 # CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set Index: debian/config-udeb =================================================================== --- debian/config-udeb (revision 284) +++ debian/config-udeb (working copy) @@ -359,7 +359,6 @@ # # CONFIG_FEATURE_SH_EXTRA_QUIET is not set CONFIG_FEATURE_SH_STANDALONE_SHELL=y -# CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN is not set CONFIG_FEATURE_COMMAND_EDITING=y CONFIG_FEATURE_COMMAND_HISTORY=15 # CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set Index: debian/config-static =================================================================== --- debian/config-static (revision 284) +++ debian/config-static (working copy) @@ -442,7 +442,6 @@ # # CONFIG_FEATURE_SH_EXTRA_QUIET is not set CONFIG_FEATURE_SH_STANDALONE_SHELL=y -CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN=y CONFIG_FEATURE_COMMAND_EDITING=y CONFIG_FEATURE_COMMAND_HISTORY=15 CONFIG_FEATURE_COMMAND_SAVEHISTORY=y Index: modutils/lsmod.c =================================================================== --- modutils/lsmod.c (revision 284) +++ modutils/lsmod.c (working copy) @@ -38,16 +38,10 @@ #include <sys/file.h> #include "busybox.h" +#include "obj/module.h" -#ifndef CONFIG_FEATURE_CHECK_TAINTED_MODULE -static inline void check_tainted(void) { printf("\n"); } -#else -#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) - -static void check_tainted(void) +#ifdef CONFIG_FEATURE_CHECK_TAINTED_MODULE +static inline void check_tainted(void) { int tainted; FILE *f; @@ -67,108 +61,84 @@ printf(" Not tainted\n"); } } +#else +static inline void check_tainted(void) +{ + printf("\n"); +} #endif -#ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE - -struct module_info +static inline int lsmod_query(void) { - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; -}; + struct module_info info; + char *module_names, *mn, *deps, *dn; + size_t bufsize, depsize, nmod, count, i, j; + module_names = xmalloc(bufsize = 256); + if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize, &nmod)) { + bb_perror_msg_and_die("QM_MODULES"); + } -int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); + deps = xmalloc(depsize = 256); -/* Values for query_module's which. */ -static const int QM_MODULES = 1; -static const int QM_DEPS = 2; -static const int QM_REFS = 3; -static const int QM_SYMBOLS = 4; -static const int QM_INFO = 5; + 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) { + /* The module was removed out from underneath us. */ + continue; + } + /* else choke */ + bb_perror_msg_and_die("module %s: QM_INFO", mn); + } + if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) { + if (errno == ENOENT) { + /* The module was removed out from underneath us. */ + continue; + } + bb_perror_msg_and_die("module %s: QM_REFS", mn); + } + printf("%-20s%8lu%4ld", mn, info.size, info.usecount); + if (info.flags & NEW_MOD_DELETED) + printf(" (deleted)"); + else if (info.flags & NEW_MOD_INITIALIZING) + printf(" (initializing)"); + else if (!(info.flags & NEW_MOD_RUNNING)) + printf(" (uninitialized)"); + else { + if (info.flags & NEW_MOD_AUTOCLEAN) + printf(" (autoclean) "); + if (!(info.flags & NEW_MOD_USED_ONCE)) + printf(" (unused)"); + } + if (count) printf(" ["); + for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) { + printf("%s%s", dn, (j==count-1)? "":" "); + } + if (count) printf("]"); -/* Bits of module.flags. */ -static const int NEW_MOD_RUNNING = 1; -static const int NEW_MOD_DELETED = 2; -static const int NEW_MOD_AUTOCLEAN = 4; -static const int NEW_MOD_VISITED = 8; -static const int NEW_MOD_USED_ONCE = 16; -static const int NEW_MOD_INITIALIZING = 64; + printf("\n"); + } -extern int lsmod_main(int argc, char **argv) -{ - struct module_info info; - char *module_names, *mn, *deps, *dn; - size_t bufsize, depsize, nmod, count, i, j; - - module_names = xmalloc(bufsize = 256); - if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize, - &nmod)) { - bb_perror_msg_and_die("QM_MODULES"); - } - - deps = xmalloc(depsize = 256); - printf("Module Size Used by"); - check_tainted(); - - 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) { - /* The module was removed out from underneath us. */ - continue; - } - /* else choke */ - bb_perror_msg_and_die("module %s: QM_INFO", mn); - } - if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - bb_perror_msg_and_die("module %s: QM_REFS", mn); - } - printf("%-20s%8lu%4ld", mn, info.size, info.usecount); - if (info.flags & NEW_MOD_DELETED) - printf(" (deleted)"); - else if (info.flags & NEW_MOD_INITIALIZING) - printf(" (initializing)"); - else if (!(info.flags & NEW_MOD_RUNNING)) - printf(" (uninitialized)"); - else { - if (info.flags & NEW_MOD_AUTOCLEAN) - printf(" (autoclean) "); - if (!(info.flags & NEW_MOD_USED_ONCE)) - printf(" (unused)"); - } - if (count) printf(" ["); - for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) { - printf("%s%s", dn, (j==count-1)? "":" "); - } - if (count) printf("]"); - - printf("\n"); - } - -#ifdef CONFIG_FEATURE_CLEAN_UP - free(module_names); -#endif - - return( 0); + return( 0); } -#else /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */ - extern int lsmod_main(int argc, char **argv) { printf("Module Size Used by"); check_tainted(); +#ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE + if (getuid() != 0) + { +#endif if (bb_xprint_file_by_name("/proc/modules") < 0) { return 0; } return 1; +#ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE + } + return lsmod_query(); +#endif } -#endif /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */ + Index: modutils/Config.in =================================================================== --- modutils/Config.in (revision 284) +++ modutils/Config.in (working copy) @@ -39,14 +39,12 @@ help Support module loading for newer (post 2.1) Linux kernels. -if 0 config CONFIG_FEATURE_2_6_MODULES bool " Support version 2.6.x Linux kernels" default n depends on CONFIG_INSMOD help - Support module loading for newer (post 2.1) Linux kernels. -endif + Support module loading for post 2.6 Linux kernels. config CONFIG_FEATURE_INSMOD_VERSION_CHECKING bool " Module version checking" @@ -94,7 +92,7 @@ lsmod is used to display a list of loaded modules. config CONFIG_FEATURE_QUERY_MODULE_INTERFACE - bool " Support lsmod query_module interface (add 638 bytes)" + bool " Support lsmod query_module interface" default y depends on CONFIG_LSMOD && ( CONFIG_FEATURE_2_4_MODULES || CONFIG_FEATURE_2_6_MODULES ) help Index: modutils/insmod.c =================================================================== --- modutils/insmod.c (revision 284) +++ modutils/insmod.c (working copy) @@ -86,6 +86,8 @@ #include "obj/obj.h" #include "obj/kallsyms.h" +#define STRVERSIONLEN 32 + static int flag_force_load = 0; static int flag_autoclean = 0; static int flag_verbose = 0; @@ -99,9 +101,43 @@ char *m_filename; char *m_fullName; +struct utsname uts_info; + /*======================================================================*/ +/* 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 */ + *str = '\0'; +} + +/* Get the kernel version in the canonical integer form. */ + +static int get_kernel_version(char str[STRVERSIONLEN]) +{ + char *p, *q; + int a, b, c; + + strncpy(str, uts_info.release, STRVERSIONLEN-1); + str[STRVERSIONLEN-1] = '\0'; + p = str; + + a = strtoul(p, &p, 10); + if (*p != '.') + return -1; + b = strtoul(p + 1, &p, 10); + if (*p != '.') + return -1; + c = strtoul(p + 1, &q, 10); + if (p + 1 == q) + return -1; + use_numeric_only(a, b, q); + + return a << 16 | b << 8 | c; +} + static int check_module_name_match(const char *filename, struct stat *statbuf, void *userdata) { @@ -127,10 +163,8 @@ /* Conditionally add the symbols from the given symbol set to the new module. */ -static int -add_symbols_from( - struct obj_file *f, - int idx, struct module_symbol *syms, size_t nsyms, int gpl) +static int add_symbols_from(struct obj_file *f, int idx, + struct module_symbol *syms, size_t nsyms, int gpl) { struct module_symbol *s; size_t i; @@ -160,6 +194,7 @@ } sym = obj_find_symbol(f, (char *) s->name); + 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), @@ -222,159 +257,11 @@ } +#ifdef CONFIG_FEATURE_2_2_MODULES + /*======================================================================*/ /* Functions relating to module loading in pre 2.1 kernels. */ - static int -old_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q; - struct obj_symbol *sym; - int *loc; - - p = *argv; - if ((q = strchr(p, '=')) == NULL) { - argc--; - continue; - } - *q++ = '\0'; - - sym = obj_find_symbol(f, p); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - bb_error_msg("symbol for parameter %s not found", p); - return 0; - } - - loc = (int *) (f->sections[sym->secidx]->contents + sym->value); - - /* Do C quoting if we begin with a ". */ - if (*q == '"') { - char *r, *str; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') { - bb_error_msg("improperly terminated string argument for %s", p); - return 0; - } else if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } else - *r = *q; - } - *r = '\0'; - obj_string_patch(f, sym->secidx, sym->value, str); - } else if (*q >= '0' && *q <= '9') { - do - *loc++ = strtoul(q, &q, 0); - while (*q++ == ','); - } else { - char *contents = f->sections[sym->secidx]->contents; - char *myloc = contents + sym->value; - char *r; /* To search for commas */ - - /* Break the string with comas */ - while ((r = strchr(q, ',')) != (char *) NULL) { - *r++ = '\0'; - obj_string_patch(f, sym->secidx, myloc - contents, q); - myloc += sizeof(char *); - q = r; - } - - /* last part */ - obj_string_patch(f, sym->secidx, myloc - contents, q); - } - - argc--, argv++; - } - - return 1; -} - -#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING -static int old_is_module_checksummed(struct obj_file *f) -{ - return obj_find_symbol(f, "Using_Versions") != NULL; -} -/* Get the module's kernel version in the canonical integer form. */ - - static int -old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - struct obj_symbol *sym; - char *p, *q; - int a, b, c; - - sym = obj_find_symbol(f, "kernel_version"); - if (sym == NULL) - return -1; - - p = f->sections[sym->secidx]->contents + sym->value; - safe_strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ - -#ifdef CONFIG_FEATURE_2_2_MODULES - /* Fetch all the symbols and divvy them up as appropriate for the modules. */ static int old_get_kernel_symbols(const char *m_name) @@ -449,19 +336,6 @@ return 1; } -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int old_is_kernel_checksummed(void) -{ - /* Using_Versions is the first symbol. */ - if (nksyms > 0 - && strcmp((char *) ksyms[0].name, - "Using_Versions") == 0) return ksyms[0].value; - else - return 0; -} - - static int old_create_mod_use_count(struct obj_file *f) { struct obj_section *sec; @@ -585,292 +459,11 @@ #endif /* CONFIG_FEATURE_2_2_MODULES */ +#ifdef CONFIG_FEATURE_2_4_MODULES - /*======================================================================*/ /* Functions relating to module loading after 2.1.18. */ - static int -new_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q, *key, *sym_name; - struct obj_symbol *sym; - char *contents, *loc; - int min, max, n; - - p = *argv; - if ((q = strchr(p, '=')) == NULL) { - argc--; - continue; - } - - key = alloca(q - p + 6); - memcpy(key, "parm_", 5); - memcpy(key + 5, p, q - p); - key[q - p + 5] = 0; - - p = get_modinfo_value(f, key); - key += 5; - if (p == NULL) { - bb_error_msg("invalid parameter %s", key); - return 0; - } - -#ifdef SYMBOL_PREFIX - sym_name = alloca (strlen (key) + sizeof SYMBOL_PREFIX); - strcpy (sym_name, SYMBOL_PREFIX); - strcat (sym_name, key); -#else - sym_name = key; -#endif - sym = obj_find_symbol(f, sym_name); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - bb_error_msg("symbol for parameter %s not found", key); - return 0; - } - - if (isdigit(*p)) { - min = strtoul(p, &p, 10); - if (*p == '-') - max = strtoul(p + 1, &p, 10); - else - max = min; - } else - min = max = 1; - - contents = f->sections[sym->secidx]->contents; - loc = contents + sym->value; - n = (*++q != '\0'); - - while (1) { - if ((*p == 's') || (*p == 'c')) { - char *str; - - /* Do C quoting if we begin with a ", else slurp the lot. */ - if (*q == '"') { - char *r; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') { - bb_error_msg("improperly terminated string argument for %s", - key); - return 0; - } else if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } else - *r = *q; - } - *r = '\0'; - ++q; - } else { - char *r; - - /* In this case, the string is not quoted. We will break - it using the coma (like for ints). If the user wants to - include comas in a string, he just has to quote it */ - - /* Search the next coma */ - r = strchr(q, ','); - - /* Found ? */ - if (r != (char *) NULL) { - /* Recopy the current field */ - str = alloca(r - q + 1); - memcpy(str, q, r - q); - - /* I don't know if it is usefull, as the previous case - doesn't null terminate the string ??? */ - str[r - q] = '\0'; - - /* Keep next fields */ - q = r; - } else { - /* last string */ - str = q; - q = ""; - } - } - - if (*p == 's') { - /* Normal string */ - obj_string_patch(f, sym->secidx, loc - contents, str); - loc += tgt_sizeof_char_p; - } else { - /* Array of chars (in fact, matrix !) */ - unsigned long charssize; /* size of each member */ - - /* Get the size of each member */ - /* Probably we should do that outside the loop ? */ - if (!isdigit(*(p + 1))) { - bb_error_msg("parameter type 'c' for %s must be followed by" - " the maximum size", key); - return 0; - } - charssize = strtoul(p + 1, (char **) NULL, 10); - - /* Check length */ - if (strlen(str) >= charssize) { - bb_error_msg("string too long for %s (max %ld)", key, - charssize - 1); - return 0; - } - - /* Copy to location */ - strcpy((char *) loc, str); - loc += charssize; - } - } else { - long v = strtoul(q, &q, 0); - switch (*p) { - case 'b': - *loc++ = v; - break; - case 'h': - *(short *) loc = v; - loc += tgt_sizeof_short; - break; - case 'i': - *(int *) loc = v; - loc += tgt_sizeof_int; - break; - case 'l': - *(long *) loc = v; - loc += tgt_sizeof_long; - break; - - default: - bb_error_msg("unknown parameter type '%c' for %s", *p, key); - return 0; - } - } - -retry_end_of_value: - switch (*q) { - case '\0': - goto end_of_arg; - - case ' ': - case '\t': - case '\n': - case '\r': - ++q; - goto retry_end_of_value; - - case ',': - if (++n > max) { - bb_error_msg("too many values for %s (max %d)", key, max); - return 0; - } - ++q; - break; - - default: - bb_error_msg("invalid argument syntax for %s", key); - return 0; - } - } - -end_of_arg: - if (n < min) { - bb_error_msg("too few values for %s (min %d)", key, min); - return 0; - } - - argc--, argv++; - } - - return 1; -} - -#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING -static int new_is_module_checksummed(struct obj_file *f) -{ - const char *p = get_modinfo_value(f, "using_checksums"); - if (p) - return atoi(p); - else - return 0; -} - -/* Get the module's kernel version in the canonical integer form. */ - - static int -new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - char *p, *q; - int a, b, c; - - p = get_modinfo_value(f, "kernel_version"); - if (p == NULL) - return -1; - safe_strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ - - -#ifdef CONFIG_FEATURE_2_4_MODULES - /* Fetch the loaded modules, and all currently exported symbols. */ static int new_get_kernel_symbols(void) @@ -963,23 +556,6 @@ } -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int new_is_kernel_checksummed(void) -{ - struct module_symbol *s; - size_t i; - - /* Using_Versions is not the first symbol, but it should be in there. */ - - for (i = 0, s = ksyms; i < nksyms; ++i, ++s) - if (strcmp((char *) s->name, "Using_Versions") == 0) - return s->value; - - return 0; -} - - static int new_create_this_module(struct obj_file *f, const char *m_name) { struct obj_section *sec; @@ -1274,29 +850,84 @@ if (fd >= 0) close(fd); } -#else /* CONFIG_FEATURE_CHECK_TAINTED_MODULE */ -#define check_tainted_module(x, y) do { } while(0); #endif /* CONFIG_FEATURE_CHECK_TAINTED_MODULE */ -#ifdef CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS -/* add module source, timestamp, kernel version and a symbol for the - * start of some sections. this info is used by ksymoops to do better - * debugging. - */ - static int -get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ #ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING - if (get_modinfo_value(f, "kernel_version") == NULL) - return old_get_module_version(f, str); - else - return new_get_module_version(f, str); -#else /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ - strncpy(str, "???", sizeof(str)); +/* Get the module's kernel version in the canonical integer form. */ +static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) +{ + int a, b, c; + char *p, *q; + + if ((p = get_modinfo_value(f, "kernel_version")) == NULL) { + struct obj_symbol *sym; + + m_has_modinfo = 0; + if ((sym = obj_find_symbol(f, "kernel_version")) == NULL) + sym = obj_find_symbol(f, "__module_kernel_version"); + if (sym == NULL) + return -1; + p = f->sections[sym->secidx]->contents + sym->value; + } else + m_has_modinfo = 1; + + strncpy(str, p, STRVERSIONLEN-1); + str[STRVERSIONLEN-1] = '\0'; + p = str; + + a = strtoul(p, &p, 10); + if (*p != '.') + return -1; + b = strtoul(p + 1, &p, 10); + if (*p != '.') + return -1; + c = strtoul(p + 1, &q, 10); + if (p + 1 == q) + return -1; + use_numeric_only(a, b, q); + + return a << 16 | b << 8 | c; +} +#else +static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) __attribute__((unused)); +static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) +{ return -1; +} #endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ + +#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING +/* Return the kernel symbol checksum version, or zero if not used. */ +static int is_kernel_checksummed(void) +{ + struct module_symbol *s; + size_t i; + + /* + * Using_Versions might not be the first symbol, + * but it should be in there. + */ + for (i = 0, s = ksyms; i < nksyms; ++i, ++s) + if (strcmp((char *) s->name, "Using_Versions") == 0) + return s->value; + + return 0; } +static int is_module_checksummed(struct obj_file *f) +{ + if (m_has_modinfo) { + const char *p = get_modinfo_value(f, "using_checksums"); + if (p) + return atoi(p); + else + return 0; + } else + return obj_find_symbol(f, "Using_Versions") != NULL; +} +#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ + +#ifdef CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS /* add module source, timestamp, kernel version and a symbol for the * start of some sections. this info is used by ksymoops to do better * debugging. @@ -1371,7 +1002,7 @@ new_add_ksymtab(f, sym); } free(absolute_filename); -#ifdef _NOT_SUPPORTED_ + /* record where the persistent data is going, same address as previous symbol */ if (f->persist) { @@ -1388,7 +1019,7 @@ if (use_ksymtab) new_add_ksymtab(f, sym); } -#endif /* _NOT_SUPPORTED_ */ + /* tag the desired sections if size is non-zero */ for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); ++i) { @@ -1414,6 +1045,246 @@ } #endif /* CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS */ +static int process_module_arguments(struct obj_file *f, int argc, char **argv, int required) +{ + for (; argc > 0; ++argv, --argc) { + struct obj_symbol *sym; + int c; + int min, max; + int n; + char *contents; + char *input; + char *fmt; + char *key; + char *loc; + + if ((input = strchr(*argv, '=')) == NULL) + continue; + + n = input - *argv; + input += 1; /* skip '=' */ + + key = alloca(n + 6); + + if (m_has_modinfo) { + memcpy(key, "parm_", 5); + memcpy(key + 5, *argv, n); + key[n + 5] = '\0'; + if ((fmt = get_modinfo_value(f, key)) == NULL) { + if (required || flag_verbose) { + bb_error_msg("Warning: ignoring %s, no such parameter in this module", *argv); + continue; + } + } + key += 5; + + if (isdigit(*fmt)) { + min = strtoul(fmt, &fmt, 10); + if (*fmt == '-') + max = strtoul(fmt + 1, &fmt, 10); + else + max = min; + } else + min = max = 1; + } else { /* not m_has_modinfo */ + memcpy(key, *argv, n); + key[n] = '\0'; + + if (isdigit(*input)) + fmt = "i"; + else + fmt = "s"; + min = max = 0; + } + + sym = obj_find_symbol(f, key); + + /* + * Also check that the parameter was not + * resolved from the kernel. + */ + if (sym == NULL || sym->secidx > SHN_HIRESERVE) { + bb_error_msg("symbol for parameter %s not found", key); + return 0; + } + + contents = f->sections[sym->secidx]->contents; + loc = contents + sym->value; + n = 1; + + while (*input) { + char *str; + + switch (*fmt) { + case 's': + case 'c': + /* + * Do C quoting if we begin with a ", + * else slurp the lot. + */ + if (*input == '"') { + char *r; + + str = alloca(strlen(input)); + for (r = str, input++; *input != '"'; ++input, ++r) { + if (*input == '\0') { + bb_error_msg("improperly terminated string argument for %s", key); + return 0; + } + /* else */ + if (*input != '\\') { + *r = *input; + continue; + } + /* else handle \ */ + switch (*++input) { + case 'a': *r = '\a'; break; + case 'b': *r = '\b'; break; + case 'e': *r = '\033'; break; + case 'f': *r = '\f'; break; + case 'n': *r = '\n'; break; + case 'r': *r = '\r'; break; + case 't': *r = '\t'; break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + c = *input - '0'; + if ('0' <= input[1] && input[1] <= '7') { + c = (c * 8) + *++input - '0'; + if ('0' <= input[1] && input[1] <= '7') + c = (c * 8) + *++input - '0'; + } + *r = c; + break; + + default: *r = *input; break; + } + } + *r = '\0'; + ++input; + } else { + /* + * The string is not quoted. + * We will break it using the comma + * (like for ints). + * If the user wants to include commas + * in a string, he just has to quote it + */ + char *r; + + /* Search the next comma */ + if ((r = strchr(input, ',')) != NULL) { + /* + * Found a comma + * Recopy the current field + */ + str = alloca(r - input + 1); + memcpy(str, input, r - input); + str[r - input] = '\0'; + /* Keep next fields */ + input = r; + } else { + /* last string */ + str = input; + input = ""; + } + } + + if (*fmt == 's') { + /* Normal string */ + obj_string_patch(f, sym->secidx, loc - contents, str); + loc += tgt_sizeof_char_p; + } else { + /* Array of chars (in fact, matrix !) */ + long charssize; /* size of each member */ + + /* Get the size of each member */ + /* Probably we should do that outside the loop ? */ + if (!isdigit(*(fmt + 1))) { + bb_error_msg("parameter type 'c' for %s must be followed by" + " the maximum size", key); + return 0; + } + charssize = strtoul(fmt + 1, (char **) NULL, 10); + + /* Check length */ + if (strlen(str) >= charssize-1) { + bb_error_msg("string too long for %s (max %ld)", + key, charssize - 1); + return 0; + } + /* Copy to location */ + strcpy((char *) loc, str); /* safe, see check above */ + loc += charssize; + } + /* + * End of 's' and 'c' + */ + break; + + case 'b': + *loc++ = strtoul(input, &input, 0); + break; + + case 'h': + *(short *) loc = strtoul(input, &input, 0); + loc += tgt_sizeof_short; + break; + + case 'i': + *(int *) loc = strtoul(input, &input, 0); + loc += tgt_sizeof_int; + break; + + case 'l': + *(long *) loc = strtoul(input, &input, 0); + loc += tgt_sizeof_long; + break; + + default: + bb_error_msg("unknown parameter type '%c' for %s", + *fmt, key); + return 0; + } + /* + * end of switch (*fmt) + */ + + while (*input && isspace(*input)) + ++input; + if (*input == '\0') + break; /* while (*input) */ + /* else */ + + if (*input == ',') { + if (max && (++n > max)) { + bb_error_msg("too many values for %s (max %d)", key, max); + return 0; + } + ++input; + /* continue with while (*input) */ + } else { + bb_error_msg("invalid argument syntax for %s: '%c'", + key, *input); + return 0; + } + } /* end of while (*input) */ + + if (min && (n < min)) { + bb_error_msg("too few values for %s (min %d)", key, min); + return 0; + } + } /* end of for (;argc > 0;) */ + + return 1; +} + #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP static void print_load_map(struct obj_file *f) { @@ -1506,77 +1377,76 @@ #endif +#if defined(CONFIG_FEATURE_2_2_MODULES) || defined (CONFIG_FEATURE_2_4_MODULES) +static int do_2_0_and_2_4(int fp, int argc, char **argv, char *m_name); +#endif +#ifdef CONFIG_FEATURE_2_6_MODULES +static int do_2_6(int fp, int argc, char **argv); +#endif + extern int insmod_main( int argc, char **argv) { int opt; - int k_crcs; int len; char *tmp, *tmp1; - unsigned long m_size; - ElfW(Addr) m_addr; - struct obj_file *f; struct stat st; char *m_name = 0; - int exit_status = EXIT_FAILURE; -#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING - struct utsname uts_info; - char m_strversion[STRVERSIONLEN]; - int m_version; - int m_crcs; -#endif - int fp = 0; + int fp; #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP int flag_print_load_map = 0; #endif - int gpl; + int k_version; + char k_strversion[STRVERSIONLEN]; + uname(&uts_info); /* Parse any options */ #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP - while ((opt = getopt(argc, argv, "fkqsvxmLo:")) > 0) { + while ((opt = getopt(argc, argv, "fkqsvxmLo:")) > 0) #else - while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) { + while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) #endif - switch (opt) { - case 'f': /* force loading */ - flag_force_load = 1; - break; - case 'k': /* module loaded by kerneld, auto-cleanable */ - flag_autoclean = 1; - break; - case 's': /* log to syslog */ - /* log to syslog -- not supported */ - /* but kernel needs this for request_module(), */ - /* as this calls: modprobe -k -s -- <module> */ - /* so silently ignore this flag */ - break; - case 'v': /* verbose output */ - flag_verbose = 1; - break; - case 'q': /* silent */ - flag_quiet = 1; - break; - case 'x': /* do not export externs */ - flag_export = 0; - break; - case 'o': /* name the output module */ - free(m_name); - m_name = bb_xstrdup(optarg); - break; - case 'L': /* Stub warning */ - /* This is needed for compatibility with modprobe. - * In theory, this does locking, but we don't do - * that. So be careful and plan your life around not - * loading the same module 50 times concurrently. */ - break; + { + switch (opt) { + case 'f': /* force loading */ + flag_force_load = 1; + break; + case 'k': /* module loaded by kerneld, auto-cleanable */ + flag_autoclean = 1; + break; + case 's': /* log to syslog */ + /* log to syslog -- not supported */ + /* but kernel needs this for request_module(), */ + /* as this calls: modprobe -k -s -- <module> */ + /* so silently ignore this flag */ + break; + case 'v': /* verbose output */ + flag_verbose = 1; + break; + case 'q': /* silent */ + flag_quiet = 1; + break; + case 'x': /* do not export externs */ + flag_export = 0; + break; + case 'o': /* name the output module */ + free(m_name); + m_name = bb_xstrdup(optarg); + break; + case 'L': /* Stub warning */ + /* This is needed for compatibility with modprobe. + * In theory, this does locking, but we don't do + * that. So be careful and plan your life around not + * loading the same module 50 times concurrently. */ + break; #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP - case 'm': /* print module load map */ - flag_print_load_map = 1; - break; + case 'm': /* print module load map */ + flag_print_load_map = 1; + break; #endif - default: - bb_show_usage(); + default: + bb_show_usage(); + } } - } if (argv[optind] == NULL) { bb_show_usage(); @@ -1587,15 +1457,24 @@ tmp = basename(tmp1); len = strlen(tmp); - if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') { - len-=2; + k_version = get_kernel_version(k_strversion); + +#if defined(CONFIG_FEATURE_2_6_MODULES) + if (k_version > 0x20500 && len > 3 && tmp[len - 3] == '.' && + tmp[len - 2] == 'k' && tmp[len - 1] == 'o') { + len-=3; tmp[len] = '\0'; } + else +#endif + if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') { + len-=2; + tmp[len] = '\0'; + } - bb_xasprintf(&m_fullName, "%s.o", tmp); #if defined(CONFIG_FEATURE_2_6_MODULES) - if (k_version > 4) + if (k_version > 0x20500) bb_xasprintf(&m_fullName, "%s.ko", tmp); else #endif @@ -1605,22 +1484,19 @@ m_name = tmp; } else { free(tmp1); - tmp1 = 0; /* flag for free(m_name) before exit() */ } /* Get a filedesc for the module. Check we we have a complete path */ if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) || - (fp = open(argv[optind], O_RDONLY)) == 0) { - struct utsname myuname; - + (fp = open(argv[optind], O_RDONLY)) < 0) { /* Hmm. Could not open it. First search under /lib/modules/`uname -r`, * but do not error out yet if we fail to find it... */ - if (uname(&myuname) == 0) { + if (k_version) { /* uname succeedd */ char *module_dir; char *tmdn; char real_module_dir[FILENAME_MAX]; - tmdn = concat_path_file(_PATH_MODULES, myuname.release); + tmdn = concat_path_file(_PATH_MODULES, k_strversion); /* Jump through hoops in case /lib/modules/`uname -r` * is a symlink. We do not want recursive_action to * follow symlinks, but we do want to follow the @@ -1636,7 +1512,7 @@ } /* Check if we have found anything yet */ - if (m_filename == 0 || ((fp = open(m_filename, O_RDONLY)) == 0)) + if (m_filename == 0 || ((fp = open(m_filename, O_RDONLY)) < 0)) { char module_dir[FILENAME_MAX]; @@ -1647,94 +1523,107 @@ /* No module found under /lib/modules/`uname -r`, this * time cast the net a bit wider. Search /lib/modules/ */ if (! recursive_action(module_dir, TRUE, FALSE, FALSE, - check_module_name_match, 0, m_fullName)) + check_module_name_match, 0, m_fullName)) { if (m_filename == 0 - || ((fp = open(m_filename, O_RDONLY)) == 0)) + || ((fp = open(m_filename, O_RDONLY)) < 0)) { bb_error_msg("%s: no module by that name found", m_fullName); - goto out; + return EXIT_FAILURE; } } else bb_error_msg_and_die("%s: no module by that name found", m_fullName); } - } else + } else m_filename = bb_xstrdup(argv[optind]); if (!flag_quiet) printf("Using %s\n", m_filename); + if (k_version > 0x20500) + { +#ifdef CONFIG_FEATURE_2_6_MODULES + return do_2_6(fp, argc - optind, argv + optind); +#endif + } + else if (k_version > 0x20100) + { +#ifdef CONFIG_FEATURE_2_4_MODULES + return do_2_0_and_2_4(fp, argc - optind, argv + optind, m_name); +#endif + } + else if (k_version > 0x20000) + { +#ifdef CONFIG_FEATURE_2_2_MODULES + return do_2_0_and_2_4(fp, argc - optind, argv + optind, m_name); +#endif + } + return EXIT_FAILURE; +} + +#if defined(CONFIG_FEATURE_2_2_MODULES) || defined (CONFIG_FEATURE_2_4_MODULES) +static int do_2_0_and_2_4(int fp, int argc, char **argv, char *m_name) +{ + struct obj_file *f; + char k_strversion[STRVERSIONLEN]; + int k_version = 0; +#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING + char m_strversion[STRVERSIONLEN]; + int m_version; + int m_crcs; +#endif + unsigned long m_size; + ElfW(Addr) m_addr; + int gpl; + if ((f = obj_load(fp, ET_REL, m_filename)) == NULL) bb_perror_msg_and_die("Could not load the module"); - if (get_modinfo_value(f, "kernel_version") == NULL) - m_has_modinfo = 0; - else - m_has_modinfo = 1; - -#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING /* Version correspondence? */ - if (!flag_quiet) { - if (uname(&uts_info) < 0) - uts_info.release[0] = '\0'; - if (m_has_modinfo) { - m_version = new_get_module_version(f, m_strversion); - } else { - m_version = old_get_module_version(f, m_strversion); - if (m_version == -1) { - bb_error_msg("couldn't find the kernel version the module was " - "compiled for"); - goto out; - } - } - - if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) { - if (flag_force_load) { - bb_error_msg("Warning: kernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s", - m_filename, m_strversion, uts_info.release); - } else { - bb_error_msg("kernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s.", - m_filename, m_strversion, uts_info.release); - goto out; - } - } + k_version = get_kernel_version(k_strversion); +#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING + m_version = get_module_version(f, m_strversion); + if (m_version == -1) { + error("couldn't find the kernel version the module was compiled for"); + return EXIT_FAILURE; } - - k_crcs = 0; #endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ - k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); - - if (k_new_syscalls) { + if (k_version > 0x20100) + { #ifdef CONFIG_FEATURE_2_4_MODULES if (!new_get_kernel_symbols()) - goto out; - k_crcs = new_is_kernel_checksummed(); -#else - bb_error_msg("Not configured to support new kernels"); - goto out; + return EXIT_FAILURE; #endif - } else { + } + else + { #ifdef CONFIG_FEATURE_2_2_MODULES - if (!old_get_kernel_symbols(m_name)) - goto out; - k_crcs = old_is_kernel_checksummed(); -#else - bb_error_msg("Not configured to support old kernels"); - goto out; + if (!old_get_kernel_symbols()) + return EXIT_FAILURE; #endif } #ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING - if (m_has_modinfo) - m_crcs = new_is_module_checksummed(f); - else - m_crcs = old_is_module_checksummed(f); - + k_crcs = is_kernel_checksummed(); + m_crcs = is_module_checksummed(f); + if ((m_crcs == 0 || k_crcs == 0) && + strncmp(k_strversion, m_strversion, STRVERSIONLEN) != 0) { + if (flag_force_load) { + lprintf("Warning: kernel-module version mismatch\n" + "\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" + "\t%s was compiled for kernel version %s\n" + "\twhile this kernel is version %s.", + filename, m_strversion, k_strversion); + return EXIT_FAILURE; + } + } if (m_crcs != k_crcs) obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); #endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ @@ -1745,29 +1634,27 @@ /* Allocate common symbols, symbol tables, and string tables. */ - if (k_new_syscalls + if (k_new_syscalls ? !new_create_this_module(f, m_name) - : !old_create_mod_use_count(f)) + : !old_create_mod_use_count(f)) { - goto out; + return EXIT_FAILURE; } if (!obj_check_undefineds(f, 0)) { - goto out; + return EXIT_FAILURE; } obj_allocate_commons(f); +#ifdef CONFIG_FEATURE_CHECK_TAINTED_MODULE check_tainted_module(f, m_name); +#endif /* done with the module name, on to the optional var=value arguments */ ++optind; if (optind < argc) { - if (m_has_modinfo - ? !new_process_module_arguments(f, argc - optind, argv + optind) - : !old_process_module_arguments(f, argc - optind, argv + optind)) - { - goto out; - } + if (!process_module_arguments(f, argc - optind, argv + optind, 1)) + return EXIT_FAILURE; } arch_create_got(f); @@ -1787,26 +1674,26 @@ if (m_addr == -1) switch (errno) { case EEXIST: bb_error_msg("A module named %s already exists", m_name); - goto out; + return EXIT_FAILURE; case ENOMEM: bb_error_msg("Can't allocate kernel memory for module; needed %lu bytes", m_size); - goto out; + return EXIT_FAILURE; default: bb_perror_msg("create_module: %s", m_name); - goto out; + return EXIT_FAILURE; } if (!obj_relocate(f, m_addr)) { delete_module(m_name); - goto out; + return EXIT_FAILURE; } - if (k_new_syscalls + if (k_new_syscalls ? !new_init_module(m_name, f, m_size) - : !old_init_module(m_name, f, m_size)) + : !old_init_module(m_name, f, m_size)) { delete_module(m_name); - goto out; + return EXIT_FAILURE; } #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP @@ -1814,22 +1701,71 @@ print_load_map(f); #endif - exit_status = EXIT_SUCCESS; + return EXIT_SUCCESS; +} +#endif /* CONFIG_FEATURE_2_2_MODULES || CONFIG_FEATURE_2_4_MODULES */ -out: -#ifdef CONFIG_FEATURE_CLEAN_UP - if(fp) - fclose(fp); - if(tmp1) { - free(tmp1); - } else { - free(m_name); +#ifdef CONFIG_FEATURE_2_6_MODULES +#include <sys/mman.h> +#include <sys/syscall.h> + +/* We use error numbers in a loose translation... */ +static const char *moderror(int err) +{ + switch (err) { + case ENOEXEC: + return "Invalid module format"; + case ENOENT: + return "Unknown symbol in module"; + case ESRCH: + return "Module has wrong symbol version"; + case EINVAL: + return "Invalid parameters"; + default: + return strerror(err); } - free(m_filename); -#endif - return(exit_status); } +static int do_2_6(int fd, int argc, char **argv) +{ + int i; + long int ret; + struct stat st; + unsigned long len; + void *map; + char *options = bb_xstrdup(""); + + /* Rest is options */ + for (i = 2; i < argc; i++) { + options = xrealloc(options, strlen(options) + 2 + strlen(argv[i]) + 2); + /* Spaces handled by "" pairs, but no way of escaping quotes */ + if (strchr(argv[i], ' ')) { + strcat(options, "\""); + strcat(options, argv[i]); + strcat(options, "\""); + } else { + strcat(options, argv[i]); + } + strcat(options, " "); + } + + fstat(fd, &st); + len = st.st_size; + map = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + bb_perror_msg_and_die("cannot mmap `%s'", m_filename); + } + + ret = syscall(__NR_init_module, map, len, options); + if (ret != 0) { + bb_perror_msg_and_die("cannot insert `%s': %s (%li)", + m_filename, moderror(errno), ret); + } + + return 0; +} +#endif /* CONFIG_FEATURE_2_6_MODULES */ + int check_module (const char *mod) { k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); @@ -1842,3 +1778,4 @@ return -1; } +
signature.asc
Description: Digital signature