Hello Dave, I would like to send proposed patch set which can support PaX linux introduced at http://grsecurity.net/ over crash utility. In previous thread, you said that it is important for current implementation not to be increased maintenance burden. Then, I tolerably think to consider about them in my merge work with small modifications to current code as possible. But the reality is, there are several undesirable impacts which I made in this work. So could you please check and make a conclusion from this patch set? (Detail about modification are written in each patch file.) Thanks, Toshi -------- Toshikazu Nakayama (9): add PaX linux staff from linux-2.6.27. setup PaX module structure members and pseudos manufacture module's dumping symbol data use IN_MODULE macros for ec->st_value define new namespace command to sort by per module order vefiry PaX module RW area, also fix leak catch apt module symbol sharpen vague module data with found out section RW for lowest or highest module virtual address defs.h | 42 +++++++++++- kernel.c | 58 ++++++++++++++++- symbols.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 291 insertions(+), 30 deletions(-)
Date: Mon, 19 Dec 2011 10:26:47 +0900 Subject: [PATCH 1/9] add PaX linux staff from linux-2.6.27. [defs.h] Add rx and rw module members in offset_table and load_module structure. Define PAX() and apply this condition in IN_MODULE() and IN_MODULE_INIT(). PaX module is scattered located in both RX and RW virtual address ranges. [symbols.c: dump_offset_table()] For dumping layout of struct module, I felt specific purpose about last module_kallsyms_start entry, add new entries in front of it. [kernel.c: module_init()] Because original key member's offsets about "struct module" are removed, populate RX parts of PaX module's corresponding offsets into them. This can be seem less annoying from current implementation such like reading kallsyms, fixed is_module_adress() selection. [notes] The PAX() condition will be attached in the original palaces where need to be distinct module object's member name or value treatments but these must be small set, not make beyond necessity. [constraints] Don't support older PaX kernel features than 2.6.27 Don't consider hidden virtual address by CONFIG_PAX_KERNEXEC Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- defs.h | 40 ++++++++++++++++++++++++++++++++++++++-- kernel.c | 39 +++++++++++++++++++++++++++++++++++++++ symbols.c | 17 +++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/defs.h b/defs.h index 381e8c2..4470710 100755 --- a/defs.h +++ b/defs.h @@ -1617,6 +1617,14 @@ struct offset_table { /* stash of commonly-used offsets */ long user_regs_struct_r15; long sched_entity_cfs_rq; long sched_entity_my_q; + long module_module_core_rx; + long module_core_size_rx; + long module_module_init_rx; + long module_init_size_rx; + long module_module_core_rw; + long module_core_size_rw; + long module_module_init_rw; + long module_init_size_rw; }; struct size_table { /* stash of commonly-used sizes */ @@ -2160,14 +2168,42 @@ struct load_module { struct syment *mod_init_symend; ulong mod_percpu; ulong mod_percpu_size; + ulong module_core_rx; + uint core_size_rx; + ulong module_init_rx; + uint init_size_rx; + ulong module_core_rw; + uint core_size_rw; + ulong module_init_rw; + uint init_size_rw; }; -#define IN_MODULE(A,L) \ +#define IN_MODULE_GENERIC(A,L) \ (((ulong)(A) >= (L)->mod_base) && ((ulong)(A) < ((L)->mod_base+(L)->mod_size))) -#define IN_MODULE_INIT(A,L) \ +#define IN_MODULE_INIT_GENERIC(A,L) \ (((ulong)(A) >= (L)->mod_init_module_ptr) && ((ulong)(A) < ((L)->mod_init_module_ptr+(L)->mod_init_size))) +#define PAX() ((THIS_KERNEL_VERSION >= LINUX(2,6,27)) && \ + VALID_MEMBER(module_module_core_rx)) +#define IN_MODULE_PAX(A,L) \ + (((ulong)(A) >= (L)->module_core_rx) && \ + ((ulong)(A) < ((L)->module_core_rx+(L->core_size_rx))) || \ + ((ulong)(A) >= (L)->module_core_rw) && \ + ((ulong)(A) < ((L)->module_core_rw+(L->core_size_rw)))) + +#define IN_MODULE_INIT_PAX(A,L) \ + (((ulong)(A) >= (L)->module_init_rx) && \ + ((ulong)(A) < ((L)->module_init_rx+(L->init_size_rx))) || \ + ((ulong)(A) >= (L)->module_init_rw) && \ + ((ulong)(A) < ((L)->module_init_rw+(L->init_size_rw)))) + +#define IN_MODULE(A,L) \ + (!PAX() ? IN_MODULE_GENERIC(A,L) : IN_MODULE_PAX(A,L)) + +#define IN_MODULE_INIT(A,L) \ + ((!PAX()) ? IN_MODULE_INIT_GENERIC(A,L) : IN_MODULE_INIT_PAX(A,L)) + #define IN_MODULE_PERCPU(A,L) \ (((ulong)(A) >= (L)->mod_percpu) && ((ulong)(A) < ((L)->mod_percpu+(L)->mod_percpu_size))) diff --git a/kernel.c b/kernel.c index 2375911..a06f398 100755 --- a/kernel.c +++ b/kernel.c @@ -2754,6 +2754,45 @@ module_init(void) MEMBER_OFFSET_INIT(module_init_text_size, "module", "init_text_size"); MEMBER_OFFSET_INIT(module_percpu, "module", "percpu"); + MEMBER_OFFSET_INIT(module_module_core_rx, "module", + "module_core_rx"); + MEMBER_OFFSET_INIT(module_core_size_rx, "module", + "core_size_rx"); + MEMBER_OFFSET_INIT(module_module_init_rx, "module", + "module_init_rx"); + MEMBER_OFFSET_INIT(module_init_size_rx, "module", + "init_size_rx"); + MEMBER_OFFSET_INIT(module_module_core_rw, "module", + "module_core_rw"); + MEMBER_OFFSET_INIT(module_core_size_rw, "module", + "core_size_rw"); + MEMBER_OFFSET_INIT(module_module_init_rw, "module", + "module_init_rw"); + MEMBER_OFFSET_INIT(module_init_size_rw, "module", + "init_size_rw"); + if (PAX()) { + /* + * PaX shall populate RX offsets into original ones. + * This decision can work out PaX with less impact for + * existing routines. + * + * Since PaX module dose not own text size, + * these values should be sharpen by section attributes + * while loading them from object file. + */ + MEMBER_OFFSET_INIT(module_module_core, "module", + "module_core_rx"); + MEMBER_OFFSET_INIT(module_core_size, "module", + "core_size_rx"); + MEMBER_OFFSET_INIT(module_core_text_size, "module", + "core_size_rx"); + MEMBER_OFFSET_INIT(module_module_init, "module", + "module_init_rx"); + MEMBER_OFFSET_INIT(module_init_size, "module", + "init_size_rx"); + MEMBER_OFFSET_INIT(module_init_text_size, "module", + "init_size_rx"); + } /* * Make sure to pick the kernel "modules" list_head symbol, diff --git a/symbols.c b/symbols.c index 6a9040b..477e423 100755 --- a/symbols.c +++ b/symbols.c @@ -7638,6 +7638,23 @@ dump_offset_table(char *spec, ulong makestruct) fprintf(fp, " module_attribute_attr: %ld\n", OFFSET(module_attribute_attr)); + fprintf(fp, " module_module_core_rx: %ld\n", + OFFSET(module_module_core_rx)); + fprintf(fp, " module_core_size_rx: %ld\n", + OFFSET(module_core_size_rx)); + fprintf(fp, " module_module_init_rx: %ld\n", + OFFSET(module_module_init_rx)); + fprintf(fp, " module_init_size_rx: %ld\n", + OFFSET(module_init_size_rx)); + fprintf(fp, " module_module_core_rw: %ld\n", + OFFSET(module_module_core_rw)); + fprintf(fp, " module_core_size_rw: %ld\n", + OFFSET(module_core_size_rw)); + fprintf(fp, " module_module_init_rw: %ld\n", + OFFSET(module_module_init_rw)); + fprintf(fp, " module_init_size_rw: %ld\n", + OFFSET(module_init_size_rw)); + fprintf(fp, " module_kallsyms_start: %ld\n", OFFSET(module_kallsyms_start)); fprintf(fp, " kallsyms_header_sections: %ld\n", -- 1.7.8.163.g9859a
Date: Mon, 19 Dec 2011 11:46:23 +0900 Subject: [PATCH 2/9] setup PaX module structure members and pseudos [symbols.c: store_module_symbols_v2()] The module RX and RW core/init base and size or other section info are filled out for PaX. And pseudo symbols are set with lowest or highest virtual address of a module so that they can roll out whole a module area. [todo] PaX module dose not text size members, better to trust find_mod_etext() at this point. The .init text size won't be resolved until loading section data from object file at all. Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- symbols.c | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) diff --git a/symbols.c b/symbols.c index 477e423..2fdc7f4 100755 --- a/symbols.c +++ b/symbols.c @@ -1446,7 +1446,30 @@ store_module_symbols_v2(ulong total, int mods_installed) } lm->mod_text_start = lm->mod_base; + if (PAX()) { + lm->module_core_rx = + ULONG(modbuf + OFFSET(module_module_core_rx)); + lm->core_size_rx = + UINT(modbuf + OFFSET(module_core_size_rx)); + lm->module_init_rx = + ULONG(modbuf + OFFSET(module_module_init_rx)); + lm->init_size_rx = + UINT(modbuf + OFFSET(module_init_size_rx)); + lm->module_core_rw = + ULONG(modbuf + OFFSET(module_module_core_rw)); + lm->core_size_rw = + UINT(modbuf + OFFSET(module_core_size_rw)); + lm->module_init_rw = + ULONG(modbuf + OFFSET(module_module_init_rw)); + lm->init_size_rw = + UINT(modbuf + OFFSET(module_init_size_rw)); + /* Trust find_mod_etext() */ + lm->mod_etext_guess = 0; + } st->ext_module_symtable[mcnt].value = lm->mod_base; + if (PAX() && lm->module_core_rx > lm->module_core_rw) + st->ext_module_symtable[mcnt].value = + lm->module_core_rw; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf2, "%s%s", "_MODULE_START_", mod_name); @@ -1457,6 +1480,9 @@ store_module_symbols_v2(ulong total, int mods_installed) if (lm->mod_init_size > 0) { st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr; + if (PAX() && lm->module_init_rx > lm->module_init_rw) + st->ext_module_symtable[mcnt].value = + lm->module_init_rw; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf3, "%s%s", "_MODULE_INIT_START_", mod_name); @@ -1640,6 +1666,9 @@ store_module_symbols_v2(ulong total, int mods_installed) } st->ext_module_symtable[mcnt].value = lm->mod_base + size; + if (PAX() && lm->module_core_rx < lm->module_core_rw) + st->ext_module_symtable[mcnt].value = + lm->module_core_rw + lm->core_size_rw; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf2, "%s%s", "_MODULE_END_", mod_name); @@ -1650,6 +1679,9 @@ store_module_symbols_v2(ulong total, int mods_installed) if (lm->mod_init_size > 0) { st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr + lm->mod_init_size; + if (PAX() && lm->module_init_rx < lm->module_init_rw) + st->ext_module_symtable[mcnt].value = + lm->module_init_rw + lm->init_size_rw; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf4, "%s%s", "_MODULE_INIT_END_", mod_name); -- 1.7.8.163.g9859a
Date: Mon, 19 Dec 2011 13:37:29 +0900 Subject: [PATCH 3/9] manufacture module's dumping symbol data Make consideration of PaX module contents in symbol dump. [symbols.c: dump_symbol_table()] These values in *lm are superficially based on RX because of simplifying implementation. Reality, however, module sections are being located from different base addresses of core or init's RX or RW. Dump contents got taken care of this differences at least. Also resolve section offset gap which is not attached to mod_base, and properly show offset value from attached base address. Finally add to dump PaX module private data with the hole of virtual address space which gives hint of module allocation. This parts work only if PAX() condition is true. Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- symbols.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 83 insertions(+), 12 deletions(-) diff --git a/symbols.c b/symbols.c index 2fdc7f4..168b320 100755 --- a/symbols.c +++ b/symbols.c @@ -2821,23 +2821,33 @@ dump_symbol_table(void) fprintf(fp, " mod_text_start: %lx (%lx)\n", lm->mod_text_start, lm->mod_text_start ? - lm->mod_text_start - lm->mod_base : 0); + (!PAX()) ? lm->mod_text_start - lm->mod_base + : lm->mod_text_start - lm->module_core_rx + : 0); fprintf(fp, " mod_etext_guess: %lx (%lx)\n", - lm->mod_etext_guess, - lm->mod_etext_guess ? - lm->mod_etext_guess - lm->mod_base : 0); + lm->mod_etext_guess, + lm->mod_etext_guess ? + (!PAX()) ? lm->mod_etext_guess - lm->mod_base + : lm->mod_etext_guess - lm->module_core_rx + : 0); fprintf(fp, " mod_rodata_start: %lx (%lx)\n", - lm->mod_rodata_start, - lm->mod_rodata_start ? - lm->mod_rodata_start - lm->mod_base : 0); + lm->mod_rodata_start, + lm->mod_rodata_start ? + (!PAX()) ? lm->mod_rodata_start - lm->mod_base + : lm->mod_rodata_start - lm->module_core_rx + : 0); fprintf(fp, " mod_data_start: %lx (%lx)\n", lm->mod_data_start, lm->mod_data_start ? - lm->mod_data_start - lm->mod_base : 0); + (!PAX()) ? lm->mod_data_start - lm->mod_base + : lm->mod_data_start - lm->module_core_rw + : 0); fprintf(fp, " mod_bss_start: %lx (%lx)\n", - lm->mod_bss_start, - lm->mod_bss_start ? - lm->mod_bss_start - lm->mod_base : 0); + lm->mod_bss_start, + lm->mod_bss_start ? + (!PAX()) ? lm->mod_bss_start - lm->mod_base + : lm->mod_bss_start - lm->module_core_rw + : 0); fprintf(fp, " mod_init_size: %ld\n", lm->mod_init_size); fprintf(fp, " mod_init_text_size: %ld\n", @@ -2872,12 +2882,27 @@ dump_symbol_table(void) for (s = 0; s < lm->mod_sections; s++) { + /* + * plus gap is lower value than base address. + */ + long gap; + + gap = 0; + if (lm->mod_init_module_ptr && + STRNEQ(lm->mod_section_data[s].name, ".init")) { + gap = lm->mod_base - lm->mod_init_module_ptr; + if (PAX() && + !(lm->mod_section_data[s].priority & 8)) + gap = lm->mod_base - lm->module_init_rw; + } else if (PAX() && + !(lm->mod_section_data[s].priority & 8)) + gap = lm->mod_base - lm->module_core_rw; fprintf(fp, " %12s prio: %x flags: %05x offset: %-8lx size: %lx\n", lm->mod_section_data[s].name, lm->mod_section_data[s].priority, lm->mod_section_data[s].flags, - lm->mod_section_data[s].offset, + lm->mod_section_data[s].offset + gap, lm->mod_section_data[s].size); } @@ -2888,6 +2913,52 @@ dump_symbol_table(void) sp->value, sp->name); } } + if (!PAX()) + continue; + + fprintf(fp, " module_core_rx: %lx\n", + lm->module_core_rx); + fprintf(fp, " core_size_rx: %ld\n", lm->core_size_rx); + fprintf(fp, " module_init_rx: %lx\n", + lm->module_init_rx); + fprintf(fp, " init_size_rx: %ld\n", lm->init_size_rx); + fprintf(fp, " module_core_rw: %lx\n", + lm->module_core_rw); + fprintf(fp, " core_size_rw: %ld\n", lm->core_size_rw); + fprintf(fp, " module_init_rw: %lx\n", + lm->module_init_rw); + fprintf(fp, " init_size_rw: %ld\n", lm->init_size_rw); + + fprintf(fp, " [hole between RX and RW]\n"); + fprintf(fp, " core hole start: %lx\n", + (lm->module_core_rx < lm->module_core_rw) + ? lm->module_core_rx + lm->core_size_rx + : lm->module_core_rw + lm->core_size_rw); + fprintf(fp, " core hole end: %lx\n", + (lm->module_core_rx < lm->module_core_rw) + ? lm->module_core_rw : lm->module_core_rx); + fprintf(fp, " core hole size: %ld\n", + (lm->module_core_rx < lm->module_core_rw) + ? lm->module_core_rw - (lm->module_core_rx + + lm->core_size_rx) + : lm->module_core_rx - (lm->module_core_rw + + lm->core_size_rw)); + + if (!lm->mod_init_module_ptr) + continue; + fprintf(fp, " init hole start: %lx\n", + (lm->module_init_rx < lm->module_init_rw) + ? lm->module_init_rx + lm->init_size_rx + : lm->module_init_rw + lm->init_size_rw); + fprintf(fp, " init hole end: %lx\n", + (lm->module_init_rx < lm->module_init_rw) + ? lm->module_init_rw : lm->module_init_rx); + fprintf(fp, " init hole size: %ld\n", + (lm->module_init_rx < lm->module_init_rw) + ? lm->module_init_rw - (lm->module_init_rx + + lm->init_size_rx) + : lm->module_init_rx - (lm->module_init_rw + + lm->init_size_rw)); } fprintf(fp, "\n"); -- 1.7.8.163.g9859a
Date: Mon, 19 Dec 2011 14:07:01 +0900 Subject: [PATCH 4/9] use IN_MODULE macros for ec->st_value Make consideration of PaX module RW area. [symbols.c: store_module_kallsyms_v2()] Otherwise, all symbols in RW are discarded here. Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- symbols.c | 8 +++----- 1 files changed, 3 insertions(+), 5 deletions(-) diff --git a/symbols.c b/symbols.c index 168b320..7368eec 100755 --- a/symbols.c +++ b/symbols.c @@ -2009,11 +2009,9 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr, break; } - if (((ec->st_value < lm->mod_base) || - (ec->st_value > (lm->mod_base + lm->mod_size))) && - ((ec->st_value < lm->mod_init_module_ptr) || - (ec->st_value > (lm->mod_init_module_ptr + lm->mod_init_size)))) - continue; + if (!IN_MODULE(ec->st_value, lm) && + !IN_MODULE_INIT(ec->st_value, lm)) + continue; if (ec->st_shndx == SHN_UNDEF) continue; -- 1.7.8.163.g9859a
Date: Mon, 19 Dec 2011 14:14:37 +0900 Subject: [PATCH 5/9] define new namespace command to sort by per module order Make consideration of PaX module symbol where are in scattering location. [symbols.c: namespace_ctl()] Add NAMESPACE_PRELOAD/NAMESPACE_RESTORE command to namespace_ctl() for temporal namespace activation/deactivation before NAMESPACE_COMPLETE. [note] Don't call other namspace commands while temporal activation because realloc() can corrupt its activation. [symbols.c: store_module_symbols_v2()] When qsort() is executed in all PaX module's virtual address scope, module's symbols can not be gathered because locations are not contiguous. Potentially, symbols in .init are may the same problem as this although I've never seen that mod_init_module_ptr is non NULL. Do qsort() in per module loops by taking up new namespace command. This can prove the proper result for liner contiguous locations too. [exp] module c9046a00 probably grab module c9030000's symbol by overall qsort(). crash> module c9030000 | grep -e core -e init state_initialized = 1, init = 0xc90cb000, module_init_rx = 0x0, module_init_rw = 0x0, module_core_rx = 0xc9090000, module_core_rw = 0xc902e000, init_size_rw = 0, core_size_rw = 12948, init_size_rx = 0, core_size_rx = 236794, crash> module c9046a00 | grep -e core -e init state_initialized = 1, init = 0xc9081000, module_init_rx = 0x0, module_init_rw = 0x0, module_core_rx = 0xc90cb000, module_core_rw = 0xc9046000, init_size_rw = 0, core_size_rw = 3176, init_size_rx = 0, core_size_rx = 166780 Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- defs.h | 2 ++ symbols.c | 30 +++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/defs.h b/defs.h index 4470710..1c558b3 100755 --- a/defs.h +++ b/defs.h @@ -2028,6 +2028,8 @@ struct syment { #define NAMESPACE_FREE (3) #define NAMESPACE_INSTALL (4) #define NAMESPACE_COMPLETE (5) +#define NAMESPACE_PRELOAD (6) +#define NAMESPACE_RESTORE (7) struct namespace { char *address; diff --git a/symbols.c b/symbols.c index 7368eec..a38a804 100755 --- a/symbols.c +++ b/symbols.c @@ -1341,7 +1341,7 @@ store_module_symbols_v2(ulong total, int mods_installed) ulong nksyms; long strbuflen; ulong size; - int mcnt, lm_mcnt; + int mcnt, mcnt_pre, lm_mcnt; struct kernel_symbol *modsym; struct load_module *lm; char buf1[BUFSIZE]; @@ -1383,7 +1383,7 @@ store_module_symbols_v2(ulong total, int mods_installed) modbuf = GETBUF(SIZE(module)); modsymbuf = NULL; - m = mcnt = mod_next = 0; + m = mcnt = mod_next = mcnt_pre = 0; for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) { @@ -1696,6 +1696,15 @@ store_module_symbols_v2(ulong total, int mods_installed) if (!lm->mod_etext_guess) find_mod_etext(lm); + namespace_ctl(NAMESPACE_PRELOAD, &st->ext_module_namespace, + &st->ext_module_symtable[mcnt_pre], + &st->ext_module_symtable[mcnt]); + qsort(&st->ext_module_symtable[mcnt_pre], mcnt - mcnt_pre, + sizeof(struct syment), compare_syms); + namespace_ctl(NAMESPACE_RESTORE, &st->ext_module_namespace, + &st->ext_module_symtable[mcnt_pre], + &st->ext_module_symtable[mcnt]); + mcnt_pre = mcnt; NEXT_MODULE(mod_next, modbuf); } @@ -1707,9 +1716,6 @@ store_module_symbols_v2(ulong total, int mods_installed) namespace_ctl(NAMESPACE_COMPLETE, &st->ext_module_namespace, st->ext_module_symtable, st->ext_module_symend); - qsort(st->ext_module_symtable, mcnt, sizeof(struct syment), - compare_syms); - qsort(st->load_modules, m, sizeof(struct load_module), compare_mods); for (m = 0; m < st->mods_installed; m++) { @@ -2360,6 +2366,20 @@ namespace_ctl(int cmd, struct namespace *ns, void *nsarg1, void *nsarg2) sp->name = ns->address + (long)sp->name; return TRUE; + case NAMESPACE_PRELOAD: + sp = (struct syment *)nsarg1; + sp_end = (struct syment *)nsarg2; + for (; sp < sp_end; sp++) + sp->name = ns->address + (long)sp->name; + return TRUE; + + case NAMESPACE_RESTORE: + sp = (struct syment *)nsarg1; + sp_end = (struct syment *)nsarg2; + for (; sp < sp_end; sp++) + sp->name -= (long)ns->address; + return TRUE; + default: return FALSE; /* can't get here */ } -- 1.7.8.163.g9859a
Date: Mon, 19 Dec 2011 14:30:50 +0900 Subject: [PATCH 6/9] vefiry PaX module RW area, also fix leak [kernel.c: verify_modules()] This is may too strict but in addition to RX base and size, verify RW base and size. Fix modbuf leak at the same time. Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- kernel.c | 19 ++++++++++++++++++- 1 files changed, 18 insertions(+), 1 deletions(-) diff --git a/kernel.c b/kernel.c index a06f398..8fff0d1 100755 --- a/kernel.c +++ b/kernel.c @@ -3011,6 +3011,13 @@ verify_modules(void) if (!kvtop(NULL, lm->mod_base, &paddr, 0)) { irregularities++; break; + } else if (PAX()) { + mod_base = ULONG(modbuf + + OFFSET(module_module_core_rw)); + if (!kvtop(NULL, mod_base, &paddr, 0)) { + irregularities++; + break; + } } switch (kt->flags & (KMOD_V1|KMOD_V2)) @@ -3057,6 +3064,14 @@ verify_modules(void) (mod_size != lm->mod_size)) { irregularities++; goto irregularity; + } else if (PAX()) { + mod_size = UINT(modbuf + + OFFSET(module_core_size_rw)); + if (mod_size != + lm->core_size_rw) { + irregularities++; + goto irregularity; + } } break; } @@ -3066,8 +3081,10 @@ irregularity: } } - if (!found || irregularities) + if (!found || irregularities) { + FREEBUF(modbuf); return FALSE; + } mods_installed++; -- 1.7.8.163.g9859a
Date: Mon, 19 Dec 2011 14:40:51 +0900 Subject: [PATCH 7/9] catch apt module symbol Make consideration of PaX module's RW area search and hole of virtual address space. [symbols.c: module_symbol()] Retry RW area if failed in RX area. Without retry, module RW area is never appeared as in_ksymbol_range(). [exp] crash> sym c9046040 sym: invalid address: c9046040 [symbols.c: value_search_module()] Add IN_MODULE()s checking. Without this checking, value serching may hits the symbol where is in the hole of virtual address space. [exp] - c9046040 (d) sctp_af_inet : owner [sctp] module. crash> sym c9046040 c9046000 (b) per_cpu__cookie_scratch+85760 [ipv6] A value_search_module() hit the per_cpu__cookie_scratch symbol which is owned by ipv6 module. This reason is ipv6 module's symbols are in sctp module's hole. By checking IN_MODULE()s, such a problem can be resolved. crash> sym c9046040 c9046040 (d) sctp_af_inet [sctp] Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- symbols.c | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletions(-) diff --git a/symbols.c b/symbols.c index a38a804..6fd93bf 100755 --- a/symbols.c +++ b/symbols.c @@ -4184,6 +4184,7 @@ module_symbol(ulong value, } else continue; +retry: if ((value >= base) && (value < end)) { if (lmp) *lmp = lm; @@ -4213,6 +4214,17 @@ module_symbol(ulong value, } return TRUE; } + if (PAX()) { /* try again in RW. */ + if (base == lm->mod_base) { + base = lm->module_core_rw; + end = lm->module_core_rw + lm->core_size_rw; + goto retry; + } else if (base == lm->mod_init_module_ptr) { + base = lm->module_init_rw; + end = lm->module_init_rw + lm->init_size_rw; + goto retry; + } + } } return FALSE; @@ -4237,7 +4249,9 @@ value_search_module(ulong value, ulong *offset) retry: for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; - + if (!IN_MODULE(value, lm) && !IN_MODULE_INIT(value, lm) && + !IN_MODULE_PERCPU(value, lm)) + continue; if (search_init) { if (lm->mod_init_symtable) { sp = lm->mod_init_symtable; -- 1.7.8.163.g9859a
Date: Mon, 19 Dec 2011 16:16:29 +0900 Subject: [PATCH 8/9] sharpen vague module data with found out section [symbols.c: calculate_load_order_v2()] Because mod_etext_guess with found out section data looks more accurate than find_mod_etext() for PaX, so try to update. And mod_init_text_size was filled with mod_init_size under PAX() condition, also update with .init.text section size. This can improve reliability of is_kernel_text() return value when lm->mod_flags & MOD_LOAD_SYMS is true. In reverse, false condition is got little unreliable by this vague issues for PaX. This is constraint in PaX but I think that can be recovered almost case by previous value_search(). Delete duplicated .data section setting at the same time. Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- symbols.c | 13 +++++++++---- 1 files changed, 9 insertions(+), 4 deletions(-) diff --git a/symbols.c b/symbols.c index 6fd93bf..b51eb65 100755 --- a/symbols.c +++ b/symbols.c @@ -9523,8 +9523,12 @@ calculate_load_order_v2(struct load_module *lm, bfd *bfd, int dynamic, s1->name, s1->value, syminfo.value, secname); } - if (strcmp(secname, ".text") == 0) + if (strcmp(secname, ".text") == 0) { lm->mod_text_start = sec_start; + if (PAX()) + lm->mod_etext_guess = lm->mod_text_start + + lm->mod_section_data[i].size; + } if (strcmp(secname, ".bss") == 0) lm->mod_bss_start = sec_start; @@ -9532,11 +9536,12 @@ calculate_load_order_v2(struct load_module *lm, bfd *bfd, int dynamic, if (strcmp(secname, ".data") == 0) lm->mod_data_start = sec_start; - if (strcmp(secname, ".data") == 0) - lm->mod_data_start = sec_start; - if (strcmp(secname, ".rodata") == 0) lm->mod_rodata_start = sec_start; + + if (PAX() && lm->mod_init_text_size > 0 && + strcmp(secname, ".init.text")) + lm->mod_init_text_size = lm->mod_section_data[i].size; s1++; } } -- 1.7.8.163.g9859a
Date: Tue, 20 Dec 2011 11:00:14 +0900 Subject: [PATCH 9/9] RW for lowest or highest module virtual address Make consideration of PaX module RW base address. [symbols.c: lowest_module_address()/highest_module_address()] Compare RW base address in addtion to mod_base. Signed-off-by: Toshikazu Nakayama <nakayama.ts@xxxxxxxxxxxxxx> --- symbols.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/symbols.c b/symbols.c index b51eb65..878c597 100755 --- a/symbols.c +++ b/symbols.c @@ -2126,6 +2126,11 @@ lowest_module_address(void) low = lm->mod_base; if (low < lowest) lowest = low; + if (PAX()) { + low = lm->module_core_rw; + if (low < lowest) + lowest = low; + } } return lowest; @@ -2144,6 +2149,11 @@ highest_module_address(void) high = lm->mod_base + lm->mod_size; if (high > highest) highest = high; + if (PAX()) { + high = lm->module_core_rw + lm->core_size_rw; + if (high > highest) + highest = high; + } } return highest; -- 1.7.8.163.g9859a
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility