--- zzzz-none-000/linux-2.6.19.2/kernel/module.c 2007-01-10 19:10:37.000000000 +0000 +++ davinci-8020-5505/linux-2.6.19.2/kernel/module.c 2007-01-19 14:42:56.000000000 +0000 @@ -43,6 +43,11 @@ #include #include #include + +#ifdef CONFIG_PAX_KERNEXEC +#include +#endif + #include #if 0 @@ -67,6 +72,8 @@ static BLOCKING_NOTIFIER_HEAD(module_notify_list); +extern int gr_check_modstop(void); + int register_module_notifier(struct notifier_block * nb) { return blocking_notifier_chain_register(&module_notify_list, nb); @@ -656,6 +663,9 @@ char name[MODULE_NAME_LEN]; int ret, forced = 0; + if (gr_check_modstop()) + return -EPERM; + if (!capable(CAP_SYS_MODULE)) return -EPERM; @@ -1142,16 +1152,19 @@ module_unload_free(mod); /* This may be NULL, but that's OK */ - module_free(mod, mod->module_init); + module_free(mod, mod->module_init_rw); + module_free_exec(mod, mod->module_init_rx); kfree(mod->args); if (mod->percpu) percpu_modfree(mod->percpu); /* Free lock-classes: */ - lockdep_free_key_range(mod->module_core, mod->core_size); + lockdep_free_key_range(mod->module_core_rx, mod->core_size_rx); + lockdep_free_key_range(mod->module_core_rw, mod->core_size_rw); /* Finally, free the core (containing the module structure) */ - module_free(mod, mod->module_core); + module_free_exec(mod, mod->module_core_rx); + module_free(mod, mod->module_core_rw); } void *__symbol_get(const char *symbol) @@ -1308,11 +1321,14 @@ || strncmp(secstrings + s->sh_name, ".init", 5) == 0) continue; - s->sh_entsize = get_offset(&mod->core_size, s); + if ((s->sh_flags & SHF_WRITE) || !(s->sh_flags & SHF_ALLOC)) + s->sh_entsize = get_offset(&mod->core_size_rw, s); + else + s->sh_entsize = get_offset(&mod->core_size_rx, s); DEBUGP("\t%s\n", secstrings + s->sh_name); } if (m == 0) - mod->core_text_size = mod->core_size; + mod->core_size_rx = mod->core_size_rx; } DEBUGP("Init section allocation order:\n"); @@ -1326,12 +1342,15 @@ || strncmp(secstrings + s->sh_name, ".init", 5) != 0) continue; - s->sh_entsize = (get_offset(&mod->init_size, s) - | INIT_OFFSET_MASK); + if ((s->sh_flags & SHF_WRITE) || !(s->sh_flags & SHF_ALLOC)) + s->sh_entsize = get_offset(&mod->init_size_rw, s); + else + s->sh_entsize = get_offset(&mod->init_size_rx, s); + s->sh_entsize |= INIT_OFFSET_MASK; DEBUGP("\t%s\n", secstrings + s->sh_name); } if (m == 0) - mod->init_text_size = mod->init_size; + mod->init_size_rx = mod->init_size_rx; } } @@ -1342,7 +1361,7 @@ if (!license_is_gpl_compatible(license)) { if (!(tainted & TAINT_PROPRIETARY_MODULE)) - printk(KERN_WARNING "%s: module license '%s' taints " + printk(KERN_WARNING "%s: module license '%s' taints" "kernel.\n", mod->name, license); add_taint_module(mod, TAINT_PROPRIETARY_MODULE); } @@ -1513,6 +1532,10 @@ struct exception_table_entry *extable; mm_segment_t old_fs; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", umod, len, uargs); if (len < sizeof(*hdr)) @@ -1671,21 +1694,57 @@ layout_sections(mod, hdr, sechdrs, secstrings); /* Do the allocs. */ - ptr = module_alloc(mod->core_size); + ptr = module_alloc(mod->core_size_rw); if (!ptr) { err = -ENOMEM; goto free_percpu; } - memset(ptr, 0, mod->core_size); - mod->module_core = ptr; + memset(ptr, 0, mod->core_size_rw); + mod->module_core_rw = ptr; + + ptr = module_alloc(mod->init_size_rw); + if (!ptr && mod->init_size_rw) { + err = -ENOMEM; + goto free_core_rw; + } + memset(ptr, 0, mod->init_size_rw); + mod->module_init_rw = ptr; + + ptr = module_alloc_exec(mod->core_size_rx); + if (!ptr) { + err = -ENOMEM; + goto free_init_rw; + } - ptr = module_alloc(mod->init_size); - if (!ptr && mod->init_size) { +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + memset(ptr, 0, mod->core_size_rx); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + mod->module_core_rx = ptr; + + ptr = module_alloc_exec(mod->init_size_rx); + if (!ptr && mod->init_size_rx) { err = -ENOMEM; - goto free_core; + goto free_core_rx; } - memset(ptr, 0, mod->init_size); - mod->module_init = ptr; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + memset(ptr, 0, mod->init_size_rx); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + mod->module_init_rx = ptr; /* Transfer each section which specifies SHF_ALLOC */ DEBUGP("final section addresses:\n"); @@ -1695,17 +1754,44 @@ if (!(sechdrs[i].sh_flags & SHF_ALLOC)) continue; - if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK) - dest = mod->module_init - + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK); - else - dest = mod->module_core + sechdrs[i].sh_entsize; + if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK) { + if ((sechdrs[i].sh_flags & SHF_WRITE) || !(sechdrs[i].sh_flags & SHF_ALLOC)) + dest = mod->module_init_rw + + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK); + else + dest = mod->module_init_rx + + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK); + } else { + if ((sechdrs[i].sh_flags & SHF_WRITE) || !(sechdrs[i].sh_flags & SHF_ALLOC)) + dest = mod->module_core_rw + sechdrs[i].sh_entsize; + else + dest = mod->module_core_rx + sechdrs[i].sh_entsize; + } + + if (sechdrs[i].sh_type != SHT_NOBITS) { - if (sechdrs[i].sh_type != SHT_NOBITS) - memcpy(dest, (void *)sechdrs[i].sh_addr, - sechdrs[i].sh_size); +#ifdef CONFIG_PAX_KERNEXEC + if (!(sechdrs[i].sh_flags & SHF_WRITE) && (sechdrs[i].sh_flags & SHF_ALLOC)) + pax_open_kernel(cr0); +#endif + + memcpy(dest, (void *)sechdrs[i].sh_addr, sechdrs[i].sh_size); + +#ifdef CONFIG_PAX_KERNEXEC + if (!(sechdrs[i].sh_flags & SHF_WRITE) && (sechdrs[i].sh_flags & SHF_ALLOC)) + pax_close_kernel(cr0); +#endif + + } /* Update sh_addr to point to copy in image. */ - sechdrs[i].sh_addr = (unsigned long)dest; + +#ifdef CONFIG_PAX_KERNEXEC + if (sechdrs[i].sh_flags & SHF_EXECINSTR) + sechdrs[i].sh_addr = (unsigned long)dest - __KERNEL_TEXT_OFFSET; + else +#endif + + sechdrs[i].sh_addr = (unsigned long)dest; DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name); } /* Module has been moved. */ @@ -1718,7 +1804,7 @@ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); if (strcmp(mod->name, "ndiswrapper") == 0) - add_taint(TAINT_PROPRIETARY_MODULE); + add_taint_module(mod, TAINT_PROPRIETARY_MODULE); if (strcmp(mod->name, "driverloader") == 0) add_taint_module(mod, TAINT_PROPRIETARY_MODULE); @@ -1726,8 +1812,18 @@ setup_modinfo(mod, sechdrs, infoindex); /* Fix up syms, so that st_value is a pointer to location. */ + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, mod); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + if (err < 0) goto cleanup; @@ -1782,11 +1878,20 @@ if (!(sechdrs[info].sh_flags & SHF_ALLOC)) continue; +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + if (sechdrs[i].sh_type == SHT_REL) err = apply_relocate(sechdrs, strtab, symindex, i,mod); else if (sechdrs[i].sh_type == SHT_RELA) err = apply_relocate_add(sechdrs, strtab, symindex, i, mod); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + if (err < 0) goto cleanup; } @@ -1800,14 +1905,31 @@ /* Set up and sort exception table */ mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); mod->extable = extable = (void *)sechdrs[exindex].sh_addr; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + sort_extable(extable, extable + mod->num_exentries); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* Finally, copy percpu area over. */ percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, sechdrs[pcpuindex].sh_size); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + err = module_finalize(hdr, sechdrs, mod); if (err < 0) goto cleanup; @@ -1821,12 +1943,12 @@ * Do it before processing of module parameters, so the module * can provide parameter accessor functions of its own. */ - if (mod->module_init) - flush_icache_range((unsigned long)mod->module_init, - (unsigned long)mod->module_init - + mod->init_size); - flush_icache_range((unsigned long)mod->module_core, - (unsigned long)mod->module_core + mod->core_size); + if (mod->module_init_rx) + flush_icache_range((unsigned long)mod->module_init_rx, + (unsigned long)mod->module_init_rx + + mod->init_size_rx); + flush_icache_range((unsigned long)mod->module_core_rx, + (unsigned long)mod->module_core_rx + mod->core_size_rx); set_fs(old_fs); @@ -1869,9 +1991,13 @@ module_arch_cleanup(mod); cleanup: module_unload_free(mod); - module_free(mod, mod->module_init); - free_core: - module_free(mod, mod->module_core); + module_free_exec(mod, mod->module_init_rx); + free_core_rx: + module_free_exec(mod, mod->module_core_rx); + free_init_rw: + module_free(mod, mod->module_init_rw); + free_core_rw: + module_free(mod, mod->module_core_rw); free_percpu: if (percpu) percpu_modfree(percpu); @@ -1907,6 +2033,9 @@ struct module *mod; int ret = 0; + if (gr_check_modstop()) + return -EPERM; + /* Must have permission */ if (!capable(CAP_SYS_MODULE)) return -EPERM; @@ -1958,10 +2087,12 @@ /* Drop initial reference. */ module_put(mod); unwind_remove_table(mod->unwind_info, 1); - module_free(mod, mod->module_init); - mod->module_init = NULL; - mod->init_size = 0; - mod->init_text_size = 0; + module_free(mod, mod->module_init_rw); + module_free_exec(mod, mod->module_init_rx); + mod->module_init_rw = NULL; + mod->module_init_rx = NULL; + mod->init_size_rw = 0; + mod->init_size_rx = 0; mutex_unlock(&module_mutex); return 0; @@ -1992,10 +2123,14 @@ unsigned long nextval; /* At worse, next value is at end of module */ - if (within(addr, mod->module_init, mod->init_size)) - nextval = (unsigned long)mod->module_init+mod->init_text_size; - else - nextval = (unsigned long)mod->module_core+mod->core_text_size; + if (within(addr, mod->module_init_rx, mod->init_size_rx)) + nextval = (unsigned long)mod->module_init_rw; + else if (within(addr, mod->module_init_rw, mod->init_size_rw)) + nextval = (unsigned long)mod->module_core_rx; + else if (within(addr, mod->module_core_rx, mod->core_size_rx)) + nextval = (unsigned long)mod->module_core_rw; + else + nextval = (unsigned long)mod->module_core_rw+mod->core_size_rw; /* Scan for closest preceeding symbol, and next symbol. (ELF starts real symbols at 1). */ @@ -2036,8 +2171,10 @@ struct module *mod; list_for_each_entry(mod, &modules, list) { - if (within(addr, mod->module_init, mod->init_size) - || within(addr, mod->module_core, mod->core_size)) { + if (within(addr, mod->module_init_rx, mod->init_size_rx) + || within(addr, mod->module_init_rw, mod->init_size_rw) + || within(addr, mod->module_core_rx, mod->core_size_rx) + || within(addr, mod->module_core_rw, mod->core_size_rw)) { if (modname) *modname = mod->name; return get_ksymbol(mod, addr, size, offset); @@ -2158,7 +2295,7 @@ char buf[8]; seq_printf(m, "%s %lu", - mod->name, mod->init_size + mod->core_size); + mod->name, mod->init_size_rx + mod->init_size_rw + mod->core_size_rx + mod->core_size_rw); print_unload_info(m, mod); /* Informative for users. */ @@ -2167,7 +2304,7 @@ mod->state == MODULE_STATE_COMING ? "Loading": "Live"); /* Used by oprofile and other similar tools. */ - seq_printf(m, " 0x%p", mod->module_core); + seq_printf(m, " 0x%p 0x%p", mod->module_core_rx, mod->module_core_rw); /* Taints info */ if (mod->taints) @@ -2225,7 +2362,8 @@ spin_lock_irqsave(&modlist_lock, flags); list_for_each_entry(mod, &modules, list) { - if (within(addr, mod->module_core, mod->core_size)) { + if (within(addr, mod->module_core_rx, mod->core_size_rx) || + within(addr, mod->module_core_rw, mod->core_size_rw)) { spin_unlock_irqrestore(&modlist_lock, flags); return 1; } @@ -2243,8 +2381,8 @@ struct module *mod; list_for_each_entry(mod, &modules, list) - if (within(addr, mod->module_init, mod->init_text_size) - || within(addr, mod->module_core, mod->core_text_size)) + if (within(addr, mod->module_init_rx, mod->init_size_rx) + || within(addr, mod->module_core_rx, mod->core_size_rx)) return mod; return NULL; }