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

d.hatayama at fujitsu.com d.hatayama at fujitsu.com
Thu Oct 29 03:22:14 UTC 2020


> 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.
> Good point, thanks!

And also this logic is based on the kernel logic that such pgt pair
is generated even when PTI is disabled at runtime. But I think you should test
with PTI disabled for in case.

> 
> 
> + * 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?
> There are no technical challenges. I just do not have Ice lake machine to test it.

I see.

> Do you know how I can get dump/vmlinux with 5-level paging enabled?

At least I don't have Ice Lake machine and I cannot share such crash dump.

> Once 5-level paging support is done, this method can be used as default, as there are
> no limitations.



> 
> 
> + */
> +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));
> As I understand machdep->pgd is a buffer, cached value of some pgd table from the dump.
> machdep->pgd does not have to be aligned in the memory.
> We just need to read at specific offset "pgd_idx * sizeof(uint64_t)” to get our pgd_pte.
> I think " & PHYSICAL_PAGE_MASK” is not needed here.
> Let me know if I wrong.

As I said in another mail, the comment from me was wrong; I was confused by pgd.

> 
> But i’m going to introduce pgd prefetch from inside find_kernel_start() to do not depend on
> prefetch from the caller. So caller must provide top pgd physical address
> 
> @@ -350,7 +350,7 @@ quit:
>   * does not support 5-level paging.
>   */
>  static int
> -find_kernel_start(ulong *va, ulong *pa)
> +find_kernel_start(uint64_t pgd, ulong *va, ulong *pa)
>  {
>         int i, pgd_idx, pud_idx, pmd_idx, pte_idx;
>         uint64_t pgd_pte, pud_pte, pmd_pte, pte;
> @@ -361,6 +358,7 @@ find_kernel_start(ulong *va, ulong *pa)
>         pmd_idx = pmd_index(__START_KERNEL_map);
>         pte_idx = pte_index(__START_KERNEL_map);
> 
> +       FILL_PGD(pgd & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
>         for (; pgd_idx < PTRS_PER_PGD; pgd_idx++) {
>                 pgd_pte = ULONG(machdep->pgd + pgd_idx * sizeof(uint64_t));
>                 if (pgd_pte & _PAGE_PRESENT)
> 
> Thanks for review. Again will wait for 5-level paging dump/machine availability and send the improved patch.
> Do you want me to switch to this method as default (to use it before IDTR method)?

Yes. Please remove the condition idtr == 0. By this, we can calculate kaslr_offset
in earlier kernel boot phase where IDTR is not configured.

Also,

> +       if (idtr == 0 && st->_stext_vmlinux && (st->_stext_vmlinux != UNINITIALIZED)) {
> +               ulong va, pa;
> +               ret = find_kernel_start(&va, &pa);
> +               if (ret == FALSE)
> +                       goto quit;

this gives up the search immediately. Please keep searching remaining registers,
at least for sadump format.

> +               kaslr_offset = va - st->_stext_vmlinux;
> +               phys_base = pa - (va - __START_KERNEL_map);
> +
> +               goto found;
> +       }

Please do linux_banner sanity check for in case at least for sadump format.

Thanks.
HATAYAMA, Daisuke






More information about the Crash-utility mailing list