* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include "busybox.h"
+#include "libbb.h"
#include <libgen.h>
#include <sys/utsname.h>
#define ENABLE_FEATURE_2_4_MODULES 1
#endif
-#if !ENABLE_FEATURE_2_4_MODULES
-#define insmod_ng_main insmod_main
-#endif
+/*
+ * Big piece of 2.4-specific code
+ */
+#if ENABLE_FEATURE_2_4_MODULES
#if ENABLE_FEATURE_2_6_MODULES
-extern int insmod_ng_main( int argc, char **argv);
+static int insmod_ng_main(int argc, char **argv);
#endif
-
-#if ENABLE_FEATURE_2_4_MODULES
-
-
#if ENABLE_FEATURE_INSMOD_LOADINKMEM
#define LOADBITS 0
#else
#define LOADBITS 1
#endif
-
/* Alpha */
#if defined(__alpha__)
#define MATCH_MACHINE(x) (x == EM_ALPHA)
/* Microblaze */
#if defined(__microblaze__)
#define USE_SINGLE
+#include <linux/elf-em.h>
#define MATCH_MACHINE(x) (x == EM_XILINX_MICROBLAZE)
#define SHT_RELM SHT_RELA
#define Elf32_RelM Elf32_Rela
/* The system calls unchanged between 2.0 and 2.1. */
unsigned long create_module(const char *, size_t);
-int delete_module(const char *);
+int delete_module(const char *module, unsigned int flags);
#endif /* module.h */
/* The relocatable object is manipulated using elfin types. */
-#include <stdio.h>
#include <elf.h>
#include <endian.h>
static void *obj_extend_section(struct obj_section *sec, unsigned long more);
-static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+static void obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
const char *string);
-static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+static void obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
struct obj_symbol *sym);
-static int obj_check_undefineds(struct obj_file *f);
+static void obj_check_undefineds(struct obj_file *f);
static void obj_allocate_commons(struct obj_file *f);
static enum obj_reloc arch_apply_relocation(struct obj_file *f,
struct obj_section *targsec,
- struct obj_section *symsec,
+ /*struct obj_section *symsec,*/
struct obj_symbol *sym,
ElfW(RelM) *rel, ElfW(Addr) value);
#define SPFX ""
#endif
-
-#define _PATH_MODULES "/lib/modules"
enum { STRVERSIONLEN = 64 };
/*======================================================================*/
static struct external_module *ext_modules;
static int n_ext_modules;
static int n_ext_modules_used;
-extern int delete_module(const char *);
static char *m_filename;
static char *m_fullName;
/*======================================================================*/
-static int check_module_name_match(const char *filename, struct stat *statbuf,
- void *userdata, int depth)
+static int FAST_FUNC check_module_name_match(const char *filename,
+ struct stat *statbuf UNUSED_PARAM,
+ void *userdata, int depth UNUSED_PARAM)
{
char *fullname = (char *) userdata;
+ char *tmp;
if (fullname[0] == '\0')
return FALSE;
- else {
- char *tmp, *tmp1 = xstrdup(filename);
- tmp = bb_get_last_path_component(tmp1);
- if (strcmp(tmp, fullname) == 0) {
- free(tmp1);
- /* Stop searching if we find a match */
- m_filename = xstrdup(filename);
- return FALSE;
- }
- free(tmp1);
+
+ tmp = bb_get_last_path_component_nostrip(filename);
+ if (strcmp(tmp, fullname) == 0) {
+ /* Stop searching if we find a match */
+ m_filename = xstrdup(filename);
+ return FALSE;
}
return TRUE;
}
static struct obj_file *arch_new_file(void)
{
struct arch_file *f;
- f = xmalloc(sizeof(*f));
-
- memset(f, 0, sizeof(*f));
-
- return &f->root;
+ f = xzalloc(sizeof(*f));
+ return &f->root; /* it's a first member */
}
static struct obj_section *arch_new_section(void)
{
- return xmalloc(sizeof(struct obj_section));
+ return xzalloc(sizeof(struct obj_section));
}
static struct obj_symbol *arch_new_symbol(void)
{
struct arch_symbol *sym;
- sym = xmalloc(sizeof(*sym));
-
- memset(sym, 0, sizeof(*sym));
-
+ sym = xzalloc(sizeof(*sym));
return &sym->root;
}
static enum obj_reloc
arch_apply_relocation(struct obj_file *f,
struct obj_section *targsec,
- struct obj_section *symsec,
+ /*struct obj_section *symsec,*/
struct obj_symbol *sym,
ElfW(RelM) *rel, ElfW(Addr) v)
{
+#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
+ || defined(__sh__) || defined(__s390__) || defined(__x86_64__)
struct arch_file *ifile = (struct arch_file *) f;
+#endif
enum obj_reloc ret = obj_reloc_ok;
ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
+#if defined(__arm__) || defined(__H8300H__) || defined(__H8300S__) \
+ || defined(__i386__) || defined(__mc68000__) || defined(__microblaze__) \
+ || defined(__mips__) || defined(__nios2__) || defined(__powerpc__) \
+ || defined(__s390__) || defined(__sh__) || defined(__x86_64__)
ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
+#endif
#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
struct arch_symbol *isym = (struct arch_symbol *) sym;
#endif
-#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) || defined(__sh__) || defined(__s390__)
+#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
+ || defined(__sh__) || defined(__s390__)
#if defined(USE_GOT_ENTRIES)
ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
#endif
case R_386_PLT32:
case R_386_PC32:
+ case R_386_GOTOFF:
*loc += v - dot;
break;
case R_386_GOT32:
goto bb_use_got;
-
- case R_386_GOTOFF:
- *loc += v - got;
break;
#elif defined(__microblaze__)
#if defined(USE_SINGLE)
-static int arch_single_init(ElfW(RelM) *rel, struct arch_single_entry *single,
+static int arch_single_init(/*ElfW(RelM) *rel,*/ struct arch_single_entry *single,
int offset, int size)
{
if (single->allocated == 0) {
#if defined(USE_GOT_ENTRIES)
if (got_allocate) {
got_offset += arch_single_init(
- rel, &intsym->gotent,
+ /*rel,*/ &intsym->gotent,
got_offset, GOT_ENTRY_SIZE);
got_needed = 1;
plt_offset, PLT_ENTRY_SIZE);
#else
plt_offset += arch_single_init(
- rel, &intsym->pltent,
+ /*rel,*/ &intsym->pltent,
plt_offset, PLT_ENTRY_SIZE);
#endif
plt_needed = 1;
while (n > 0) {
ch = *name++;
h = (h << 4) + ch;
- if ((g = (h & 0xf0000000)) != 0) {
+ g = (h & 0xf0000000);
+ if (g != 0) {
h ^= g >> 24;
h &= ~g;
}
int n_type = ELF_ST_TYPE(info);
int n_binding = ELF_ST_BIND(info);
- for (sym = f->symtab[hash]; sym; sym = sym->next)
+ for (sym = f->symtab[hash]; sym; sym = sym->next) {
if (f->symbol_cmp(sym->name, name) == 0) {
int o_secidx = sym->secidx;
int o_info = sym->info;
return sym;
}
}
+ }
/* Completely new symbol. */
sym = arch_new_symbol();
sym->next = f->symtab[hash];
f->symtab[hash] = sym;
sym->ksymidx = -1;
-
- if (ELF_ST_BIND(info) == STB_LOCAL && symidx != -1) {
+ if (ELF_ST_BIND(info) == STB_LOCAL && symidx != (unsigned long)(-1)) {
if (symidx >= f->local_symtab_size)
bb_error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
name, (long) symidx, (long) f->local_symtab_size);
int newidx = f->header.e_shnum++;
struct obj_section *sec;
- f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
+ f->sections = xrealloc_vector(f->sections, 2, newidx);
f->sections[newidx] = sec = arch_new_section();
- memset(sec, 0, sizeof(*sec));
sec->header.sh_type = SHT_PROGBITS;
sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
sec->header.sh_size = size;
f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
f->sections[newidx] = sec = arch_new_section();
- memset(sec, 0, sizeof(*sec));
sec->header.sh_type = SHT_PROGBITS;
sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
sec->header.sh_size = size;
{
unsigned long oldsize = sec->header.sh_size;
if (more) {
- sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
+ sec->header.sh_size += more;
+ sec->contents = xrealloc(sec->contents, sec->header.sh_size);
}
return sec->contents + oldsize;
}
/*======================================================================*/
/* Functions relating to module loading after 2.1.18. */
-static int
+static void
new_process_module_arguments(struct obj_file *f, int argc, char **argv)
{
while (argc > 0) {
int min, max, n;
p = *argv;
- if ((q = strchr(p, '=')) == NULL) {
+ q = strchr(p, '=');
+ if (q == NULL) {
argc--;
continue;
}
p = get_modinfo_value(f, key);
key += 5;
if (p == NULL) {
- bb_error_msg("invalid parameter %s", key);
- return 0;
+ bb_error_msg_and_die("invalid parameter %s", key);
}
#ifdef SYMBOL_PREFIX
/* 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;
+ bb_error_msg_and_die("symbol for parameter %s not found", key);
}
if (isdigit(*p)) {
str = alloca(strlen(q));
for (r = str, q++; *q != '"'; ++q, ++r) {
- if (*q == '\0') {
- bb_error_msg("improperly terminated string argument for %s",
+ if (*q == '\0')
+ bb_error_msg_and_die("improperly terminated string argument for %s",
key);
- return 0;
- } else if (*q == '\\')
+ if (*q == '\\')
switch (*++q) {
case 'a':
*r = '\a';
default:
*r = *q;
break;
- } else
- *r = *q;
+ }
+ else
+ *r = *q;
}
*r = '\0';
++q;
/* 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"
+ bb_error_msg_and_die("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,
+ bb_error_msg_and_die("string too long for %s (max %ld)", key,
charssize - 1);
- return 0;
}
/* Copy to location */
break;
default:
- bb_error_msg("unknown parameter type '%c' for %s", *p, key);
- return 0;
+ bb_error_msg_and_die("unknown parameter type '%c' for %s", *p, key);
}
}
-
-retry_end_of_value:
+ retry_end_of_value:
switch (*q) {
case '\0':
goto end_of_arg;
case ',':
if (++n > max) {
- bb_error_msg("too many values for %s (max %d)", key, max);
- return 0;
+ bb_error_msg_and_die("too many values for %s (max %d)", key, max);
}
++q;
break;
default:
- bb_error_msg("invalid argument syntax for %s", key);
- return 0;
+ bb_error_msg_and_die("invalid argument syntax for %s", key);
}
}
-
-end_of_arg:
+ end_of_arg:
if (n < min) {
- bb_error_msg("too few values for %s (min %d)", key, min);
- return 0;
+ bb_error_msg_and_die("too few values for %s (min %d)", key, min);
}
- argc--, argv++;
+ argc--;
+ argv++;
}
-
- return 1;
}
#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
const char *p = get_modinfo_value(f, "using_checksums");
if (p)
return xatoi(p);
- else
- return 0;
+ return 0;
}
/* Get the module's kernel version in the canonical integer form. */
/* Fetch the loaded modules, and all currently exported symbols. */
-static int new_get_kernel_symbols(void)
+static void new_get_kernel_symbols(void)
{
char *module_names, *mn;
struct external_module *modules, *m;
/* Collect the loaded modules. */
- module_names = xmalloc(bufsize = 256);
-retry_modules_load:
+ bufsize = 256;
+ module_names = xmalloc(bufsize);
+
+ retry_modules_load:
if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
if (errno == ENOSPC && bufsize < ret) {
- module_names = xrealloc(module_names, bufsize = ret);
+ bufsize = ret;
+ module_names = xrealloc(module_names, bufsize);
goto retry_modules_load;
}
- bb_perror_msg("QM_MODULES");
- return 0;
+ bb_perror_msg_and_die("QM_MODULES");
}
n_ext_modules = nmod = ret;
/* The module was removed out from underneath us. */
continue;
}
- bb_perror_msg("query_module: QM_INFO: %s", mn);
- return 0;
+ bb_perror_msg_and_die("query_module: QM_INFO: %s", mn);
}
- syms = xmalloc(bufsize = 1024);
-retry_mod_sym_load:
+ bufsize = 1024;
+ syms = xmalloc(bufsize);
+ retry_mod_sym_load:
if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
switch (errno) {
case ENOSPC:
- syms = xrealloc(syms, bufsize = ret);
+ bufsize = ret;
+ syms = xrealloc(syms, bufsize);
goto retry_mod_sym_load;
case ENOENT:
/* The module was removed out from underneath us. */
continue;
default:
- bb_perror_msg("query_module: QM_SYMBOLS: %s", mn);
- return 0;
+ bb_perror_msg_and_die("query_module: QM_SYMBOLS: %s", mn);
}
}
nsyms = ret;
/* Collect the kernel's symbols. */
syms = xmalloc(bufsize = 16 * 1024);
-retry_kern_sym_load:
+ retry_kern_sym_load:
if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
if (errno == ENOSPC && bufsize < ret) {
- syms = xrealloc(syms, bufsize = ret);
+ bufsize = ret;
+ syms = xrealloc(syms, bufsize);
goto retry_kern_sym_load;
}
- bb_perror_msg("kernel: QM_SYMBOLS");
- return 0;
+ bb_perror_msg_and_die("kernel: QM_SYMBOLS");
}
nksyms = nsyms = ret;
ksyms = syms;
for (j = 0, s = syms; j < nsyms; ++j, ++s) {
s->name += (unsigned long) syms;
}
- return 1;
}
}
-static int new_create_this_module(struct obj_file *f, const char *m_name)
+static void new_create_this_module(struct obj_file *f, const char *m_name)
{
struct obj_section *sec;
obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
m_name);
-
- return 1;
}
#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
sec = obj_find_section(f, ".this");
if (!sec || !sec->contents) {
- bb_perror_msg_and_die("corrupt module %s?",m_name);
+ bb_perror_msg_and_die("corrupt module %s?", m_name);
}
module = (struct new_module *) sec->contents;
m_addr = sec->header.sh_addr;
/*======================================================================*/
-static int
+static void
obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
const char *string)
{
loc = obj_extend_section(strsec, len);
}
memcpy(loc, string, len);
-
- return 1;
}
-static int
+static void
obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
struct obj_symbol *sym)
{
p->reloc_offset = offset;
p->sym = sym;
f->symbol_patches = p;
-
- return 1;
}
-static int obj_check_undefineds(struct obj_file *f)
+static void obj_check_undefineds(struct obj_file *f)
{
- unsigned long i;
- int ret = 1;
+ unsigned i;
for (i = 0; i < HASH_BUCKETS; ++i) {
struct obj_symbol *sym;
sym->secidx = SHN_ABS;
sym->value = 0;
} else {
- if (!flag_quiet) {
- bb_error_msg("unresolved symbol %s", sym->name);
- }
- ret = 0;
+ if (!flag_quiet)
+ bb_error_msg_and_die("unresolved symbol %s", sym->name);
}
}
}
-
- return ret;
}
static void obj_allocate_commons(struct obj_file *f)
if (i == f->header.e_shnum) {
struct obj_section *sec;
- f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec));
+ f->sections = xrealloc_vector(f->sections, 2, i);
f->sections[i] = sec = arch_new_section();
f->header.e_shnum = i + 1;
- memset(sec, 0, sizeof(*sec));
sec->header.sh_type = SHT_PROGBITS;
sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
sec->name = ".bss";
/* Do it! */
switch (arch_apply_relocation
- (f, targsec, symsec, intsym, rel, value)
+ (f, targsec, /*symsec,*/ intsym, rel, value)
) {
case obj_reloc_ok:
break;
/*======================================================================*/
-static struct obj_file *obj_load(FILE * fp, int loadprogbits)
+static struct obj_file *obj_load(FILE *fp, int loadprogbits UNUSED_PARAM)
{
struct obj_file *f;
ElfW(Shdr) * section_headers;
- int shnum, i;
+ size_t shnum, i;
char *shstrtab;
/* Read the file header. */
f = arch_new_file();
- memset(f, 0, sizeof(*f));
f->symbol_cmp = strcmp;
f->symbol_hash = obj_elf_hash;
f->load_order_search_start = &f->load_order;
fseek(fp, 0, SEEK_SET);
if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
- bb_perror_msg("error reading ELF header");
- return NULL;
+ bb_perror_msg_and_die("error reading ELF header");
}
if (f->header.e_ident[EI_MAG0] != ELFMAG0
|| f->header.e_ident[EI_MAG1] != ELFMAG1
|| f->header.e_ident[EI_MAG2] != ELFMAG2
|| f->header.e_ident[EI_MAG3] != ELFMAG3) {
- bb_error_msg("not an ELF file");
- return NULL;
+ bb_error_msg_and_die("not an ELF file");
}
if (f->header.e_ident[EI_CLASS] != ELFCLASSM
|| f->header.e_ident[EI_DATA] != (BB_BIG_ENDIAN
? ELFDATA2MSB : ELFDATA2LSB)
|| f->header.e_ident[EI_VERSION] != EV_CURRENT
|| !MATCH_MACHINE(f->header.e_machine)) {
- bb_error_msg("ELF file not for this architecture");
- return NULL;
+ bb_error_msg_and_die("ELF file not for this architecture");
}
if (f->header.e_type != ET_REL) {
- bb_error_msg("ELF file not a relocatable object");
- return NULL;
+ bb_error_msg_and_die("ELF file not a relocatable object");
}
/* Read the section headers. */
if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
- bb_error_msg("section header size mismatch: %lu != %lu",
+ bb_error_msg_and_die("section header size mismatch: %lu != %lu",
(unsigned long) f->header.e_shentsize,
(unsigned long) sizeof(ElfW(Shdr)));
- return NULL;
}
shnum = f->header.e_shnum;
section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
fseek(fp, f->header.e_shoff, SEEK_SET);
if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
- bb_perror_msg("error reading ELF section headers");
- return NULL;
+ bb_perror_msg_and_die("error reading ELF section headers");
}
/* Read the section data. */
struct obj_section *sec;
f->sections[i] = sec = arch_new_section();
- memset(sec, 0, sizeof(*sec));
sec->header = section_headers[i];
sec->idx = i;
sec->contents = xmalloc(sec->header.sh_size);
fseek(fp, sec->header.sh_offset, SEEK_SET);
if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
- bb_perror_msg("error reading ELF section data");
- return NULL;
+ bb_perror_msg_and_die("error reading ELF section data");
}
} else {
sec->contents = NULL;
#if SHT_RELM == SHT_REL
case SHT_RELA:
- bb_error_msg("RELA relocations not supported on this architecture");
- return NULL;
+ bb_error_msg_and_die("RELA relocations not supported on this architecture");
#else
case SHT_REL:
- bb_error_msg("REL relocations not supported on this architecture");
- return NULL;
+ bb_error_msg_and_die("REL relocations not supported on this architecture");
#endif
-
default:
if (sec->header.sh_type >= SHT_LOPROC) {
/* Assume processor specific section types are debug
break;
}
- bb_error_msg("can't handle sections of type %ld",
+ bb_error_msg_and_die("can't handle sections of type %ld",
(long) sec->header.sh_type);
- return NULL;
}
}
}
ElfW(Sym) * sym;
if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
- bb_error_msg("symbol size mismatch: %lu != %lu",
+ bb_error_msg_and_die("symbol size mismatch: %lu != %lu",
(unsigned long) sec->header.sh_entsize,
(unsigned long) sizeof(ElfW(Sym)));
- return NULL;
}
nsym = sec->header.sh_size / sizeof(ElfW(Sym));
*/
val |= sym->st_other & 4;
#endif
-
obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
val, sym->st_size);
}
case SHT_RELM:
if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
- bb_error_msg("relocation entry size mismatch: %lu != %lu",
+ bb_error_msg_and_die("relocation entry size mismatch: %lu != %lu",
(unsigned long) sec->header.sh_entsize,
(unsigned long) sizeof(ElfW(RelM)));
- return NULL;
}
break;
/* XXX Relocation code from modutils-2.3.19 is not here.
* kernel for the module
*/
-static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase)
+static int obj_load_progbits(FILE *fp, struct obj_file *f, char *imagebase)
{
ElfW(Addr) base = f->baseaddr;
struct obj_section* sec;
* linux/include/linux/module.h. Checking for leading "GPL" will not
* work, somebody will use "GPL sucks, this is proprietary".
*/
- static const char * const gpl_licenses[] = {
+ static const char *const gpl_licenses[] = {
"GPL",
"GPL v2",
"GPL and additional rights",
"Dual BSD/GPL",
- "Dual MPL/GPL",
+ "Dual MPL/GPL"
};
sec = obj_find_section(f, ".modinfo");
while (ptr < endptr) {
value = strchr(ptr, '=');
if (value && strncmp(ptr, "license", value-ptr) == 0) {
- int i;
+ unsigned i;
if (license)
*license = value+1;
- for (i = 0; i < sizeof(gpl_licenses)/sizeof(gpl_licenses[0]); ++i) {
+ for (i = 0; i < ARRAY_SIZE(gpl_licenses); ++i) {
if (strcmp(value+1, gpl_licenses[i]) == 0)
return 0;
}
return 2;
}
- if (strchr(ptr, '\0'))
- ptr = strchr(ptr, '\0') + 1;
+ ptr = strchr(ptr, '\0');
+ if (ptr)
+ ptr++;
else
ptr = endptr;
}
}
#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)
+#define TAINT_PROPRIETORY_MODULE (1 << 0)
+#define TAINT_FORCED_MODULE (1 << 1)
+#define TAINT_UNSAFE_SMP (1 << 2)
#define TAINT_URL "http://www.tux.org/lkml/#export-tainted"
-static void set_tainted(struct obj_file *f, int fd, char *m_name,
+static void set_tainted(int fd, char *m_name,
int kernel_has_tainted, int taint, const char *text1, const char *text2)
{
+ static smallint printed_info;
+
char buf[80];
int oldval;
- static int first = 1;
+
if (fd < 0 && !kernel_has_tainted)
return; /* New modutils on old kernel */
printf("Warning: loading %s will taint the kernel: %s%s\n",
m_name, text1, text2);
- if (first) {
+ if (!printed_info) {
printf(" See %s for information about tainted modules\n", TAINT_URL);
- first = 0;
+ printed_info = 1;
}
if (fd >= 0) {
read(fd, buf, sizeof(buf)-1);
/* Check if loading this module will taint the kernel. */
static void check_tainted_module(struct obj_file *f, char *m_name)
{
- static const char tainted_file[] = TAINT_FILENAME;
+ static const char tainted_file[] ALIGN1 = TAINT_FILENAME;
+
int fd, kernel_has_tainted;
const char *ptr;
case 0:
break;
case 1:
- set_tainted(f, fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", "");
+ set_tainted(fd, m_name, kernel_has_tainted, 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, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr);
+ set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr);
break;
default:
- set_tainted(f, fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", "");
+ set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", "");
break;
}
if (flag_force_load)
- set_tainted(f, fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", "");
+ set_tainted(fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", "");
if (fd >= 0)
close(fd);
* start of some sections. this info is used by ksymoops to do better
* debugging.
*/
+#if !ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+#define get_module_version(f, str) get_module_version(str)
+#endif
static int
get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
{
add_ksymoops_symbols(struct obj_file *f, const char *filename,
const char *m_name)
{
- static const char symprefix[] = "__insmod_";
- struct obj_section *sec;
- struct obj_symbol *sym;
- char *name, *absolute_filename;
- char str[STRVERSIONLEN], real[PATH_MAX];
- int i, l, lm_name, lfilename, use_ksymtab, version;
- struct stat statbuf;
-
- static const char *section_names[] = {
+ static const char symprefix[] ALIGN1 = "__insmod_";
+ static const char section_names[][8] = {
".text",
".rodata",
".data",
".sbss"
};
- if (realpath(filename, real)) {
- absolute_filename = xstrdup(real);
- } else {
- bb_perror_msg("cannot get realpath for %s", filename);
+ struct obj_section *sec;
+ struct obj_symbol *sym;
+ char *name, *absolute_filename;
+ char str[STRVERSIONLEN];
+ unsigned i;
+ int l, lm_name, lfilename, use_ksymtab, version;
+ struct stat statbuf;
+
+ /* WARNING: was using realpath, but replaced by readlink to stop using
+ * lots of stack. But here it seems to be able to cause problems? */
+ absolute_filename = xmalloc_readlink(filename);
+ if (!absolute_filename)
absolute_filename = xstrdup(filename);
- }
lm_name = strlen(m_name);
lfilename = strlen(absolute_filename);
* is 0xffffff, decimal 16777215. putting all three fields in
* one symbol is less readable but saves kernel space.
*/
- l = sizeof(symprefix)+ /* "__insmod_" */
- lm_name+ /* module name */
- 2+ /* "_O" */
- lfilename+ /* object filename */
- 2+ /* "_M" */
- 2*sizeof(statbuf.st_mtime)+ /* mtime in hex */
- 2+ /* "_V" */
- 8+ /* version in dec */
- 1; /* nul */
+ l = sizeof(symprefix) + /* "__insmod_" */
+ lm_name + /* module name */
+ 2 + /* "_O" */
+ lfilename + /* object filename */
+ 2 + /* "_M" */
+ 2 * sizeof(statbuf.st_mtime) + /* mtime in hex */
+ 2 + /* "_V" */
+ 8 + /* version in dec */
+ 1; /* nul */
name = xmalloc(l);
if (stat(absolute_filename, &statbuf) != 0)
statbuf.st_mtime = 0;
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,
- (int)(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,
ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
/* record where the persistent data is going, same address as previous symbol */
if (f->persist) {
- l = sizeof(symprefix)+ /* "__insmod_" */
- lm_name+ /* module name */
- 2+ /* "_P" */
- strlen(f->persist)+ /* data store */
- 1; /* nul */
+ l = sizeof(symprefix) + /* "__insmod_" */
+ lm_name + /* module name */
+ 2 + /* "_P" */
+ strlen(f->persist) + /* data store */
+ 1; /* nul */
name = xmalloc(l);
snprintf(name, l, "%s%s_P%s",
symprefix, m_name, f->persist);
#endif /* _NOT_SUPPORTED_ */
/* tag the desired sections if size is non-zero */
- for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); ++i) {
+ for (i = 0; i < ARRAY_SIZE(section_names); ++i) {
sec = obj_find_section(f, section_names[i]);
if (sec && sec->header.sh_size) {
- l = sizeof(symprefix)+ /* "__insmod_" */
- lm_name+ /* module name */
- 2+ /* "_S" */
- strlen(sec->name)+ /* section name */
- 2+ /* "_L" */
- 8+ /* length in dec */
- 1; /* nul */
+ l = sizeof(symprefix) + /* "__insmod_" */
+ lm_name + /* module name */
+ 2 + /* "_S" */
+ strlen(sec->name) + /* section name */
+ 2 + /* "_L" */
+ 8 + /* length in dec */
+ 1; /* nul */
name = xmalloc(l);
snprintf(name, l, "%s%s_S%s_L%ld",
symprefix, m_name, sec->name,
#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL
/* Quick reference which section indicies are loaded. */
- loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
+ i = f->header.e_shnum;
+ loaded = alloca(sizeof(int) * i);
while (--i >= 0)
- loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
+ loaded[i] = ((f->sections[i]->header.sh_flags & SHF_ALLOC) != 0);
/* Collect the symbols we'll be listing. */
void print_load_map(struct obj_file *f);
#endif
-int insmod_main( int argc, char **argv);
-int insmod_main( int argc, char **argv)
+int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int insmod_main(int argc, char **argv)
{
char *opt_o, *arg1;
int len;
ElfW(Addr) m_addr;
struct obj_file *f;
struct stat st;
- char *m_name = 0;
+ char *m_name = NULL;
int exit_status = EXIT_FAILURE;
int m_has_modinfo;
#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
int m_version, m_crcs;
#endif
#if ENABLE_FEATURE_CLEAN_UP
- FILE *fp = 0;
+ FILE *fp = NULL;
#else
FILE *fp;
#endif
struct utsname myuname;
/* Parse any options */
- getopt32(argc, argv, OPTION_STR, &opt_o);
+ getopt32(argv, OPTION_STR, &opt_o);
arg1 = argv[optind];
if (option_mask32 & OPT_o) { // -o /* name the output module */
free(m_name);
m_name = tmp;
} else {
free(tmp1);
- tmp1 = 0; /* flag for free(m_name) before exit() */
+ tmp1 = NULL; /* flag for free(m_name) before exit() */
}
- /* Get a filedesc for the module. Check we we have a complete path */
+ /* Get a filedesc for the module. Check that we have a complete path */
if (stat(arg1, &st) < 0 || !S_ISREG(st.st_mode)
|| (fp = fopen(arg1, "r")) == NULL
) {
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(CONFIG_DEFAULT_MODULES_DIR, myuname.release);
/* 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
* /lib/modules/`uname -r` dir, So resolve it ourselves
* if it is a link... */
- if (realpath(tmdn, real_module_dir) == NULL)
- module_dir = tmdn;
- else
- module_dir = real_module_dir;
+ module_dir = xmalloc_readlink(tmdn);
+ if (!module_dir)
+ module_dir = xstrdup(tmdn);
recursive_action(module_dir, ACTION_RECURSE,
- check_module_name_match, 0, m_fullName, 0);
+ check_module_name_match, NULL, m_fullName, 0);
+ free(module_dir);
free(tmdn);
}
/* Check if we have found anything yet */
- if (m_filename == 0 || ((fp = fopen(m_filename, "r")) == NULL)) {
- char module_dir[FILENAME_MAX];
+ if (!m_filename || ((fp = fopen(m_filename, "r")) == NULL)) {
+ int r;
+ char *module_dir;
free(m_filename);
- m_filename = 0;
- if (realpath (_PATH_MODULES, module_dir) == NULL)
- strcpy(module_dir, _PATH_MODULES);
+ m_filename = NULL;
+ module_dir = xmalloc_readlink(CONFIG_DEFAULT_MODULES_DIR);
+ if (!module_dir)
+ module_dir = xstrdup(CONFIG_DEFAULT_MODULES_DIR);
/* No module found under /lib/modules/`uname -r`, this
* time cast the net a bit wider. Search /lib/modules/ */
- if (!recursive_action(module_dir, ACTION_RECURSE,
- check_module_name_match, 0, m_fullName, 0)
+ r = recursive_action(module_dir, ACTION_RECURSE,
+ check_module_name_match, NULL, m_fullName, 0);
+ if (r)
+ bb_error_msg_and_die("%s: module not found", m_fullName);
+ free(module_dir);
+ if (m_filename == NULL
+ || ((fp = fopen(m_filename, "r")) == NULL)
) {
- if (m_filename == 0
- || ((fp = fopen(m_filename, "r")) == NULL)
- ) {
- bb_error_msg("%s: no module by that name found", m_fullName);
- goto out;
- }
- } else
- bb_error_msg_and_die("%s: no module by that name found", m_fullName);
+ bb_error_msg_and_die("%s: module not found", m_fullName);
+ }
}
} else
m_filename = xstrdup(arg1);
#endif
f = obj_load(fp, LOADBITS);
- if (f == NULL)
- bb_perror_msg_and_die("cannot load the module");
if (get_modinfo_value(f, "kernel_version") == NULL)
m_has_modinfo = 0;
if (m_has_modinfo) {
m_version = new_get_module_version(f, m_strversion);
if (m_version == -1) {
- bb_error_msg("cannot find the kernel version the module was "
+ bb_error_msg_and_die("cannot 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);
+ bb_error_msg("%skernel-module version mismatch\n"
+ "\t%s was compiled for kernel version %s\n"
+ "\twhile this kernel is version %s",
+ flag_force_load ? "warning: " : "",
+ m_filename, m_strversion, uts_info.release);
+ if (!flag_force_load)
goto out;
- }
}
}
k_crcs = 0;
#endif /* FEATURE_INSMOD_VERSION_CHECKING */
- if (!query_module(NULL, 0, NULL, 0, NULL)) {
- if (!new_get_kernel_symbols())
- goto out;
- k_crcs = new_is_kernel_checksummed();
- } else {
- bb_error_msg("not configured to support old kernels");
- goto out;
- }
+ if (query_module(NULL, 0, NULL, 0, NULL))
+ bb_error_msg_and_die("not configured to support old kernels");
+ new_get_kernel_symbols();
+ k_crcs = new_is_kernel_checksummed();
#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
m_crcs = 0;
/* Allocate common symbols, symbol tables, and string tables. */
- if (!new_create_this_module(f, m_name)) {
- goto out;
- }
-
- if (!obj_check_undefineds(f)) {
- goto out;
- }
+ new_create_this_module(f, m_name);
+ obj_check_undefineds(f);
obj_allocate_commons(f);
check_tainted_module(f, m_name);
/* done with the module name, on to the optional var=value arguments */
++optind;
if (optind < argc) {
- if (!new_process_module_arguments(f, argc - optind, argv + optind)) {
- goto out;
- }
+ new_process_module_arguments(f, argc - optind, argv + optind);
}
arch_create_got(f);
/* Find current size of the module */
m_size = obj_load_size(f);
-
m_addr = create_module(m_name, m_size);
- if (m_addr == -1) switch (errno) {
+ if (m_addr == (ElfW(Addr))(-1)) switch (errno) {
case EEXIST:
- bb_error_msg("a module named %s already exists", m_name);
- goto out;
+ bb_error_msg_and_die("a module named %s already exists", m_name);
case ENOMEM:
- bb_error_msg("can't allocate kernel memory for module; needed %lu bytes",
+ bb_error_msg_and_die("can't allocate kernel memory for module; needed %lu bytes",
m_size);
- goto out;
default:
- bb_perror_msg("create_module: %s", m_name);
- goto out;
+ bb_perror_msg_and_die("create_module: %s", m_name);
}
-#if !LOADBITS
+#if !LOADBITS
/*
* the PROGBITS section was not loaded by the obj_load
* now we can load them directly into the kernel memory
*/
if (!obj_load_progbits(fp, f, (char*)m_addr)) {
- delete_module(m_name);
+ delete_module(m_name, 0);
goto out;
}
#endif
if (!obj_relocate(f, m_addr)) {
- delete_module(m_name);
+ delete_module(m_name, 0);
goto out;
}
if (!new_init_module(m_name, f, m_size)) {
- delete_module(m_name);
+ delete_module(m_name, 0);
goto out;
}
exit_status = EXIT_SUCCESS;
-out:
+ out:
#if ENABLE_FEATURE_CLEAN_UP
if (fp)
fclose(fp);
return exit_status;
}
-
-#endif
+#endif /* ENABLE_FEATURE_2_4_MODULES */
+/*
+ * End of big piece of 2.4-specific code
+ */
#if ENABLE_FEATURE_2_6_MODULES
#include <sys/mman.h>
+
+#if defined __UCLIBC__ && !ENABLE_FEATURE_2_4_MODULES
+/* big time suckage. The old prototype above renders our nice fwd-decl wrong */
+extern int init_module(void *module, unsigned long len, const char *options);
+#else
#include <asm/unistd.h>
#include <sys/syscall.h>
+#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
+#endif
/* We use error numbers in a loose translation... */
static const char *moderror(int err)
{
switch (err) {
case ENOEXEC:
- return "Invalid module format";
+ return "invalid module format";
case ENOENT:
- return "Unknown symbol in module";
+ return "unknown symbol in module";
case ESRCH:
- return "Module has wrong symbol version";
+ return "module has wrong symbol version";
case EINVAL:
- return "Invalid parameters";
+ return "invalid parameters";
default:
return strerror(err);
}
}
-int insmod_ng_main(int argc, char **argv);
-int insmod_ng_main(int argc, char **argv)
+#if !ENABLE_FEATURE_2_4_MODULES
+int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int insmod_main(int argc UNUSED_PARAM, char **argv)
+#else
+static int insmod_ng_main(int argc UNUSED_PARAM, char **argv)
+#endif
{
- long ret;
size_t len;
+ int optlen;
void *map;
char *filename, *options;
bb_show_usage();
/* Rest is options */
- options = xstrdup("");
+ options = xzalloc(1);
+ optlen = 0;
while (*++argv) {
- int optlen = strlen(options);
options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
/* Spaces handled by "" pairs, but no way of escaping quotes */
- sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv);
+ optlen += sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv);
}
#if 0
- /* Any special reason why mmap? It isn't performace critical... */
+ /* Any special reason why mmap? It isn't performance critical. -vda */
+ /* Yes, xmalloc'ing can use *alot* of RAM. Don't forget that there are
+ * modules out there that are half a megabyte! mmap()ing is way nicer
+ * for small mem boxes, i guess. */
+ /* But after load, these modules will take up that 0.5mb in kernel
+ * anyway. Using malloc here causes only a transient spike to 1mb,
+ * after module is loaded, we go back to normal 0.5mb usage
+ * (in kernel). Also, mmap isn't magic - when we touch mapped data,
+ * we use memory. -vda */
int fd;
struct stat st;
unsigned long len;
map = xmalloc_open_read_close(filename, &len);
#endif
- ret = syscall(__NR_init_module, map, len, options);
- if (ret != 0) {
- bb_perror_msg_and_die("cannot insert '%s': %s (%li)",
- filename, moderror(errno), ret);
- }
-
+ if (init_module(map, len, options) != 0)
+ bb_error_msg_and_die("cannot insert '%s': %s",
+ filename, moderror(errno));
return 0;
}