- 論壇徽章:
- 0
|
看到Godbach大神在博客上的《 Linux內(nèi)核NULL指針引發(fā)的BUG》文章,由于剛學(xué)了一點內(nèi)核皮毛,便想嘗試一下,結(jié)果出了一點問題,希望能夠得到大家的幫助。下面是我的嘗試與出現(xiàn)的問題:
1、先編寫一個簡單的字符設(shè)備驅(qū)動chr_dev.c,如下所示
static struct cdev chr_dev;
static dev_t ndev;
static int chr_open(struct inode *nd, struct file *filp)
{
int major = MAJOR(nd->i_rdev);
int minor = MINOR(nd->i_rdev);
printk("chr_open, major=%d, minor=%d\n", major, minor);
return 0;
}
static ssize_t chr_read(struct file *f, char __user *u, size_t sz, loff_t *off)
{
printk("kernel NULL pointer:%x", *(unsigned char *)0);
printk("kernel NULL pointer:%x", *(unsigned char *)1);
printk("kernel NULL pointer:%x", *(unsigned long *)2);
void (*p)();
p = NULL;
(*p)(); //在這里解引用空指針
return 0;
}
struct file_operations chr_ops=
{
.owner = THIS_MODULE,
.open = chr_open,
.read = chr_read,
};
static int demo_init(void)
{
int ret;
cdev_init(&chr_dev, &chr_ops);
ret = alloc_chrdev_region(&ndev, 0, 1, "chr_dev");
if(ret < 0)
return ret;
printk("demo_init():major=%d, minor=%d\n", MAJOR(ndev), MINOR(ndev));
ret = cdev_add(&chr_dev, ndev, 1);
if(ret < 0)
return ret;
return 0;
}
static void demo_exit(void)
{
printk("Removing chr_dev module...\n");
cdev_del(&chr_dev);
unregister_chrdev_region(ndev, 1);
}
module_init(demo_init);
module_exit(demo_exit);
2、然后仿照寫了一個testhole.c文件,用于映射0地址并指向null_func函數(shù),另外觸發(fā)調(diào)用字符驅(qū)動,如下所示:
#define BUFFSIZE 1024
void null_func(void)
{
printf("aaaaaaaaaaaaaaaaaaaaaaa\n");
}
void test_chrdev()
{
int fd;
int n;
char buf[BUFFSIZE];
fd = open("/dev/chr_dev", O_RDONLY);
if(fd == -1)
{
perror("open error");
exit(-1);
}
while((n = read(fd, buf, BUFFSIZE)) < 0)
{
perror("read error");
exit(-1);
}
close(fd);
}
void map_and_call_null()
{
char *addr;
if((personality(MMAP_PAGE_ZERO)) != -1)
{
if((addr = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, 0, 0)) == MAP_FAILED)
{
perror("mmap");
return;
}
}
else
{
perror("personality error");
return;
}
*(unsigned char *)0 = '\x90';
*(unsigned char *)1 = '\xe9';
*(unsigned long *)2 = (unsigned long)&null_func - 6;
printf("%x", *(unsigned long *)2);
//void (*aaa)();
//aaa = NULL;
//(*aaa)();
test_chrdev();
}
int main()
{
map_and_call_null();
return 0;
}
3、出現(xiàn)的問題
運行testhole程序后,驅(qū)動程序并沒有調(diào)用到null_func函數(shù),而是產(chǎn)生了BUG: unable to handle kernel NULL pointer dereference at (null)問題,我在驅(qū)動程序的chr_read中打印出地址0,1,2中的值,發(fā)現(xiàn)與map_and_call_null函數(shù)中賦予的值是一樣的,為什么會出現(xiàn)這樣的問題呢?我自己的猜想是不是內(nèi)核態(tài)不能直接執(zhí)行用戶態(tài)的函數(shù)?希望大家不吝賜教。。 |
|