[Crash-utility] [PATCH v2 3/3] kaslr: get offset by walking page tree

d.hatayama at fujitsu.com d.hatayama at fujitsu.com
Wed Oct 28 11:37:08 UTC 2020


>  /*
> + * Find virtual (VA) and physical (PA) addresses of kernel start
> + *
> + * va:
> + *   Actual address of the kernel start (_stext) placed
> + *   randomly by kaslr feature. To be more accurate,
> + *   VA = _stext(from vmlinux) + kaslr_offset
> + *
> + * pa:
> + *   Physical address where the kerenel is placed.
> + *
> + * In nokaslr case, VA = _stext (from vmlinux)
> + * In kaslr case, virtual address of the kernel placement goes
> + * in this range: ffffffff80000000..ffffffff9fffffff, or
> + * __START_KERNEL_map..+512MB
> + *
> + * https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt
> + *
> + * Randomized VA will be the first valid page starting from
> + * ffffffff80000000 (__START_KERNEL_map). Page tree entry of
> + * this page will contain the PA of the kernel start.

I didn't come up with this natural idea, which is better in that
IDTR is unnecessary.

> + *
> + * NOTES:
> + * 1. This method does not support PTI (Page Table Isolation)
> + * case where CR3 points to the isolated page tree.

calc_kaslr_offset() already deals with PTI here:

        if (st->pti_init_vmlinux || st->kaiser_init_vmlinux)
                pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);
        else
                pgd = cr3 & ~CR3_PCID_MASK;

Thus it's OK to think that the CR3 points at the kernel counterpart.

> + * 2. 4-level paging support only, as caller (calc_kaslr_offset)
> + * does not support 5-level paging.

According to the mm.txt the address range for kernel text appears
same in 5-level paging. What is the reason not to cover 5-level
paging in this patch? Is there something that cannot be assumed on
5-level paging?

> + */
> +static int
> +find_kernel_start(ulong *va, ulong *pa)
> +{
> +       int i, pgd_idx, pud_idx, pmd_idx, pte_idx;
> +       uint64_t pgd_pte, pud_pte, pmd_pte, pte;
> +
> +       pgd_idx = pgd_index(__START_KERNEL_map);
> +       pud_idx = pud_index(__START_KERNEL_map);
> +       pmd_idx = pmd_index(__START_KERNEL_map);
> +       pte_idx = pte_index(__START_KERNEL_map);
> +
> +       for (; pgd_idx < PTRS_PER_PGD; pgd_idx++) {
> +               pgd_pte = ULONG(machdep->pgd + pgd_idx * sizeof(uint64_t));

machdep->pgd is not guaranteed to be aligned by PAGE_SIZE.
This could refer to the pgd for userland that resides in the next page.
I guess it's necessary to get the 1st pgd entry in the page machdep->pgd belongs to.
Like this?

    pgd_pte = ULONG((machdep->pgd & PHYSICAL_PAGE_MASK) + pgd_idx * sizeof(uint64_t));

Thanks.
HATAYAMA, Daisuke






More information about the Crash-utility mailing list