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)); + } 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