-----Original Message----- > PaX and grsecurity kernels split module memory into dedicated r/x and > r/w mappings using '*_rw' and '*_rx' named member variables in 'struct > module'. To add basic support for such kernels detect the split layout > by testing for the corresponding structure members and use these > instead. > > So far we limit ourself to only track module code mappings for such > kernels as adding support for separate data mappings violates lots of > invariants in the rest of our code base, thereby would require a major > rework. However, with that patch applied, module code references can be > resolved in backtraces, memory and code dumps, which makes it already > very useful for analyzing such kernels. > > Signed-off-by: Mathias Krause <minipli@xxxxxxxxxxxxxx> > --- > v2: > - add members to end of struct offset_table > - add offsets to dump_offset_table() > > defs.h | 13 +++++++++++ > kernel.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++---- > symbols.c | 63 +++++++++++++++++++++++++++++++++------------------ > 3 files changed, 117 insertions(+), 27 deletions(-) > > diff --git a/defs.h b/defs.h > index 17e98763362b..ae860448ab15 100644 > --- a/defs.h > +++ b/defs.h > @@ -654,12 +654,15 @@ struct new_utsname { > #define TIMER_BASES (0x20ULL) > #define IRQ_DESC_TREE_RADIX (0x40ULL) > #define IRQ_DESC_TREE_XARRAY (0x80ULL) > +#define KMOD_PAX (0x100ULL) > > #define XEN() (kt->flags & ARCH_XEN) > #define OPENVZ() (kt->flags & ARCH_OPENVZ) > #define PVOPS() (kt->flags & ARCH_PVOPS) > #define PVOPS_XEN() (kt->flags & ARCH_PVOPS_XEN) > > +#define PAX_MODULE_SPLIT() (kt->flags2 & KMOD_PAX) > + > #define XEN_MACHINE_TO_MFN(m) ((ulonglong)(m) >> PAGESHIFT()) > #define XEN_PFN_TO_PSEUDO(p) ((ulonglong)(p) << PAGESHIFT()) > > @@ -2089,6 +2092,14 @@ struct offset_table { /* stash of commonly-used offsets */ > long size_class_size; > long gendisk_private_data; > long zram_table_entry; > + long module_core_size_rw; > + long module_core_size_rx; > + long module_init_size_rw; > + long module_init_size_rx; > + long module_module_core_rw; > + long module_module_core_rx; > + long module_module_init_rw; > + long module_module_init_rx; > }; > > struct size_table { /* stash of commonly-used sizes */ > @@ -2313,6 +2324,8 @@ struct array_table { > * in the offset table, size table or array_table. > */ > #define OFFSET(X) (OFFSET_verify(offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) > +#define MODULE_OFFSET(X,Y) (PAX_MODULE_SPLIT() ? OFFSET(Y) : OFFSET(X)) > +#define MODULE_OFFSET2(X,T) MODULE_OFFSET(X, X##_##T) > #define SIZE(X) (SIZE_verify(size_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) > #define INVALID_OFFSET (-1) > #define INVALID_MEMBER(X) (offset_table.X == INVALID_OFFSET) > diff --git a/kernel.c b/kernel.c > index f179375f2d3d..f0268adccd4a 100644 > --- a/kernel.c > +++ b/kernel.c > @@ -3540,6 +3540,62 @@ module_init(void) > "module_core"); > MEMBER_OFFSET_INIT(module_module_init, "module", > "module_init"); > + } else if (MEMBER_EXISTS("module", "module_core_rx")) { > + if (CRASHDEBUG(1)) > + error(INFO, "PaX module layout detected.\n"); > + kt->flags2 |= KMOD_PAX; > + > + MEMBER_OFFSET_INIT(module_core_size_rw, "module", > + "core_size_rw"); > + MEMBER_OFFSET_INIT(module_core_size_rx, "module", > + "core_size_rx"); > + > + MEMBER_OFFSET_INIT(module_init_size_rw, "module", > + "init_size_rw"); > + 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_module_core_rx, "module", > + "module_core_rx"); > + > + MEMBER_OFFSET_INIT(module_module_init_rw, "module", > + "module_init_rw"); > + MEMBER_OFFSET_INIT(module_module_init_rx, "module", > + "module_init_rx"); > + } else if (MEMBER_EXISTS("module_layout", "base_rx")) { > + if (CRASHDEBUG(1)) > + error(INFO, "PaX module layout detected.\n"); > + kt->flags2 |= KMOD_PAX; > + > + ASSIGN_OFFSET(module_core_size_rw) = > + MEMBER_OFFSET("module", "core_layout") + > + MEMBER_OFFSET("module_layout", "size_rw"); > + ASSIGN_OFFSET(module_core_size_rx) = > + MEMBER_OFFSET("module", "core_layout") + > + MEMBER_OFFSET("module_layout", "size_rx"); > + > + ASSIGN_OFFSET(module_init_size_rw) = > + MEMBER_OFFSET("module", "init_layout") + > + MEMBER_OFFSET("module_layout", "size_rw"); > + ASSIGN_OFFSET(module_init_size_rx) = > + MEMBER_OFFSET("module", "init_layout") + > + MEMBER_OFFSET("module_layout", "size_rx"); > + > + ASSIGN_OFFSET(module_module_core_rw) = > + MEMBER_OFFSET("module", "core_layout") + > + MEMBER_OFFSET("module_layout", "base_rw"); > + ASSIGN_OFFSET(module_module_core_rx) = > + MEMBER_OFFSET("module", "core_layout") + > + MEMBER_OFFSET("module_layout", "base_rx"); > + > + ASSIGN_OFFSET(module_module_init_rw) = > + MEMBER_OFFSET("module", "init_layout") + > + MEMBER_OFFSET("module_layout", "base_rw"); > + ASSIGN_OFFSET(module_module_init_rx) = > + MEMBER_OFFSET("module", "init_layout") + > + MEMBER_OFFSET("module_layout", "base_rx"); > } else { > ASSIGN_OFFSET(module_core_size) = > MEMBER_OFFSET("module", "core_layout") + > @@ -3682,10 +3738,10 @@ module_init(void) > case KALLSYMS_V2: > if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) { > numksyms = UINT(modbuf + OFFSET(module_num_symtab)); > - size = UINT(modbuf + OFFSET(module_core_size)); > + size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx)); > } else { > numksyms = ULONG(modbuf + OFFSET(module_num_symtab)); > - size = ULONG(modbuf + OFFSET(module_core_size)); > + size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx)); > } > > if (!size) { > @@ -3792,7 +3848,7 @@ verify_modules(void) > break; > case KMOD_V2: > mod_base = ULONG(modbuf + > - OFFSET(module_module_core)); > + MODULE_OFFSET2(module_module_core, rx)); > break; > } > > @@ -3816,10 +3872,10 @@ verify_modules(void) > OFFSET(module_name); > if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) > mod_size = UINT(modbuf + > - OFFSET(module_core_size)); > + MODULE_OFFSET2(module_core_size, rx)); > else > mod_size = ULONG(modbuf + > - OFFSET(module_core_size)); > + MODULE_OFFSET2(module_core_size, rx)); > if (strlen(module_name) < MAX_MOD_NAME) > strcpy(buf, module_name); > else > @@ -5997,6 +6053,8 @@ dump_kernel_table(int verbose) > fprintf(fp, "%sIRQ_DESC_TREE_RADIX", others++ ? "|" : ""); > if (kt->flags2 & IRQ_DESC_TREE_XARRAY) > fprintf(fp, "%sIRQ_DESC_TREE_XARRAY", others++ ? "|" : ""); > + if (kt->flags2 & KMOD_PAX) > + fprintf(fp, "%sKMOD_PAX", others++ ? "|" : ""); > fprintf(fp, ")\n"); > > fprintf(fp, " stext: %lx\n", kt->stext); > diff --git a/symbols.c b/symbols.c > index 2fecaee093a2..9a80e8a585d1 100644 > --- a/symbols.c > +++ b/symbols.c > @@ -1766,17 +1766,17 @@ store_module_symbols_v2(ulong total, int mods_installed) > > if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) { > nksyms = UINT(modbuf + OFFSET(module_num_symtab)); > - size = UINT(modbuf + OFFSET(module_core_size)); > + size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx)); > } else { > nksyms = ULONG(modbuf + OFFSET(module_num_symtab)); > - size = ULONG(modbuf + OFFSET(module_core_size)); > + size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx)); > } > > mod_name = modbuf + OFFSET(module_name); > > lm = &st->load_modules[m++]; > BZERO(lm, sizeof(struct load_module)); > - lm->mod_base = ULONG(modbuf + OFFSET(module_module_core)); > + lm->mod_base = ULONG(modbuf + MODULE_OFFSET2(module_module_core, rx)); > lm->module_struct = mod; > lm->mod_size = size; > if (strlen(mod_name) < MAX_MOD_NAME) > @@ -1795,23 +1795,23 @@ store_module_symbols_v2(ulong total, int mods_installed) > lm->mod_flags = MOD_EXT_SYMS; > lm->mod_ext_symcnt = mcnt; > lm->mod_init_module_ptr = ULONG(modbuf + > - OFFSET(module_module_init)); > + MODULE_OFFSET2(module_module_init, rx)); > if (VALID_MEMBER(module_percpu)) > lm->mod_percpu = ULONG(modbuf + OFFSET(module_percpu)); > if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) { > lm->mod_etext_guess = lm->mod_base + > - UINT(modbuf + OFFSET(module_core_text_size)); > + UINT(modbuf + MODULE_OFFSET(module_core_text_size, module_core_size_rx)); > lm->mod_init_size = > - UINT(modbuf + OFFSET(module_init_size)); > + UINT(modbuf + MODULE_OFFSET2(module_init_size, rx)); > lm->mod_init_text_size = > - UINT(modbuf + OFFSET(module_init_text_size)); > + UINT(modbuf + MODULE_OFFSET(module_init_text_size, module_init_size_rx)); > } else { > lm->mod_etext_guess = lm->mod_base + > - ULONG(modbuf + OFFSET(module_core_text_size)); > + ULONG(modbuf + MODULE_OFFSET(module_core_text_size, module_core_size_rx)); > lm->mod_init_size = > - ULONG(modbuf + OFFSET(module_init_size)); > + ULONG(modbuf + MODULE_OFFSET2(module_init_size, rx)); > lm->mod_init_text_size = > - ULONG(modbuf + OFFSET(module_init_text_size)); > + ULONG(modbuf + MODULE_OFFSET(module_init_text_size, module_init_size_rx)); > } > lm->mod_text_start = lm->mod_base; > > @@ -9113,18 +9113,37 @@ dump_offset_table(char *spec, ulong makestruct) > OFFSET(module_num_gpl_syms)); > fprintf(fp, " module_list: %ld\n", > OFFSET(module_list)); > - fprintf(fp, " module_module_core: %ld\n", > - OFFSET(module_module_core)); > - fprintf(fp, " module_core_size: %ld\n", > - OFFSET(module_core_size)); > - fprintf(fp, " module_core_text_size: %ld\n", > - OFFSET(module_core_text_size)); > - fprintf(fp, " module_init_size: %ld\n", > - OFFSET(module_init_size)); > - fprintf(fp, " module_init_text_size: %ld\n", > - OFFSET(module_init_text_size)); > - fprintf(fp, " module_module_init: %ld\n", > - OFFSET(module_module_init)); > + if (PAX_MODULE_SPLIT()) { > + fprintf(fp, " module_module_core_rx: %ld\n", > + OFFSET(module_module_core_rx)); > + fprintf(fp, " module_module_core_rw: %ld\n", > + OFFSET(module_module_core_rw)); > + fprintf(fp, " module_core_size_rx: %ld\n", > + OFFSET(module_core_size_rx)); > + fprintf(fp, " module_core_size_rw: %ld\n", > + OFFSET(module_core_size_rw)); > + fprintf(fp, " module_module_init_rx: %ld\n", > + OFFSET(module_module_init_rx)); > + fprintf(fp, " module_module_init_rw: %ld\n", > + OFFSET(module_module_init_rw)); > + fprintf(fp, " module_init_size_rx: %ld\n", > + OFFSET(module_init_size_rx)); > + fprintf(fp, " module_init_size_rw: %ld\n", > + OFFSET(module_init_size_rw)); > + } else { > + fprintf(fp, " module_module_core: %ld\n", > + OFFSET(module_module_core)); > + fprintf(fp, " module_core_size: %ld\n", > + OFFSET(module_core_size)); > + fprintf(fp, " module_core_text_size: %ld\n", > + OFFSET(module_core_text_size)); > + fprintf(fp, " module_init_size: %ld\n", > + OFFSET(module_init_size)); > + fprintf(fp, " module_init_text_size: %ld\n", > + OFFSET(module_init_text_size)); > + fprintf(fp, " module_module_init: %ld\n", > + OFFSET(module_module_init)); > + } I would prefer dumping all of the defined offsets unconditionally a little rather than this conditional switch, because they are kind of debugging information for checking if crash is working intendedly, so I think it's important to be able to also confirm they are "-1" certainly even if not used. In this patch's case, obviously they will be "-1" and not used, so might not need to be shown, but I would not like to make a precedent for future cases. Thanks, Kazu > fprintf(fp, " module_num_symtab: %ld\n", > OFFSET(module_num_symtab)); > fprintf(fp, " module_symtab: %ld\n", > -- > 2.20.1 > > > -- > Crash-utility mailing list > Crash-utility@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/crash-utility -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility