Hi Georges,
Thanks for the update.
On 2023/02/07 23:02, Aureau, Georges (Kernel Tools ERT) wrote:
Hello Kazu,
Thanks tons for your valuable comments, below is round #2.
With respect to the RHEL8 crash patch, it consisted of simply removing the 'if
(THIS_KERNEL_VERSION >= LINUX(5,7,0))' from freelist_ptr(), suited for
RHEL8.6/RHEL8.7, but obviously not for upstream.
Right, when RHEL8.6 enabled the CONFIG_SLAB_FREELIST_HARDENED, it
already had 1ad53d9fa3f6, so it's enough for RHEL8 crash to only
check VALID_MEMBER(kmem_cache_random).
Cheers,
Georges
--
diff --git a/defs.h b/defs.h
index 33a823b..56d6cf4 100644
--- a/defs.h
+++ b/defs.h
@@ -2638,6 +2638,7 @@ struct vm_table { /* kernel VM-related data */
#define SLAB_OVERLOAD_PAGE (0x8000000)
#define SLAB_CPU_CACHE (0x10000000)
#define SLAB_ROOT_CACHES (0x20000000)
+#define FREELIST_PTR_BSWAP (0x40000000)
With the following code showing it,
Acked-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
--- a/memory.c
+++ b/memory.c
@@ -13932,6 +13932,8 @@ dump_vm_table(int verbose)
fprintf(fp, "%sSLAB_CPU_CACHE", others++ ? "|" : "");\
if (vt->flags & SLAB_ROOT_CACHES)
fprintf(fp, "%sSLAB_ROOT_CACHES", others++ ? "|" :
"");\
+ if (vt->flags & FREELIST_PTR_BSWAP)
+ fprintf(fp, "%sFREELIST_PTR_BSWAP", others++ ? "|" :
"");\
if (vt->flags & USE_VMAP_AREA)
fprintf(fp, "%sUSE_VMAP_AREA", others++ ? "|" : "");\
if (vt->flags & CONFIG_NUMA)
Could I have your Signed-off-by: tag? Or it's helpful for us
if you would send a formal patch with the above diff.
Thanks,
Kazu
>
> #define IS_FLATMEM() (vt->flags & FLATMEM)
> #define IS_DISCONTIGMEM() (vt->flags & DISCONTIGMEM)
> diff --git a/memory.c b/memory.c
> index 5141fbe..b235b7c 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -320,6 +320,7 @@ static void dump_per_cpu_offsets(void);
> static void dump_page_flags(ulonglong);
> static ulong kmem_cache_nodelists(ulong);
> static void dump_hstates(void);
> +static void freelist_ptr_init(void);
> static ulong freelist_ptr(struct meminfo *, ulong, ulong);
> static ulong handle_each_vm_area(struct handle_each_vm_area_args *);
>
> @@ -370,7 +371,6 @@ mem_init(void)
> DISPLAY_DEFAULT = (sizeof(long) == 8) ? DISPLAY_64 : DISPLAY_32;
> }
>
> -
> /*
> * Stash a few popular offsets and some basic kernel virtual memory
> * items used by routines in this file.
> @@ -789,6 +789,8 @@ vm_init(void)
> MEMBER_OFFSET_INIT(kmem_cache_name, "kmem_cache",
"name");
> MEMBER_OFFSET_INIT(kmem_cache_flags, "kmem_cache",
"flags");
> MEMBER_OFFSET_INIT(kmem_cache_random, "kmem_cache",
"random");
> + if (VALID_MEMBER(kmem_cache_random))
> + freelist_ptr_init();
> MEMBER_OFFSET_INIT(kmem_cache_cpu_freelist,
"kmem_cache_cpu", "freelist");
> MEMBER_OFFSET_INIT(kmem_cache_cpu_page, "kmem_cache_cpu",
"page");
> if (INVALID_MEMBER(kmem_cache_cpu_page))
> @@ -19519,13 +19521,65 @@ count_free_objects(struct meminfo *si, ulong freelist)
> return c;
> }
>
> +/*
> + * With CONFIG_SLAB_FREELIST_HARDENED, freelist_ptr's are crypted with
xor's,
> + * and for recent release with an additionnal bswap. Some releases prio to 5.7.0
> + * may be using the additionnal bswap. The only easy and reliable way to tell is
> + * to inspect assembly code (eg. "__slab_free") for a bswap instruction.
> + */
> +static int
> +freelist_ptr_bswap_x86(void)
> +{
> + struct syment *sp, *spn;
> + char buf1[BUFSIZE];
> + char buf2[BUFSIZE];
> + char *arglist[MAXARGS];
> + ulong vaddr;
> + int found;
> +
> + if (!(sp = symbol_search("__slab_free")) ||
> + !(spn = next_symbol(NULL, sp)))
> + return FALSE;
> +
> + sprintf(buf1, "x/%ldi 0x%lx", spn->value - sp->value,
sp->value);
> +
> + found = FALSE;
> + vaddr = 0;
> + open_tmpfile();
> + gdb_pass_through(buf1, pc->tmpfile, GNU_RETURN_ON_ERROR);
> + rewind(pc->tmpfile);
> + while (fgets(buf2, BUFSIZE, pc->tmpfile)) {
> + if (parse_line(buf2, arglist) < 3)
> + continue;
> +
> + if ((vaddr = htol(strip_ending_char(arglist[0], ':'),
> + RETURN_ON_ERROR|QUIET, NULL)) >= spn->value)
> + continue;
> +
> + if (STREQ(arglist[2], "bswap")) {
> + found = TRUE;
> + break;
> + }
> + }
> + close_tmpfile();
> + return found;
> +}
> +
> +static void
> +freelist_ptr_init(void)
> +{
> + if (THIS_KERNEL_VERSION >= LINUX(5,7,0) ||
> + ((machine_type("X86_64") || machine_type("X86"))
&& freelist_ptr_bswap_x86()))
> + vt->flags |= FREELIST_PTR_BSWAP;
> +}
> +
> static ulong
> freelist_ptr(struct meminfo *si, ulong ptr, ulong ptr_addr)
> {
> if (VALID_MEMBER(kmem_cache_random)) {
> /* CONFIG_SLAB_FREELIST_HARDENED */
>
> - if (THIS_KERNEL_VERSION >= LINUX(5,7,0))
> + if (vt->flags & FREELIST_PTR_BSWAP)
> ptr_addr = (sizeof(long) == 8) ? bswap_64(ptr_addr)
> : bswap_32(ptr_addr);
> return (ptr ^ si->random ^ ptr_addr);