void print_mod_table() { print("MT n\tname\n"); for (uint32_t i=0; i<32; ++i) { auto f = uint32_t(1 << i); print("MT %||\t%||\n", i, get_mod_name(f)); } }
/* * Allocate space for a module. */ asmlinkage unsigned long sys_create_module(char *module_name, unsigned long size) { struct module *mp; void* addr; int error; int npages; int sspace = sizeof(struct module) + MOD_MAX_NAME; char name[MOD_MAX_NAME]; if (!suser()) return -EPERM; if (module_name == NULL || size == 0) return -EINVAL; if ((error = get_mod_name(module_name, name)) != 0) return error; if (find_module(name) != NULL) { return -EEXIST; } if ((mp = (struct module*) kmalloc(sspace, GFP_KERNEL)) == NULL) { return -ENOMEM; } strcpy((char *)(mp + 1), name); /* why not? */ npages = (size + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE; if ((addr = vmalloc(npages * PAGE_SIZE)) == 0) { kfree_s(mp, sspace); return -ENOMEM; } mp->next = module_list; mp->ref = NULL; mp->symtab = NULL; mp->name = (char *)(mp + 1); mp->size = npages; mp->addr = addr; mp->state = MOD_UNINITIALIZED; mp->cleanup = NULL; * (long *) addr = 0; /* set use count to zero */ module_list = mp; /* link it in */ pr_debug("module `%s' (%lu pages @ 0x%08lx) created\n", mp->name, (unsigned long) mp->size, (unsigned long) mp->addr); return (unsigned long) addr; }
asmlinkage int sys_delete_module(char *module_name) { struct module *mp; char name[MOD_MAX_NAME]; int error; if (!suser()) return -EPERM; /* else */ if (module_name != NULL) { if ((error = get_mod_name(module_name, name)) != 0) return error; if ((mp = find_module(name)) == NULL) return -ENOENT; if ((mp->ref != NULL) || ((GET_USE_COUNT(mp) & ~(MOD_AUTOCLEAN | MOD_VISITED)) != 0)) return -EBUSY; GET_USE_COUNT(mp) &= ~(MOD_AUTOCLEAN | MOD_VISITED); if (mp->state == MOD_RUNNING) (*mp->cleanup)(); mp->state = MOD_DELETED; free_modules(); } /* for automatic reaping */ else { struct module *mp_next; for (mp = module_list; mp != &kernel_module; mp = mp_next) { mp_next = mp->next; if ((mp->ref == NULL) && (mp->state == MOD_RUNNING) && ((GET_USE_COUNT(mp) & ~MOD_VISITED) == MOD_AUTOCLEAN)) { if ((GET_USE_COUNT(mp) & MOD_VISITED)) { /* Don't reap until one "cycle" after last _use_ */ GET_USE_COUNT(mp) &= ~MOD_VISITED; } else { GET_USE_COUNT(mp) &= ~(MOD_AUTOCLEAN | MOD_VISITED); (*mp->cleanup)(); mp->state = MOD_DELETED; free_modules(); } } } } return 0; }
/* * Allocate space for a module. */ asmlinkage int sys_create_module(char *module_name, unsigned long size) { int npages; void* addr; int len; char name[MOD_MAX_NAME]; char *savename; struct module *mp; int error; if (!suser()) return -EPERM; if (module_name == NULL || size == 0) return -EINVAL; if ((error = get_mod_name(module_name, name)) != 0) return error; if (find_module(name) != NULL) { return -EEXIST; } len = strlen(name) + 1; if ((savename = (char*) kmalloc(len, GFP_KERNEL)) == NULL) return -ENOMEM; memcpy(savename, name, len); if ((mp = (struct module*) kmalloc(sizeof *mp, GFP_KERNEL)) == NULL) { kfree(savename); return -ENOMEM; } npages = (size + sizeof (int) + 4095) / 4096; if ((addr = vmalloc(npages * 4096)) == 0) { kfree_s(mp, sizeof *mp); kfree(savename); return -ENOMEM; } mp->name = savename; mp->size = npages; mp->addr = addr; mp->state = MOD_UNINITIALIZED; * (int *) addr = 0; /* set use count to zero */ mp->cleanup = NULL; mp->next = module_list; module_list = mp; printk("module `%s' (%lu pages @ 0x%08lx) created\n", mp->name, (unsigned long) mp->size, (unsigned long) mp->addr); return (int) addr; }
asmlinkage int sys_delete_module(char *module_name) { struct module *mp; char name[MOD_MAX_NAME]; int error; if (!suser()) return -EPERM; if (module_name != NULL) { if ((error = get_mod_name(module_name, name)) != 0) return error; if ((mp = find_module(name)) == NULL) return -ENOENT; if (mp->state == MOD_RUNNING) (*mp->cleanup)(); mp->state = MOD_DELETED; } free_modules(); return 0; }
/* * Initialize a module. */ asmlinkage int sys_init_module(char *module_name, char *code, unsigned codesize, struct mod_routines *routines) { struct module *mp; char name[MOD_MAX_NAME]; int error; struct mod_routines rt; if (!suser()) return -EPERM; /* * First reclaim any memory from dead modules that where not * freed when deleted. Should I think be done by timers when * the module was deleted - Jon. */ free_modules(); if ((error = get_mod_name(module_name, name)) != 0) return error; printk( "initializing module `%s', %d (0x%x) bytes\n", name, codesize, codesize); memcpy_fromfs(&rt, routines, sizeof rt); if ((mp = find_module(name)) == NULL) return -ENOENT; if ((codesize + sizeof (int) + 4095) / 4096 > mp->size) return -EINVAL; memcpy_fromfs((char *)mp->addr + sizeof (int), code, codesize); memset((char *)mp->addr + sizeof (int) + codesize, 0, mp->size * 4096 - (codesize + sizeof (int))); printk( " init entry @ 0x%08lx, cleanup entry @ 0x%08lx\n", (unsigned long) rt.init, (unsigned long) rt.cleanup); mp->cleanup = rt.cleanup; if ((*rt.init)() != 0) return -EBUSY; mp->state = MOD_RUNNING; return 0; }
/* * Initialize a module. */ asmlinkage int sys_init_module(char *module_name, char *code, unsigned codesize, struct mod_routines *routines, struct symbol_table *symtab) { struct module *mp; struct symbol_table *newtab; char name[MOD_MAX_NAME]; int error; struct mod_routines rt; if (!suser()) return -EPERM; #ifdef __i386__ /* A little bit of protection... we "know" where the user stack is... */ if (symtab && ((unsigned long)symtab > 0xb0000000)) { printk(KERN_WARNING "warning: you are using an old insmod, no symbols will be inserted!\n"); symtab = NULL; } #endif if ((error = get_mod_name(module_name, name)) != 0) return error; pr_debug("initializing module `%s', %d (0x%x) bytes\n", name, codesize, codesize); memcpy_fromfs(&rt, routines, sizeof rt); if ((mp = find_module(name)) == NULL) return -ENOENT; if (codesize & MOD_AUTOCLEAN) { /* * set autoclean marker from codesize... * set usage count to "zero" */ codesize &= ~MOD_AUTOCLEAN; GET_USE_COUNT(mp) = MOD_AUTOCLEAN; } if ((codesize + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE > mp->size) return -EINVAL; memcpy_fromfs((char *)mp->addr + sizeof (long), code, codesize); memset((char *)mp->addr + sizeof (long) + codesize, 0, mp->size * PAGE_SIZE - (codesize + sizeof (long))); pr_debug("module init entry = 0x%08lx, cleanup entry = 0x%08lx\n", (unsigned long) rt.init, (unsigned long) rt.cleanup); mp->cleanup = rt.cleanup; /* update kernel symbol table */ if (symtab) { /* symtab == NULL means no new entries to handle */ struct internal_symbol *sym; struct module_ref *ref; int size; int i; int legal_start; if ((error = verify_area(VERIFY_READ, &symtab->size, sizeof(symtab->size)))) return error; size = get_user(&symtab->size); if ((newtab = (struct symbol_table*) kmalloc(size, GFP_KERNEL)) == NULL) { return -ENOMEM; } if ((error = verify_area(VERIFY_READ, symtab, size))) { kfree_s(newtab, size); return error; } memcpy_fromfs((char *)(newtab), symtab, size); /* sanity check */ legal_start = sizeof(struct symbol_table) + newtab->n_symbols * sizeof(struct internal_symbol) + newtab->n_refs * sizeof(struct module_ref); if ((newtab->n_symbols < 0) || (newtab->n_refs < 0) || (legal_start > size)) { printk(KERN_WARNING "Rejecting illegal symbol table (n_symbols=%d,n_refs=%d)\n", newtab->n_symbols, newtab->n_refs); kfree_s(newtab, size); return -EINVAL; } /* relocate name pointers, index referred from start of table */ for (sym = &(newtab->symbol[0]), i = 0; i < newtab->n_symbols; ++sym, ++i) { if ((unsigned long)sym->name < legal_start || size <= (unsigned long)sym->name) { printk(KERN_WARNING "Rejecting illegal symbol table\n"); kfree_s(newtab, size); return -EINVAL; } /* else */ sym->name += (long)newtab; } mp->symtab = newtab; /* Update module references. * On entry, from "insmod", ref->module points to * the referenced module! * Now it will point to the current module instead! * The ref structure becomes the first link in the linked * list of references to the referenced module. * Also, "sym" from above, points to the first ref entry!!! */ for (ref = (struct module_ref *)sym, i = 0; i < newtab->n_refs; ++ref, ++i) { /* Check for valid reference */ struct module *link = module_list; while (link && (ref->module != link)) link = link->next; if (link == (struct module *)0) { printk(KERN_WARNING "Non-module reference! Rejected!\n"); return -EINVAL; } ref->next = ref->module->ref; ref->module->ref = ref; ref->module = mp; } } GET_USE_COUNT(mp) += 1; if ((*rt.init)() != 0) { GET_USE_COUNT(mp) = 0; return -EBUSY; } GET_USE_COUNT(mp) -= 1; mp->state = MOD_RUNNING; return 0; }