probe_kernel_address宏功能描述:probe_kernel_address( )宏安全地尝试将地址addr中的内容读入变量retval中。
probe_kernel_address文件包含
#include<linux/uaccess.h>
probe_kernel_address宏定义
在内核源码中的位置:linux-3.19.3/include/linux/uaccess.h
宏定义格式:
#define probe_kernel_address(addr, retval) \
({ \
long ret; \
mm_segment_t old_fs = get_fs( ); \
set_fs(KERNEL_DS); \
pagefault_disable( ); \
ret = __copy_from_user_inatomic(&(retval), (__force typeof(retval)
__user *)(addr), sizeof(retval)); \
pagefault_enable( ); \
set_fs(old_fs); \
ret; \
})
probe_kernel_address输入参数说明
addr
:是源地址,数据从该地址读入变量retval中,它的类型与变量retval的类型一致。retval
:接收从地址单元addr读出的数据。
probe_kernel_address返回值说明:
- 该宏返回一个长整型:
- 如果操作成功,函数返回0,即该长整型值为0。
- 如果操作失败(或发生内核错误),函数返回-EFAULT,其值为-14。
probe_kernel_address实例解析
编写测试文件:probe_kernel_address.c
头文件及全局变量声明如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/security.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
static int __init probe_kernel_address_init(void);
static void __exit probe_kernel_address_exit(void);
模块初始化函数:
int __init probe_kernel_address_init(void)
{
struct mm_struct *mm = current->mm; //mm指向当前进程的地址空间
unsigned long mm_start = mm->mmap->vm_start; //mm_start为当前进程空间首地址
unsigned long * addr = NULL;
addr = (unsigned long *)mm_start; //强制类型转化mm_start赋值给addr
printk("mm_start=0x%lx\n", mm_start);
printk("*addr = %lx\n", *addr);
long retval = 0;
long ret = probe_kernel_address(addr, retval); //将addr所指的内容读到retval中
printk("retval = %ld\n", ret);
printk("after probe_kernel_read, retval = %lx\n", retval);
return 0;
}
模块退出函数:
void __exit probe_kernel_address_exit(void)
{
printk("exit! \n");
}
模块初始化及退出函数调用:
module_init(probe_kernel_address_init);
module_exit(probe_kernel_address_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod probe_kernel_address.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
结果分析:
该测试程序中首先获取用户空间的某一地址当作为实参赋值给addr,这里取当前进程首地址,由输出结果可知为0x7f56ab853000,输出其内容为*addr = 0x10102464c457f。然后定义变量long retval = 0,将它作为接收数据块的参数,再调用宏probe_kernel_address( )以实现将地址addr的内容读入到变量retval中,由输出结果retval = 0x10102464c457f可知它正确接收地址单元addr开始的内容。