内核打开kaslr后的调试方法

本文基于ARM64平台代码分析,ARM64平台的内核,在编译链接时,kernel代码段被链接的位置是:KIMAGE_VADDR + TEXT_OFFSET。我们可以通过查看vmlinux.lds.S链接文件查看具体内容:

. = KIMAGE_VADDR + TEXT_OFFSET;

.head.text : {
    _text = .;
    HEAD_TEXT
}

下面依次介绍各个变量。

TEXT_OFFSET

默认情况下:

TEXT_OFFSET := 0x00080000

KIMAGE_VADDR

内核中定义KIMAGE_VADDR实际上就是vmalloc区域的起始地址,也就是MODULES_END处的地址。

#define KIMAGE_VADDR        (MODULES_END)

从这一段,我们可以得到一个重要的关系,那就是KIMAGE_VADDR的值等于内核编译链接地址减去TEXT_OFFSET。

kimage_vaddr

ARM64平台运行时,kernel代码段被映射到虚拟地址空间,如果没有使能kaslr特性,那么被映射的地址就是链接的地址处,如果使能了kalsr,那么实际映射的地址可能就与链接的地址不一样,中间会多出来一个偏差kaslr offset,先暂且不管这这种情况,先看如下定义:

ENTRY(kimage_vaddr)
    .quad       _text - TEXT_OFFSET

从这个计算关系中,内核在运行时定义了kimage_vaddr,它的值等于内核实际运行地址_text减去TEXT_OFFSET。

kaslr offset

kaslr特性会对内核加载地址做relocation,上面也做了一点介绍,使能该特性后,内核实际映射的运行时地址和链接地址是不一样的,中间差距kaslr offset值。

那么它是怎么实现的呢?

在内核代码被映射到虚拟地址空间时,参考 __create_page_tables: 函数,默认是加载到链接地址处,也就是KIMAGE_VADDR + TEXT_OFFSET 位置处,但是使能了kaslr特性后,就会在映射前对地址做一个偏移,也就是kaslr offset值。

mov_q   x5, KIMAGE_VADDR + TEXT_OFFSET  // compile time __va(_text)
add x5, x5, x23         // add KASLR displacement

由此我们得知:

kernel_run_address = KIMAGE_VADDR + TEXT_OFFSET + kaslr offset

而通过前面对kimage_vaddr的定义又可以知道:

kernel_run_address = kimage_vaddr + TEXT_OFFSET

因此可得:

kimage_vaddr + TEXT_OFFSET = KIMAGE_VADDR + TEXT_OFFSET + kaslr offset

最终推导:
kaslr offset = kimage_vaddr - KIMAGE_VADDR

内核中也是函数用于计算kaslr_offset值的:

static inline unsigned long kaslr_offset(void)
{
    return kimage_vaddr - KIMAGE_VADDR;
}

addr2line

当我们在进行debug时,必须先把内核中运行的地址转换为链接地址,然后才可以使用addr2line工具进行解析,因此第一步需要计算出kaslr offset:

kernel_run_address = kernel_link_address + kaslr_offset

利用上述关系,可以推导出kaslr_offset,后续在根据内核中对应的运行时的地址,反推出链接地址即可利用addr2line解析链接地址处的symbol。

symbol_link_address = symbol_run_address - kaslr_offset


参考:

http://www.wowotech.net/memory_management/441.html
http://www.wowotech.net/memory_management/436.html

你可能感兴趣的:(内核调试)