首页 -> 安全研究
安全研究
绿盟月刊
绿盟安全月刊->第53期->安全文摘
作者:coolq
出处:http://www.linuxforum.net/forum/showflat.php?Cat=&Board=security&Number=
日期:2004-11-05
coolq
Redhat Fedora Core 2默认的内核,添加了对PAE模式的支持,所以物理地址变成了36位,对页的访问也需要经过三级页表。
另外一点重要的不同,是打上了 Ingo Molnar的4G/4G补丁,也就是说,内核的内存布局不是原来的3G用户/1G内核,
而是4G用户/4G内核,使用两个不同的页目录,因此用户态/内核态切换时需要修改CR3寄存器。
/*******************************************
* name: module hunter 2.6 ver 1.1 9.6.04 *
* (for RH FC2) *
* orig author: madsys *
* *
* rewrite: CoolQ *
* *
* usage: cat /proc/showmodules *
* *
******************************************/
#undef KBUILD_MODNAME
#define KBUILD_MODNAME mh26
#include <linux/config.h>
#ifdef CONFIG_SMP
#define __SMP__
#endif /* CONFIG_SMP */
#if CONFIG_MODVERSIONS == 1
#define MODVERSIONS
#endif /* CONFIG_MODVERSIONS */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/fixmap.h>
#include <asm/page.h>
#include <asm/types.h>
#include <asm/atomic_kmap.h>
#define STEPPING (PAGE_SIZE/32)
typedef enum RAM_MODE{
MODE_NORMAL_4K,
MODE_NORMAL_4M,
MODE_PAE_4K,
MODE_PAE_2M
}MODE;
static MODE mode;
static u32 cr3, cr4;
/*********************************************
* the following 4 funcs: *
* valid_addr_normal_4K,valid_addr_normal_4M *
* valid_addr_pae_4K, valid_addr_pae_2M *
* do the dirty job separately *
* return 1 for valid one *
* return 0 for invalid *
********************************************/
static int valid_addr_normal_4K(u32 address)
{
u32 pde, pte;
u32 cr3_tmp;
u32 pde_idx, pte_idx;
u32 addr;
if (!address)
return 0;
cr3_tmp = cr3 & 0xfffffe00;
pde_idx = address >> 22;
pte_idx = (address & 0xfffff000) >> 12;
pde = ((unsigned long *) __va(cr3_tmp))[pde_idx]; /* pde */
if (pde & 1){
addr = pde & 0xfffff000;
address &= 0x003ff000;
/* pte */
pte = ((unsigned long *) __va(addr))[pte_idx];
if (pte)
return 1;
else
return 0;
}else
return 0;
}
static int valid_addr_normal_4M(u32 address)
{
return 0;
}
static int valid_addr_pae_4K(u32 address)
{
u64 pdpte, pde, pte, addr;
u32 pdpte_idx, pde_idx, pte_idx;
u32 cr3_tmp;
if(!address)
return 0;
pdpte_idx = address >> 30;
pde_idx = (address & 0x3fe00000) >> 21;
pte_idx = (address & 0x1ff000) >> 12;
cr3_tmp = cr3 & 0xffffe0;
pdpte = ((u64*) __va(cr3_tmp))[pdpte_idx];
if(pdpte & 1){
addr = pdpte & 0xffffff000ULL;
pde = ((u64*) __va(addr))[pde_idx];
if(pde & 1){
addr = pde & 0xffffff000ULL;
pte = ((u64*) __va(addr))[pte_idx];
if(pte)
return 1;
else
return 0;
}else
return 0;
}else
return 0;
}
static int valid_addr_pae_2M(u32 address)
{
return 0;
}
/**************************************************
* FuncName: valid_addr *
* Usage: tell if an address is valid *
* i.e. does the address have the specific *
* page frame entry? *
* RetValue: *
* 1 - address valid *
* 0 - address invalid *
* Details: *
* the func will call another routine *
* according to mode(NORMAL/PAE/4K/4M/2M) *
*************************************************/
int valid_addr(u32 address)
{
switch(mode){
case MODE_NORMAL_4K:
return valid_addr_normal_4K(address);
break;
case MODE_NORMAL_4M:
return valid_addr_normal_4M(address);
break;
case MODE_PAE_4K:
return valid_addr_pae_4K(address);
break;
case MODE_PAE_2M:
return valid_addr_pae_2M(address);
break;
default:
return 0;
break;
}
}
ssize_t showmodule_read(struct file *unused_file, char *buffer, size_t len, loff_t*off)
{
struct module *p;
printk("\naddress name size"
" core_addr flags \n\n");
/* brute force all the possible vms */
for (p = (struct module *)VMALLOC_START;
p <= (struct module*)(VMALLOC_START + VMALLOC_RESERVE - PAGE_SIZE);
p = (struct module *)((u32)p + STEPPING)){
if (valid_addr((u32)p + (u32)&((struct module *)NULL)->name) )
/* the valid module struct should match some rules */
if (( (p->name[0]>=0x30 && p->name[0]<=0x39)
|| (p->name[0]> 0x41 && p->name[0]<=0x7a ))
&& (p->core_size < 1 <<20)
&& (p->core_size>= sizeof(struct module))
&& p->state <3
&& p->module_core > 0x02000000UL)
printk("0x%p%18s %6lu 0x%4p %3d\n",
p, p->name, p->core_size,
p->module_core, p->state);
}
return 0;
}
static struct file_operations showmodules_ops = {
read:showmodule_read,
};
int init_module(void)
{
struct proc_dir_entry *entry;
/* get cr3,cr4 registers and tell the VM mode */
__asm__ __volatile__ ( "movl %%cr3, %0" : "=r"(cr3) );
__asm__ __volatile__ ( "movl %%cr4, %0" : "=r"(cr4) );
if(cr4 & (1 << 5)){
u64 pdpte, pde;
pdpte = ((u64 *) __va(cr3))[0];
pde = ((u64 *) __va(pdpte))[0];
if(pde & (1 << 7))
mode = MODE_PAE_2M;
else
mode = MODE_PAE_4K;
}else{
u32 pde;
pde = ((u32 *) __va(cr3))[0];
if(pde & (1 << 7))
mode = MODE_NORMAL_4M;
else
mode = MODE_NORMAL_4K;
}
/* add an entry to /proc */
entry = create_proc_entry("showmodules", S_IRUSR, &proc_root);
entry->proc_fops = &showmodules_ops;
return 0;
}
void cleanup_module()
{
remove_proc_entry("showmodules", &proc_root);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("madsys madsys<at>ercist.iscas.ac.cn;qufuping<at>ercist.iscas.ac.cn");
coolq
init_module函数修改一下:
不知道为什么,CR3每次的内容都不一样(标准内核不一样,Redhat
FC2的就没有问题)。另外,FC2的默认内核,SMP的支持PAE,UP的是normal,不过两者都有4G的补
丁
int init_module(void)
{
struct proc_dir_entry *entry;
u32 addr;
/* get cr3,cr4 registers and tell the VM mode */
__asm__ __volatile__ ( "movl %%cr3, %0" : "=r"(cr3) );
__asm__ __volatile__ ( "movl %%cr4, %0" : "=r"(cr4) );
addr = &__this_module;
if(cr4 & (1 << 5)){
u64 pdpte, pde;
u32 pdpte_idx, pde_idx;
pdpte_idx = addr >> 30;
pde_idx = (addr & 0x3fffffff) >> 21;
pdpte = ((u64 *) __va(cr3))[pdpte_idx];
pde = ((u64 *) __va(pdpte))[pde_idx];
if(pde & (1 << 7))
mode = MODE_PAE_2M;
else
mode = MODE_PAE_4K;
}else{
u32 pde, pde_idx;
pde_idx = addr >> 22;
pde = ((u32 *) __va(cr3))[pde_idx];
if(pde & (1 << 7))
mode = MODE_NORMAL_4M;
else
mode = MODE_NORMAL_4K;
}
printk("cr3 = 0x%x\n", cr3);
/* add an entry to /proc */
printk("VM mode is %s\n", (mode == MODE_NORMAL_4K) ? "normal_4k" :
(mode == MODE_NORMAL_4M) ? "normal_4M" :
(mode == MODE_PAE_4K) ? "pae_4k" :
(mode == MODE_PAE_2M) ? "pae_2M" :
"unknown vm mode or error, better exit.");
entry = create_proc_entry("showmodules", S_IRUSR, &proc_root);
entry->proc_fops = &showmodules_ops;
return 0;
}
madsys
标准2.6kernel中,每个进程的页目录(地址)是不一样的,表现为每个进程的当前cr3不同. 这是在进程切换时改变的. 具体见:
schedule()->context_switch()->switch_mm()
不过,系统启动时(见paging_init),和重起时(见machine_real_restart),还是要设置成初试页目录地址的.
版权所有,未经许可,不得转载