Hi, Alexey

Thanks for the patch.
在 2020年10月17日 00:00, crash-utility-requ...@redhat.com 写道:
> Date: Thu, 15 Oct 2020 13:44:32 -0700
> From: Alexey Makhalov <amakha...@vmware.com>
> To: <crash-utility@redhat.com>, <amakha...@vmware.com>
> Subject: [Crash-utility] [PATCH 2/2] kaslr: get offset by walking page
>       tree
> Message-ID: <20201015204432.4695-3-amakha...@vmware.com>
> Content-Type: text/plain
> 
> This method requires only valid CR3. It walks through
> page tree starting from __START_KERNEL_map to get real
> _stext and its physical address.
> It is used as backup method to get kaslr offset, if
> IDTR is not valid (zeroed). It might happen when kernel
> invalidates IDT, for example triggering triple fault on
> reboot (reboot=t cmdline).
> 
> This method does not support PTI (Page Table Isolation)
> case where CR3 points to the isolated page tree. So, use
> it only when CR3 points to "full" kernel.
> 
> Signed-off-by: Alexey Makhalov <amakha...@vmware.com>
> ---
>  kaslr_helper.c | 115 
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 115 insertions(+)
> 
> diff --git a/kaslr_helper.c b/kaslr_helper.c
> index bb19e54..f11cb55 100644
> --- a/kaslr_helper.c
> +++ b/kaslr_helper.c
> @@ -322,6 +322,104 @@ quit:
>  }
>  
>  /*
> + * 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.
> + *
> + * NOTES:
> + * 1. This method does not support PTI (Page Table Isolation)
> + * case where CR3 points to the isolated page tree.
> + * 2. 4-level paging support only, as caller (calc_kaslr_offset)
> + * does not support 5-level paging.
Would it be good to add a flag checking for the 5-level paging before calling
the find_kernel_start()? Seems that we can not check the machdep->flags with
the 'machdep->flags & VM_5LEVEL', because that is not initialized.

But, is that possible to check the CR4(vmss.regs64[0]->cr[4]) on x86 or the
symbols '__pgtable_l5_enabled'? 

Thanks.
Lianbo

> + */
> +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));
> +             if (pgd_pte & _PAGE_PRESENT)
> +                     break;
> +             pud_idx = pmd_idx = pte_idx = 0;
> +     }
> +     if (pgd_idx == PTRS_PER_PGD)
> +             return FALSE;
> +
> +     FILL_PUD(pgd_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
> +     for (; pud_idx < PTRS_PER_PUD; pud_idx++) {
> +             pud_pte = ULONG(machdep->pud + pud_idx * sizeof(uint64_t));
> +             if (pud_pte & _PAGE_PRESENT)
> +                     break;
> +             pmd_idx = pte_idx = 0;
> +     }
> +     if (pud_idx == PTRS_PER_PUD)
> +             return FALSE;
> +     if (pud_pte & _PAGE_PSE) {
> +             /* 1GB page */
> +             *va = (~__VIRTUAL_MASK) | ((ulong)pgd_idx << __PGDIR_SHIFT) |
> +                     ((ulong)pud_idx << PUD_SHIFT);
> +             *pa = pud_pte & PHYSICAL_PAGE_MASK;
> +             return TRUE;
> +     }
> +
> +     FILL_PMD(pud_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
> +     for (; pmd_idx < PTRS_PER_PMD; pmd_idx++) {
> +             pmd_pte = ULONG(machdep->pmd + pmd_idx * sizeof(uint64_t));
> +             if (pmd_pte & _PAGE_PRESENT)
> +                     break;
> +             pte_idx = 0;
> +     }
> +     if (pmd_idx == PTRS_PER_PMD)
> +             return FALSE;
> +     if (pmd_pte & _PAGE_PSE) {
> +             /* 2MB page */
> +             *va = (~__VIRTUAL_MASK) | ((ulong)pgd_idx << __PGDIR_SHIFT) |
> +                     ((ulong)pud_idx << PUD_SHIFT) | (pmd_idx << PMD_SHIFT);
> +             *pa = pmd_pte & PHYSICAL_PAGE_MASK;
> +             return TRUE;
> +     }
> +
> +     FILL_PTBL(pmd_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
> +     for (; pte_idx < PTRS_PER_PTE; pte_idx++) {
> +             pte = ULONG(machdep->ptbl + pte_idx * sizeof(uint64_t));
> +             if (pte & _PAGE_PRESENT)
> +                     break;
> +     }
> +     if (pte_idx == PTRS_PER_PTE)
> +             return FALSE;
> +
> +     *va = (~__VIRTUAL_MASK) | ((ulong)pgd_idx << __PGDIR_SHIFT) |
> +             ((ulong)pud_idx << PUD_SHIFT) | (pmd_idx << PMD_SHIFT) |
> +             (pte_idx << PAGE_SHIFT);
> +     *pa = pmd_pte & PHYSICAL_PAGE_MASK;
> +     return TRUE;
> +}
> +
> +/*
>   * Calculate kaslr_offset and phys_base
>   *
>   * kaslr_offset:
> @@ -445,6 +543,22 @@ retry:
>                       goto quit;
>       }
>  
> +     if (idtr == 0 && st->_stext_vmlinux && (st->_stext_vmlinux != 
> UNINITIALIZED)) {
> +             ulong va, pa;
> +             ret = find_kernel_start(&va, &pa);
> +             if (ret == FALSE)
> +                     goto quit;
> +             if (CRASHDEBUG(1)) {
> +                     fprintf(fp, "calc_kaslr_offset: _stext(vmlinux): 
> %lx\n", st->_stext_vmlinux);
> +                     fprintf(fp, "calc_kaslr_offset: kernel start VA: 
> %lx\n", va);
> +                     fprintf(fp, "calc_kaslr_offset: kernel start PA: 
> %lx\n", pa);
> +             }
> +             kaslr_offset = va - st->_stext_vmlinux;
> +             phys_base = pa - (va - __START_KERNEL_map);
> +
> +             goto found;
> +     }
> +
>       /* Convert virtual address of IDT table to physical address */
>       if (!kvtop(NULL, idtr, &idtr_paddr, verbose)) {
>               if (SADUMP_DUMPFILE())
> @@ -505,6 +619,7 @@ retry:
>               fprintf(fp, "kaslr_helper: asssuming the kdump 1st kernel.\n");
>       }
>  
> +found:
>       if (CRASHDEBUG(1)) {
>               fprintf(fp, "calc_kaslr_offset: kaslr_offset=%lx\n",
>                       kaslr_offset);
> -- 2.11.0

--
Crash-utility mailing list
Crash-utility@redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to