pidからcr3レジスタの値を取得する

概要

Ubuntu 64bit において,あるプロセスのプロセス ID からそのプロセスの CR3 レジスタの値を取得するカーネルモジュールを作成する. x86 の Linux では,仮想メモリはプロセス毎に独立し,プロセス毎にページテーブルが用意されている. それぞれのプロセスにおけるページウォークは,そのプロセスに対応する pgd を起点として行われる. この時の pgd の物理アドレスが cr3 レジスタに格納されている. プロセスのコンテキストスイッチ時には,cr3 レジスタの値を切り替えることで,プロセスの仮想アドレス空間を切り替えることができる. cr3 レジスタの値は,pgd の物理アドレスであるので,プロセス ID のように一意の識別子になりうる.

実装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
uintptr_t pid_to_cr3(pid_t pid)
{
	struct pid *task_pid = find_vpid(pid);
	struct task_struct *task;

	if (!task_pid)
		return 0;

	task = pid_task(task_pid, PIDTYPE_PID);

	/* Ignore anonymous processes	*/
	if (!task->mm)
		return 0;

	if (task->active_mm == NULL)
		return 0;

	uintptr_t cr3 = __pa(task->active_mm->pgd);
	printk("cr3: %p\n", cr3);

	/* success */
	return cr3;
}

第一引数にユーザ空間におけるプロセス ID を受け取り,対応する task_struct 構造体を取得する. そして,task_struct 構造体から取得した pgd の値を物理アドレスに変換することで,cr3 レジスタの値を取得している.

参考

find_task_by_vpid を追ってみる - Linux の備忘録とか・・・(目次へ)
[Linux] Process ID (PID) から CR3 値を得る自作システムコール: 開発