首页
社区
课程
招聘
[原创]Linux高端内存映射之kmap持久内核映射
发表于: 2019-5-20 16:10 8960

[原创]Linux高端内存映射之kmap持久内核映射

2019-5-20 16:10
8960

一、高端内存由来

在i386体系结构中,高于896MB的物理内存被划分为高端内存,这部分物理内存并不是永久性的映射到内核地址空间,而是根据内核的需求取合适大小的内存临时映射到内核地址空间。这里需要先澄清两个概念:

  • 页框:物理内存划分为4096字节的等份,每一等份称作“页框”。
  • 内核地址空间:段内偏移和段基址经过分段机构合成线性地址,i386体系中线性地址空间为4GB,其中0~3GB为用户地址空间,只能访问被标记为“用户”的页框,3~4GB为内核地址空间,可以访问所有页框。

如果物理内存超过1GB,那么内核地址空间是无法访问到所有内存的。为了解决这个问题,物理内存的0~896MB映射到内核地址空间0xc0000000~0xf8000000(3GB~3GB+896MB)。物理内存中超过896MB的部分则根据内核的需要,临时映射到内核地址空间剩下的128MB中。

二、内核地址映射

          3GB~4GB内核地址空间的分配如下:

  • 直接映射区
         3GB~3GB+896MB之间的内核空间直接映射到物理内存0~896MB,与物理地址的转换关系是:va=pa + 0xc0000000。

  • 动态内存映射区
         由内核函数vmalloc分配,内核地址连续,但物理地址不一定连续,可能处于高端内存,也可能处于内存低端。

  • 永久内存映射区
         内核建立由高端内存页框到内核地址空间的长期映射。

  • 固定映射区
         留作特定用途。

三、相关变量和数据结构

  • page数据结构

页描述符,记录每个页框当前的状态,例如区分页框是属于内核还是用户进程,页框是否空闲。这些都保存在page类型的描述符中,所有描述符都保存在mem_map数组中。

  • page_address_htable

散列表,用于建立高端内存页框与永久内核映射包含的线性地址之间的联系,由线性地址查找是否已有页框与之建立映射的时候可以提高查找速度。

  • page_address_map

page_address_htable包含的数据结构,用于为高端内存中每一个页框进行当前映射,包含一个指向页描述符的指针和分配给该页框的线性地址。

struct page_address_map {
	struct page *page;
	void *virtual;
	struct list_head list;
};

  • pkmap_page_table 

指向永久内核映射的专用页表。该页表包含在普通页表中,需要在初始化过程中计算其具体地址,再由pkmap_page_table指向,由此可以快速引用。
void __init permanent_kmaps_init(pgd_t *pgd_base)		//持久内核映射,参数是cr3寄存器的值
{
	pgd_t *pgd;					//全局页目录
	pud_t *pud;					//上层页目录
	pmd_t *pmd;					//中间页目录
	pte_t *pte;					//页目录
	unsigned long vaddr;

	vaddr = PKMAP_BASE;			//持久映射地址基址(虚拟地址)
	page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);//设置PKMAP_BASE~PKMAP_BASE+4MB线性地址段的页表

	pgd = swapper_pg_dir + pgd_index(vaddr);		//页全局目录地址
	pud = pud_offset(pgd, vaddr);
	pmd = pmd_offset(pud, vaddr);
	pte = pte_offset_kernel(pmd, vaddr);
	pkmap_page_table = pte;		//指向页表中pkmbase开始的地方,这个部分是所有内核页表共享的部分
}

  • LAST_PKMAP

高端内存页框的数量。未开启PAE时为1024,开启PAE后为512。

  • PKMAP_BASE

持久内核映射的起始地址。

  • pkmap_count

计数器数组,包含LAST_PKMAP个项,描述对应页表项的使用情况。

值为0,对应页表项没有映射任何高端内存页框,可以使用;

值为1,对应页表项没有映射任何高端内存页框,但它不能使用,因为自其最后一次使用以来,其相应的TLB还未刷新;

值为n(大于1),对应的页表项映射一个高端内存页框,并且有n-1个内核成分正在使用它。


四、kmap调用路径

持久内核映射通常使用alloc_page函数获得可用页框,然后将指向页框描述符的指针传递给kmap函数建立到内核地址空间的持久映射。需要注意是的kmap可能会导致进程挂起,当可用于持久映射的4MB地址空间被使用完的时候就需要挂起进程,直到其他进程解除其中的一个地址映射关系。所以kmap不能被用于中断处理程序和软中断函数。
经过一番研究,我将kmap的运行流程整理了出来,内核版本是Linux2.6.11



[课程]Linux pwn 探索篇!

最后于 2019-5-20 16:20 被极目楚天舒编辑 ,原因:
上传的附件:
收藏
免费 6
支持
分享
最新回复 (3)
雪    币: 154
活跃值: (216)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
2019-5-20 21:16
0
雪    币: 5883
活跃值: (12394)
能力值: ( LV12,RANK:312 )
在线值:
发帖
回帖
粉丝
3
很可以 make 多挖几个kernelattack
2019-6-10 09:14
0
雪    币: 171
活跃值: (509)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
工作状态保持这种学习进度,还是牛逼啊~~
2019-12-6 19:49
0
游客
登录 | 注册 方可回帖
返回
//