|
Packit |
bf408e |
/*
|
|
Packit |
bf408e |
* kaslr_helper - helper for kaslr offset calculation
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* Copyright (c) 2011 FUJITSU LIMITED
|
|
Packit |
bf408e |
* Copyright (c) 2018 Red Hat Inc.
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
bf408e |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
bf408e |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
bf408e |
* (at your option) any later version.
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
bf408e |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
bf408e |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
bf408e |
* GNU General Public License for more details.
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* Authors: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
|
|
Packit |
bf408e |
* INDOH Takao <indou.takao@jp.fujitsu.com>
|
|
Packit |
bf408e |
* Sergio Lopez <slp@redhat.com>
|
|
Packit |
bf408e |
*/
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
#include "defs.h"
|
|
Packit |
bf408e |
#include <elf.h>
|
|
Packit |
bf408e |
#include <inttypes.h>
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
#ifdef X86_64
|
|
Packit |
bf408e |
/*
|
|
Packit |
bf408e |
* Get address of vector0 interrupt handler (Devide Error) from Interrupt
|
|
Packit |
bf408e |
* Descriptor Table.
|
|
Packit |
bf408e |
*/
|
|
Packit |
bf408e |
static ulong
|
|
Packit |
bf408e |
get_vec0_addr(ulong idtr)
|
|
Packit |
bf408e |
{
|
|
Packit |
bf408e |
struct gate_struct64 {
|
|
Packit |
bf408e |
uint16_t offset_low;
|
|
Packit |
bf408e |
uint16_t segment;
|
|
Packit |
bf408e |
uint32_t ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
|
|
Packit |
bf408e |
uint16_t offset_middle;
|
|
Packit |
bf408e |
uint32_t offset_high;
|
|
Packit |
bf408e |
uint32_t zero1;
|
|
Packit |
bf408e |
} __attribute__((packed)) gate;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
readmem(idtr, PHYSADDR, &gate, sizeof(gate), "idt_table", FAULT_ON_ERROR);
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
return ((ulong)gate.offset_high << 32)
|
|
Packit |
bf408e |
+ ((ulong)gate.offset_middle << 16)
|
|
Packit |
bf408e |
+ gate.offset_low;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/*
|
|
Packit |
bf408e |
* Parse a string of [size[KMG] ]offset[KMG]
|
|
Packit |
bf408e |
* Import from Linux kernel(lib/cmdline.c)
|
|
Packit |
bf408e |
*/
|
|
Packit |
bf408e |
static ulong
|
|
Packit |
bf408e |
memparse(char *ptr, char **retptr)
|
|
Packit |
bf408e |
{
|
|
Packit |
bf408e |
char *endptr;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
unsigned long long ret = strtoull(ptr, &endptr, 0);
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
switch (*endptr) {
|
|
Packit |
bf408e |
case 'E':
|
|
Packit |
bf408e |
case 'e':
|
|
Packit |
bf408e |
ret <<= 10;
|
|
Packit |
bf408e |
case 'P':
|
|
Packit |
bf408e |
case 'p':
|
|
Packit |
bf408e |
ret <<= 10;
|
|
Packit |
bf408e |
case 'T':
|
|
Packit |
bf408e |
case 't':
|
|
Packit |
bf408e |
ret <<= 10;
|
|
Packit |
bf408e |
case 'G':
|
|
Packit |
bf408e |
case 'g':
|
|
Packit |
bf408e |
ret <<= 10;
|
|
Packit |
bf408e |
case 'M':
|
|
Packit |
bf408e |
case 'm':
|
|
Packit |
bf408e |
ret <<= 10;
|
|
Packit |
bf408e |
case 'K':
|
|
Packit |
bf408e |
case 'k':
|
|
Packit |
bf408e |
ret <<= 10;
|
|
Packit |
bf408e |
endptr++;
|
|
Packit |
bf408e |
default:
|
|
Packit |
bf408e |
break;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (retptr)
|
|
Packit |
bf408e |
*retptr = endptr;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
return ret;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/*
|
|
Packit |
bf408e |
* Find "elfcorehdr=" in the boot parameter of kernel and return the address
|
|
Packit |
bf408e |
* of elfcorehdr.
|
|
Packit |
bf408e |
*/
|
|
Packit |
bf408e |
static ulong
|
|
Packit |
bf408e |
get_elfcorehdr(ulong kaslr_offset)
|
|
Packit |
bf408e |
{
|
|
Packit |
bf408e |
char cmdline[BUFSIZE], *ptr;
|
|
Packit |
bf408e |
ulong cmdline_vaddr;
|
|
Packit |
bf408e |
ulong cmdline_paddr;
|
|
Packit |
bf408e |
ulong buf_vaddr, buf_paddr;
|
|
Packit |
bf408e |
char *end;
|
|
Packit |
bf408e |
ulong elfcorehdr_addr = 0, elfcorehdr_size = 0;
|
|
Packit |
bf408e |
int verbose = CRASHDEBUG(1)? 1: 0;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
cmdline_vaddr = st->saved_command_line_vmlinux + kaslr_offset;
|
|
Packit |
bf408e |
if (!kvtop(NULL, cmdline_vaddr, &cmdline_paddr, verbose))
|
|
Packit |
bf408e |
return 0;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (CRASHDEBUG(1)) {
|
|
Packit |
bf408e |
fprintf(fp, "cmdline vaddr=%lx\n", cmdline_vaddr);
|
|
Packit |
bf408e |
fprintf(fp, "cmdline paddr=%lx\n", cmdline_paddr);
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (!readmem(cmdline_paddr, PHYSADDR, &buf_vaddr, sizeof(ulong),
|
|
Packit |
bf408e |
"saved_command_line", RETURN_ON_ERROR))
|
|
Packit |
bf408e |
return 0;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (!kvtop(NULL, buf_vaddr, &buf_paddr, verbose))
|
|
Packit |
bf408e |
return 0;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (CRASHDEBUG(1)) {
|
|
Packit |
bf408e |
fprintf(fp, "cmdline buffer vaddr=%lx\n", buf_vaddr);
|
|
Packit |
bf408e |
fprintf(fp, "cmdline buffer paddr=%lx\n", buf_paddr);
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
memset(cmdline, 0, BUFSIZE);
|
|
Packit |
bf408e |
if (!readmem(buf_paddr, PHYSADDR, cmdline, BUFSIZE,
|
|
Packit |
bf408e |
"saved_command_line", RETURN_ON_ERROR))
|
|
Packit |
bf408e |
return 0;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
ptr = strstr(cmdline, "elfcorehdr=");
|
|
Packit |
bf408e |
if (!ptr)
|
|
Packit |
bf408e |
return 0;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (CRASHDEBUG(1))
|
|
Packit |
bf408e |
fprintf(fp, "2nd kernel detected\n");
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
ptr += strlen("elfcorehdr=");
|
|
Packit |
bf408e |
elfcorehdr_addr = memparse(ptr, &end;;
|
|
Packit |
bf408e |
if (*end == '@') {
|
|
Packit |
bf408e |
elfcorehdr_size = elfcorehdr_addr;
|
|
Packit |
bf408e |
elfcorehdr_addr = memparse(end + 1, &end;;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (CRASHDEBUG(1)) {
|
|
Packit |
bf408e |
fprintf(fp, "elfcorehdr_addr=%lx\n", elfcorehdr_addr);
|
|
Packit |
bf408e |
fprintf(fp, "elfcorehdr_size=%lx\n", elfcorehdr_size);
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
return elfcorehdr_addr;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/*
|
|
Packit |
bf408e |
* Get vmcoreinfo from elfcorehdr.
|
|
Packit |
bf408e |
* Some codes are imported from Linux kernel(fs/proc/vmcore.c)
|
|
Packit |
bf408e |
*/
|
|
Packit |
bf408e |
static int
|
|
Packit |
bf408e |
get_vmcoreinfo(ulong elfcorehdr, ulong *addr, int *len)
|
|
Packit |
bf408e |
{
|
|
Packit |
bf408e |
unsigned char e_ident[EI_NIDENT];
|
|
Packit |
bf408e |
Elf64_Ehdr ehdr;
|
|
Packit |
bf408e |
Elf64_Phdr phdr;
|
|
Packit |
bf408e |
Elf64_Nhdr nhdr;
|
|
Packit |
bf408e |
ulong ptr;
|
|
Packit |
bf408e |
ulong nhdr_offset = 0;
|
|
Packit |
bf408e |
int i;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (!readmem(elfcorehdr, PHYSADDR, e_ident, EI_NIDENT,
|
|
Packit |
bf408e |
"EI_NIDENT", RETURN_ON_ERROR))
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (e_ident[EI_CLASS] != ELFCLASS64) {
|
|
Packit |
bf408e |
error(INFO, "Only ELFCLASS64 is supportd\n");
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (!readmem(elfcorehdr, PHYSADDR, &ehdr, sizeof(ehdr),
|
|
Packit |
bf408e |
"Elf64_Ehdr", RETURN_ON_ERROR))
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/* Sanity Check */
|
|
Packit |
bf408e |
if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
|
|
Packit |
bf408e |
(ehdr.e_type != ET_CORE) ||
|
|
Packit |
bf408e |
ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
|
|
Packit |
bf408e |
ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
|
|
Packit |
bf408e |
ehdr.e_version != EV_CURRENT ||
|
|
Packit |
bf408e |
ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
|
|
Packit |
bf408e |
ehdr.e_phentsize != sizeof(Elf64_Phdr) ||
|
|
Packit |
bf408e |
ehdr.e_phnum == 0) {
|
|
Packit |
bf408e |
error(INFO, "Invalid elf header\n");
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
ptr = elfcorehdr + ehdr.e_phoff;
|
|
Packit |
bf408e |
for (i = 0; i < ehdr.e_phnum; i++) {
|
|
Packit |
bf408e |
ulong offset;
|
|
Packit |
bf408e |
char name[16];
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (!readmem(ptr, PHYSADDR, &phdr, sizeof(phdr),
|
|
Packit |
bf408e |
"Elf64_Phdr", RETURN_ON_ERROR))
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
ptr += sizeof(phdr);
|
|
Packit |
bf408e |
if (phdr.p_type != PT_NOTE)
|
|
Packit |
bf408e |
continue;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
offset = phdr.p_offset;
|
|
Packit |
bf408e |
if (!readmem(offset, PHYSADDR, &nhdr, sizeof(nhdr),
|
|
Packit |
bf408e |
"Elf64_Nhdr", RETURN_ON_ERROR))
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
offset += DIV_ROUND_UP(sizeof(Elf64_Nhdr), sizeof(Elf64_Word))*
|
|
Packit |
bf408e |
sizeof(Elf64_Word);
|
|
Packit |
bf408e |
memset(name, 0, sizeof(name));
|
|
Packit |
bf408e |
if (!readmem(offset, PHYSADDR, name, sizeof(name),
|
|
Packit |
bf408e |
"Elf64_Nhdr name", RETURN_ON_ERROR))
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if(!strcmp(name, "VMCOREINFO")) {
|
|
Packit |
bf408e |
nhdr_offset = offset;
|
|
Packit |
bf408e |
break;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (!nhdr_offset)
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
*addr = nhdr_offset +
|
|
Packit |
bf408e |
DIV_ROUND_UP(nhdr.n_namesz, sizeof(Elf64_Word))*
|
|
Packit |
bf408e |
sizeof(Elf64_Word);
|
|
Packit |
bf408e |
*len = nhdr.n_descsz;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (CRASHDEBUG(1)) {
|
|
Packit |
bf408e |
fprintf(fp, "vmcoreinfo addr=%lx\n", *addr);
|
|
Packit |
bf408e |
fprintf(fp, "vmcoreinfo len=%d\n", *len);
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
return TRUE;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
static int
|
|
Packit Service |
2d41f0 |
qemu_get_nr_cpus(void)
|
|
Packit Service |
2d41f0 |
{
|
|
Packit Service |
2d41f0 |
if (DISKDUMP_DUMPFILE())
|
|
Packit Service |
2d41f0 |
return diskdump_get_nr_cpus();
|
|
Packit Service |
2d41f0 |
else if (KDUMP_DUMPFILE())
|
|
Packit Service |
2d41f0 |
return kdump_get_nr_cpus();
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
return 0;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
static int
|
|
Packit Service |
2d41f0 |
qemu_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr)
|
|
Packit |
bf408e |
{
|
|
Packit |
bf408e |
QEMUCPUState *cpustat;
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
if (DISKDUMP_DUMPFILE())
|
|
Packit Service |
2d41f0 |
cpustat = diskdump_get_qemucpustate(cpu);
|
|
Packit Service |
2d41f0 |
else if (KDUMP_DUMPFILE())
|
|
Packit Service |
2d41f0 |
cpustat = kdump_get_qemucpustate(cpu);
|
|
Packit Service |
2d41f0 |
else
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
if (!cpustat)
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
*cr3 = cpustat->cr[3];
|
|
Packit Service |
2d41f0 |
*cr4 = cpustat->cr[4];
|
|
Packit |
bf408e |
*idtr = cpustat->idt.base;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
return TRUE;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/*
|
|
Packit |
bf408e |
* Check if current kaslr_offset/phys_base is for 1st kernel or 2nd kernel.
|
|
Packit |
bf408e |
* If we are in 2nd kernel, get kaslr_offset/phys_base from vmcoreinfo.
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* 1. Get command line and try to retrieve "elfcorehdr=" boot parameter
|
|
Packit |
bf408e |
* 2. If "elfcorehdr=" is not found in command line, we are in 1st kernel.
|
|
Packit |
bf408e |
* There is nothing to do.
|
|
Packit |
bf408e |
* 3. If "elfcorehdr=" is found, we are in 2nd kernel. Find vmcoreinfo
|
|
Packit |
bf408e |
* using "elfcorehdr=" and retrieve kaslr_offset/phys_base from vmcoreinfo.
|
|
Packit |
bf408e |
*/
|
|
Packit |
bf408e |
static int
|
|
Packit |
bf408e |
get_kaslr_offset_from_vmcoreinfo(ulong orig_kaslr_offset,
|
|
Packit |
bf408e |
ulong *kaslr_offset, ulong *phys_base)
|
|
Packit |
bf408e |
{
|
|
Packit |
bf408e |
ulong elfcorehdr_addr = 0;
|
|
Packit |
bf408e |
ulong vmcoreinfo_addr;
|
|
Packit |
bf408e |
int vmcoreinfo_len;
|
|
Packit |
bf408e |
char *buf, *pos;
|
|
Packit |
bf408e |
int ret = FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/* Find "elfcorehdr=" in the kernel boot parameter */
|
|
Packit |
bf408e |
elfcorehdr_addr = get_elfcorehdr(orig_kaslr_offset);
|
|
Packit |
bf408e |
if (!elfcorehdr_addr)
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/* Get vmcoreinfo from the address of "elfcorehdr=" */
|
|
Packit |
bf408e |
if (!get_vmcoreinfo(elfcorehdr_addr, &vmcoreinfo_addr, &vmcoreinfo_len))
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (!vmcoreinfo_len)
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (CRASHDEBUG(1))
|
|
Packit |
bf408e |
fprintf(fp, "Find vmcoreinfo in kdump memory\n");
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
buf = GETBUF(vmcoreinfo_len);
|
|
Packit |
bf408e |
if (!readmem(vmcoreinfo_addr, PHYSADDR, buf, vmcoreinfo_len,
|
|
Packit |
bf408e |
"vmcoreinfo", RETURN_ON_ERROR))
|
|
Packit |
bf408e |
goto quit;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/* Get phys_base form vmcoreinfo */
|
|
Packit |
bf408e |
pos = strstr(buf, "NUMBER(phys_base)=");
|
|
Packit |
bf408e |
if (!pos)
|
|
Packit |
bf408e |
goto quit;
|
|
Packit |
bf408e |
*phys_base = strtoull(pos + strlen("NUMBER(phys_base)="), NULL, 0);
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
/* Get kaslr_offset form vmcoreinfo */
|
|
Packit |
bf408e |
pos = strstr(buf, "KERNELOFFSET=");
|
|
Packit |
bf408e |
if (!pos)
|
|
Packit |
bf408e |
goto quit;
|
|
Packit |
bf408e |
*kaslr_offset = strtoull(pos + strlen("KERNELOFFSET="), NULL, 16);
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
ret = TRUE;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
quit:
|
|
Packit |
bf408e |
FREEBUF(buf);
|
|
Packit |
bf408e |
return ret;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
static int
|
|
Packit Service |
2d41f0 |
get_nr_cpus(void)
|
|
Packit Service |
2d41f0 |
{
|
|
Packit Service |
2d41f0 |
if (SADUMP_DUMPFILE())
|
|
Packit Service |
2d41f0 |
return sadump_get_nr_cpus();
|
|
Packit Service |
2d41f0 |
else if (QEMU_MEM_DUMP_NO_VMCOREINFO())
|
|
Packit Service |
2d41f0 |
return qemu_get_nr_cpus();
|
|
Packit Service |
2d41f0 |
else if (VMSS_DUMPFILE())
|
|
Packit Service |
2d41f0 |
return vmware_vmss_get_nr_cpus();
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
return 0;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
static int
|
|
Packit Service |
2d41f0 |
get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr)
|
|
Packit Service |
2d41f0 |
{
|
|
Packit Service |
2d41f0 |
if (SADUMP_DUMPFILE())
|
|
Packit Service |
2d41f0 |
return sadump_get_cr3_cr4_idtr(cpu, cr3, cr4, idtr);
|
|
Packit Service |
2d41f0 |
else if (QEMU_MEM_DUMP_NO_VMCOREINFO())
|
|
Packit Service |
2d41f0 |
return qemu_get_cr3_cr4_idtr(cpu, cr3, cr4, idtr);
|
|
Packit Service |
2d41f0 |
else if (VMSS_DUMPFILE())
|
|
Packit Service |
2d41f0 |
return vmware_vmss_get_cr3_cr4_idtr(cpu, cr3, cr4, idtr);
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
#define BANNER "Linux version"
|
|
Packit Service |
2d41f0 |
static int
|
|
Packit Service |
2d41f0 |
verify_kaslr_offset(ulong kaslr_offset)
|
|
Packit Service |
2d41f0 |
{
|
|
Packit Service |
2d41f0 |
char buf[sizeof(BANNER)];
|
|
Packit Service |
2d41f0 |
ulong linux_banner_paddr;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
if (!kvtop(NULL, st->linux_banner_vmlinux + kaslr_offset,
|
|
Packit Service |
2d41f0 |
&linux_banner_paddr, CRASHDEBUG(1)))
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
if (!readmem(linux_banner_paddr, PHYSADDR, buf, sizeof(buf),
|
|
Packit Service |
2d41f0 |
"linux_banner", RETURN_ON_ERROR))
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
if (!STRNEQ(buf, BANNER))
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
return TRUE;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit |
bf408e |
/*
|
|
Packit Service |
2d41f0 |
* Find virtual (VA) and physical (PA) addresses of kernel start
|
|
Packit |
bf408e |
*
|
|
Packit Service |
2d41f0 |
* va:
|
|
Packit Service |
2d41f0 |
* Actual address of the kernel start (_stext) placed
|
|
Packit Service |
2d41f0 |
* randomly by kaslr feature. To be more accurate,
|
|
Packit Service |
2d41f0 |
* VA = _stext(from vmlinux) + kaslr_offset
|
|
Packit |
bf408e |
*
|
|
Packit Service |
2d41f0 |
* pa:
|
|
Packit Service |
2d41f0 |
* Physical address where the kerenel is placed.
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* In nokaslr case, VA = _stext (from vmlinux)
|
|
Packit Service |
2d41f0 |
* In kaslr case, virtual address of the kernel placement goes
|
|
Packit Service |
2d41f0 |
* in this range: ffffffff80000000..ffffffff9fffffff, or
|
|
Packit Service |
2d41f0 |
* __START_KERNEL_map..+512MB
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* Randomized VA will be the first valid page starting from
|
|
Packit Service |
2d41f0 |
* ffffffff80000000 (__START_KERNEL_map). Page tree entry of
|
|
Packit Service |
2d41f0 |
* this page will contain the PA of the kernel start.
|
|
Packit Service |
2d41f0 |
*/
|
|
Packit Service |
2d41f0 |
static int
|
|
Packit Service |
2d41f0 |
find_kernel_start(uint64_t pgd, ulong *va, ulong *pa)
|
|
Packit Service |
2d41f0 |
{
|
|
Packit Service |
2d41f0 |
int pgd_idx, p4d_idx, pud_idx, pmd_idx, pte_idx;
|
|
Packit Service |
2d41f0 |
uint64_t pgd_pte = 0, pud_pte, pmd_pte, pte;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
pgd_idx = pgd_index(__START_KERNEL_map);
|
|
Packit Service |
2d41f0 |
if (machdep->flags & VM_5LEVEL)
|
|
Packit Service |
2d41f0 |
p4d_idx = p4d_index(__START_KERNEL_map);
|
|
Packit Service |
2d41f0 |
pud_idx = pud_index(__START_KERNEL_map);
|
|
Packit Service |
2d41f0 |
pmd_idx = pmd_index(__START_KERNEL_map);
|
|
Packit Service |
2d41f0 |
pte_idx = pte_index(__START_KERNEL_map);
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
/* If the VM is in 5-level page table */
|
|
Packit Service |
2d41f0 |
if (machdep->flags & VM_5LEVEL)
|
|
Packit Service |
2d41f0 |
*va = ~((1UL << 57) - 1);
|
|
Packit Service |
2d41f0 |
else
|
|
Packit Service |
2d41f0 |
*va = ~__VIRTUAL_MASK;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
FILL_PGD(pgd & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
|
|
Packit Service |
2d41f0 |
for (; pgd_idx < PTRS_PER_PGD; pgd_idx++) {
|
|
Packit Service |
2d41f0 |
pgd_pte = ULONG(machdep->pgd + pgd_idx * sizeof(uint64_t));
|
|
Packit Service |
2d41f0 |
if (pgd_pte & _PAGE_PRESENT)
|
|
Packit Service |
2d41f0 |
break;
|
|
Packit Service |
2d41f0 |
p4d_idx = pud_idx = pmd_idx = pte_idx = 0;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
if (pgd_idx == PTRS_PER_PGD)
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
*va |= (ulong)pgd_idx << __PGDIR_SHIFT;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
if (machdep->flags & VM_5LEVEL) {
|
|
Packit Service |
2d41f0 |
FILL_P4D(pgd_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
|
|
Packit Service |
2d41f0 |
for (; p4d_idx < PTRS_PER_P4D; p4d_idx++) {
|
|
Packit Service |
2d41f0 |
/* reuse pgd_pte */
|
|
Packit Service |
2d41f0 |
pgd_pte = ULONG(machdep->machspec->p4d + p4d_idx * sizeof(uint64_t));
|
|
Packit Service |
2d41f0 |
if (pgd_pte & _PAGE_PRESENT)
|
|
Packit Service |
2d41f0 |
break;
|
|
Packit Service |
2d41f0 |
pud_idx = pmd_idx = pte_idx = 0;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
if (p4d_idx == PTRS_PER_P4D)
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
*va |= (ulong)p4d_idx << P4D_SHIFT;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
FILL_PUD(pgd_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
|
|
Packit Service |
2d41f0 |
for (; pud_idx < PTRS_PER_PUD; pud_idx++) {
|
|
Packit Service |
2d41f0 |
pud_pte = ULONG(machdep->pud + pud_idx * sizeof(uint64_t));
|
|
Packit Service |
2d41f0 |
if (pud_pte & _PAGE_PRESENT)
|
|
Packit Service |
2d41f0 |
break;
|
|
Packit Service |
2d41f0 |
pmd_idx = pte_idx = 0;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
if (pud_idx == PTRS_PER_PUD)
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
*va |= (ulong)pud_idx << PUD_SHIFT;
|
|
Packit Service |
2d41f0 |
if (pud_pte & _PAGE_PSE) {
|
|
Packit Service |
2d41f0 |
/* 1GB page */
|
|
Packit Service |
2d41f0 |
*pa = pud_pte & PHYSICAL_PAGE_MASK;
|
|
Packit Service |
2d41f0 |
return TRUE;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
FILL_PMD(pud_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
|
|
Packit Service |
2d41f0 |
for (; pmd_idx < PTRS_PER_PMD; pmd_idx++) {
|
|
Packit Service |
2d41f0 |
pmd_pte = ULONG(machdep->pmd + pmd_idx * sizeof(uint64_t));
|
|
Packit Service |
2d41f0 |
if (pmd_pte & _PAGE_PRESENT)
|
|
Packit Service |
2d41f0 |
break;
|
|
Packit Service |
2d41f0 |
pte_idx = 0;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
if (pmd_idx == PTRS_PER_PMD)
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
*va |= pmd_idx << PMD_SHIFT;
|
|
Packit Service |
2d41f0 |
if (pmd_pte & _PAGE_PSE) {
|
|
Packit Service |
2d41f0 |
/* 2MB page */
|
|
Packit Service |
2d41f0 |
*pa = pmd_pte & PHYSICAL_PAGE_MASK;
|
|
Packit Service |
2d41f0 |
return TRUE;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
FILL_PTBL(pmd_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
|
|
Packit Service |
2d41f0 |
for (; pte_idx < PTRS_PER_PTE; pte_idx++) {
|
|
Packit Service |
2d41f0 |
pte = ULONG(machdep->ptbl + pte_idx * sizeof(uint64_t));
|
|
Packit Service |
2d41f0 |
if (pte & _PAGE_PRESENT)
|
|
Packit Service |
2d41f0 |
break;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
if (pte_idx == PTRS_PER_PTE)
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
*va |= pte_idx << PAGE_SHIFT;
|
|
Packit Service |
2d41f0 |
*pa = pmd_pte & PHYSICAL_PAGE_MASK;
|
|
Packit Service |
2d41f0 |
return TRUE;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
/*
|
|
Packit Service |
2d41f0 |
* Page Tables based method to calculate kaslr_offset and phys_base.
|
|
Packit Service |
2d41f0 |
* It uses VA and PA of kernel start.
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* kaslr offset and phys_base are calculated as follows:
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* kaslr_offset = VA - st->_stext_vmlinux
|
|
Packit Service |
2d41f0 |
* phys_base = PA - (VA - __START_KERNEL_map)
|
|
Packit Service |
2d41f0 |
*/
|
|
Packit Service |
2d41f0 |
static int
|
|
Packit Service |
2d41f0 |
calc_kaslr_offset_from_page_tables(uint64_t pgd, ulong *kaslr_offset,
|
|
Packit Service |
2d41f0 |
ulong *phys_base)
|
|
Packit Service |
2d41f0 |
{
|
|
Packit Service |
2d41f0 |
ulong va, pa;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
if (!st->_stext_vmlinux || st->_stext_vmlinux == UNINITIALIZED) {
|
|
Packit Service |
2d41f0 |
fprintf(fp, "%s: st->_stext_vmlinux must be initialized\n",
|
|
Packit Service |
2d41f0 |
__FUNCTION__);
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
if (!find_kernel_start(pgd, &va, &pa))
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
if (CRASHDEBUG(1)) {
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: _stext(vmlinux): %lx\n", st->_stext_vmlinux);
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: kernel start VA: %lx\n", va);
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: kernel start PA: %lx\n", pa);
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
*kaslr_offset = va - st->_stext_vmlinux;
|
|
Packit Service |
2d41f0 |
*phys_base = pa - (va - __START_KERNEL_map);
|
|
Packit Service |
2d41f0 |
return TRUE;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
/*
|
|
Packit Service |
2d41f0 |
* IDT based method to calculate kaslr_offset and phys_base
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* kaslr offset and phys_base are calculated as follows:
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* kaslr_offset:
|
|
Packit |
bf408e |
* 1) Get IDTR and CR3 value from the dump header.
|
|
Packit |
bf408e |
* 2) Get a virtual address of IDT from IDTR value
|
|
Packit |
bf408e |
* --- (A)
|
|
Packit |
bf408e |
* 3) Translate (A) to physical address using CR3, the upper 52 bits
|
|
Packit |
bf408e |
* of which points a top of page table.
|
|
Packit |
bf408e |
* --- (B)
|
|
Packit |
bf408e |
* 4) Get an address of vector0 (Devide Error) interrupt handler from
|
|
Packit |
bf408e |
* IDT, which are pointed by (B).
|
|
Packit |
bf408e |
* --- (C)
|
|
Packit |
bf408e |
* 5) Get an address of symbol "divide_error" form vmlinux
|
|
Packit |
bf408e |
* --- (D)
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* Now we have two addresses:
|
|
Packit |
bf408e |
* (C)-> Actual address of "divide_error"
|
|
Packit |
bf408e |
* (D)-> Original address of "divide_error" in the vmlinux
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* kaslr_offset can be calculated by the difference between these two
|
|
Packit |
bf408e |
* value.
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* phys_base;
|
|
Packit |
bf408e |
* 1) Get IDT virtual address from vmlinux
|
|
Packit |
bf408e |
* --- (E)
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* So phys_base can be calculated using relationship of directly mapped
|
|
Packit |
bf408e |
* address.
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* phys_base =
|
|
Packit |
bf408e |
* Physical address(B) -
|
|
Packit |
bf408e |
* (Virtual address(E) + kaslr_offset - __START_KERNEL_map)
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* Note that the address (A) cannot be used instead of (E) because (A) is
|
|
Packit |
bf408e |
* not direct map address, it's a fixed map address.
|
|
Packit |
bf408e |
*
|
|
Packit Service |
2d41f0 |
* NOTE: This solution works in most every case, but does not work in the
|
|
Packit Service |
2d41f0 |
* following case. If the dump is captured on early stage of kernel boot,
|
|
Packit Service |
2d41f0 |
* IDTR points to the early IDT table(early_idts) instead of normal
|
|
Packit Service |
2d41f0 |
* IDT(idt_table). Need enhancement.
|
|
Packit Service |
2d41f0 |
*/
|
|
Packit Service |
2d41f0 |
static int
|
|
Packit Service |
2d41f0 |
calc_kaslr_offset_from_idt(uint64_t idtr, uint64_t pgd, ulong *kaslr_offset, ulong *phys_base)
|
|
Packit Service |
2d41f0 |
{
|
|
Packit Service |
2d41f0 |
uint64_t idtr_paddr;
|
|
Packit Service |
2d41f0 |
ulong divide_error_vmcore;
|
|
Packit Service |
2d41f0 |
int verbose = CRASHDEBUG(1)? 1: 0;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
if (!idtr)
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
/* Convert virtual address of IDT table to physical address */
|
|
Packit Service |
2d41f0 |
if (!kvtop(NULL, idtr, &idtr_paddr, verbose))
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
/* Now we can calculate kaslr_offset and phys_base */
|
|
Packit Service |
2d41f0 |
divide_error_vmcore = get_vec0_addr(idtr_paddr);
|
|
Packit Service |
2d41f0 |
*kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux;
|
|
Packit Service |
2d41f0 |
*phys_base = idtr_paddr -
|
|
Packit Service |
2d41f0 |
(st->idt_table_vmlinux + *kaslr_offset - __START_KERNEL_map);
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
if (verbose) {
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr);
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: pgd=%lx\n", pgd);
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: idtr(phys)=%lx\n", idtr_paddr);
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: divide_error(vmlinux): %lx\n",
|
|
Packit Service |
2d41f0 |
st->divide_error_vmlinux);
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: divide_error(vmcore): %lx\n",
|
|
Packit Service |
2d41f0 |
divide_error_vmcore);
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
return TRUE;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
/*
|
|
Packit Service |
2d41f0 |
* Calculate kaslr_offset and phys_base
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* kaslr_offset:
|
|
Packit Service |
2d41f0 |
* The difference between original address in System.map or vmlinux and
|
|
Packit Service |
2d41f0 |
* actual address placed randomly by kaslr feature. To be more accurate,
|
|
Packit Service |
2d41f0 |
* kaslr_offset = actual address - original address
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* phys_base:
|
|
Packit Service |
2d41f0 |
* Physical address where the kerenel is placed. In other words, it's a
|
|
Packit Service |
2d41f0 |
* physical address of __START_KERNEL_map. This is also decided randomly by
|
|
Packit Service |
2d41f0 |
* kaslr.
|
|
Packit |
bf408e |
*
|
|
Packit Service |
2d41f0 |
* It walks through all available CPUs registers to calculate the offset/base.
|
|
Packit |
bf408e |
*
|
|
Packit Service |
2d41f0 |
* Also, it considers the case where dump is captured whle kdump is working,
|
|
Packit Service |
2d41f0 |
* IDTR points to the IDT table of 2nd kernel, not 1st kernel.
|
|
Packit Service |
2d41f0 |
* In that case, get kaslr_offset and phys_base as follows.
|
|
Packit |
bf408e |
*
|
|
Packit |
bf408e |
* 1) Get kaslr_offset and phys_base using the above solution.
|
|
Packit |
bf408e |
* 2) Get kernel boot parameter from "saved_command_line"
|
|
Packit |
bf408e |
* 3) If "elfcorehdr=" is not included in boot parameter, we are in the
|
|
Packit |
bf408e |
* first kernel, nothing to do any more.
|
|
Packit |
bf408e |
* 4) If "elfcorehdr=" is included in boot parameter, we are in the 2nd
|
|
Packit |
bf408e |
* kernel. Retrieve vmcoreinfo from address of "elfcorehdr=" and
|
|
Packit |
bf408e |
* get kaslr_offset and phys_base from vmcoreinfo.
|
|
Packit |
bf408e |
*/
|
|
Packit |
bf408e |
#define PTI_USER_PGTABLE_BIT PAGE_SHIFT
|
|
Packit |
bf408e |
#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT)
|
|
Packit |
bf408e |
#define CR3_PCID_MASK 0xFFFull
|
|
Packit Service |
2d41f0 |
#define CR4_LA57 (1 << 12)
|
|
Packit |
bf408e |
int
|
|
Packit Service |
2d41f0 |
calc_kaslr_offset(ulong *ko, ulong *pb)
|
|
Packit |
bf408e |
{
|
|
Packit Service |
2d41f0 |
uint64_t cr3 = 0, cr4 = 0, idtr = 0, pgd = 0;
|
|
Packit Service |
2d41f0 |
ulong kaslr_offset, phys_base;
|
|
Packit |
bf408e |
ulong kaslr_offset_kdump, phys_base_kdump;
|
|
Packit Service |
2d41f0 |
int cpu, nr_cpus;
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (!machine_type("X86_64"))
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
nr_cpus = get_nr_cpus();
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
for (cpu = 0; cpu < nr_cpus; cpu++) {
|
|
Packit Service |
2d41f0 |
if (!get_cr3_cr4_idtr(cpu, &cr3, &cr4, &idtr))
|
|
Packit Service |
2d41f0 |
continue;
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
if (!cr3)
|
|
Packit Service |
2d41f0 |
continue;
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
if (st->pti_init_vmlinux || st->kaiser_init_vmlinux)
|
|
Packit Service |
2d41f0 |
pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);
|
|
Packit Service |
2d41f0 |
else
|
|
Packit Service |
2d41f0 |
pgd = cr3 & ~CR3_PCID_MASK;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
/*
|
|
Packit Service |
2d41f0 |
* Set up for kvtop.
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* calc_kaslr_offset() is called before machdep_init(PRE_GDB), so some
|
|
Packit Service |
2d41f0 |
* variables are not initialized yet. Set up them here to call kvtop().
|
|
Packit Service |
2d41f0 |
*
|
|
Packit Service |
2d41f0 |
* TODO: XEN is not supported
|
|
Packit Service |
2d41f0 |
*/
|
|
Packit Service |
2d41f0 |
vt->kernel_pgd[0] = pgd;
|
|
Packit Service |
2d41f0 |
machdep->last_pgd_read = vt->kernel_pgd[0];
|
|
Packit Service |
2d41f0 |
if (cr4 & CR4_LA57) {
|
|
Packit Service |
2d41f0 |
machdep->flags |= VM_5LEVEL;
|
|
Packit Service |
2d41f0 |
machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_5LEVEL;
|
|
Packit Service |
2d41f0 |
machdep->machspec->pgdir_shift = PGDIR_SHIFT_5LEVEL;
|
|
Packit Service |
2d41f0 |
machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_5LEVEL;
|
|
Packit Service |
2d41f0 |
if ((machdep->machspec->p4d = (char *)malloc(PAGESIZE())) == NULL)
|
|
Packit Service |
2d41f0 |
error(FATAL, "cannot malloc p4d space.");
|
|
Packit Service |
2d41f0 |
machdep->machspec->last_p4d_read = 0;
|
|
Packit Service |
2d41f0 |
} else {
|
|
Packit Service |
2d41f0 |
machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6;
|
|
Packit Service |
2d41f0 |
machdep->machspec->pgdir_shift = PGDIR_SHIFT;
|
|
Packit Service |
2d41f0 |
machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit Service |
2d41f0 |
if (!readmem(pgd, PHYSADDR, machdep->pgd, PAGESIZE(),
|
|
Packit Service |
2d41f0 |
"pgd", RETURN_ON_ERROR))
|
|
Packit Service |
2d41f0 |
continue;
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
if (!calc_kaslr_offset_from_page_tables(pgd, &kaslr_offset,
|
|
Packit Service |
2d41f0 |
&phys_base)) {
|
|
Packit Service |
2d41f0 |
if (!calc_kaslr_offset_from_idt(idtr, pgd,
|
|
Packit Service |
2d41f0 |
&kaslr_offset,
|
|
Packit Service |
2d41f0 |
&phys_base))
|
|
Packit Service |
2d41f0 |
continue;
|
|
Packit Service |
2d41f0 |
}
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
if (verify_kaslr_offset(kaslr_offset))
|
|
Packit Service |
2d41f0 |
goto found;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
vt->kernel_pgd[0] = 0;
|
|
Packit Service |
2d41f0 |
machdep->last_pgd_read = 0;
|
|
Packit Service |
2d41f0 |
return FALSE;
|
|
Packit Service |
2d41f0 |
|
|
Packit Service |
2d41f0 |
found:
|
|
Packit |
bf408e |
/*
|
|
Packit |
bf408e |
* Check if current kaslr_offset/phys_base is for 1st kernel or 2nd
|
|
Packit |
bf408e |
* kernel. If we are in 2nd kernel, get kaslr_offset/phys_base
|
|
Packit |
bf408e |
* from vmcoreinfo
|
|
Packit |
bf408e |
*/
|
|
Packit Service |
2d41f0 |
if (get_kaslr_offset_from_vmcoreinfo(kaslr_offset, &kaslr_offset_kdump,
|
|
Packit Service |
2d41f0 |
&phys_base_kdump)) {
|
|
Packit Service |
2d41f0 |
kaslr_offset = kaslr_offset_kdump;
|
|
Packit Service |
2d41f0 |
phys_base = phys_base_kdump;
|
|
Packit |
bf408e |
} else if (CRASHDEBUG(1)) {
|
|
Packit |
bf408e |
fprintf(fp, "kaslr_helper: failed to determine which kernel was running at crash,\n");
|
|
Packit |
bf408e |
fprintf(fp, "kaslr_helper: asssuming the kdump 1st kernel.\n");
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit |
bf408e |
if (CRASHDEBUG(1)) {
|
|
Packit |
bf408e |
fprintf(fp, "calc_kaslr_offset: kaslr_offset=%lx\n",
|
|
Packit Service |
2d41f0 |
kaslr_offset);
|
|
Packit Service |
2d41f0 |
fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", phys_base);
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
|
|
Packit Service |
2d41f0 |
*ko = kaslr_offset;
|
|
Packit Service |
2d41f0 |
*pb = phys_base;
|
|
Packit Service |
2d41f0 |
|
|
Packit |
bf408e |
vt->kernel_pgd[0] = 0;
|
|
Packit |
bf408e |
machdep->last_pgd_read = 0;
|
|
Packit Service |
2d41f0 |
return TRUE;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
#else
|
|
Packit |
bf408e |
int
|
|
Packit |
bf408e |
calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_page)
|
|
Packit |
bf408e |
{
|
|
Packit |
bf408e |
return FALSE;
|
|
Packit |
bf408e |
}
|
|
Packit |
bf408e |
#endif /* X86_64 */
|