probe_kernel_read函数功能描述:probe_kernel_read( )函数通过函数__probe_kernel_read( )安全地尝试将用户空间地址src开始的大小为size的数据块拷贝到内核空间地址dst开始的目标地址空间中。
probe_kernel_read文件包含
#include<linux/uaccess.h>
probe_kernel_read函数定义
在内核源码中的位置:linux-3.19.3/mm/maccess.c
函数定义格式:
long __weak probe_kernel_read(void *dst, const void *src, size_t size)
__attribute__((alias(“__probe_kernel_read”)));
probe_kernel_read输入参数说明
src
:指源起始地址,它指向某一用户空间的地址。dst
:指目标起始地址,它指向某一内核空间的地址。size
:指从src到dst要拷贝的数据块大小,它以字节为单位。
probe_kernel_read返回值说明
- 该函数返回一个长整型:如果操作成功,函数返回0,即该长整型值为0;如果操作失败(或发生内核错误),函数返回-EFAULT,其值为-14。
probe_kernel_read实例解析
编写测试文件:probe_kernel_read.c
头文件及全局变量声明如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/security.h>
#include <linux/uaccess.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
static int __init probe_kernel_read_init(void);
static void __exit probe_kernel_read_exit(void);
模块初始化函数:
int __init probe_kernel_read_init(void)
{
struct mm_struct *mm = current->mm; //mm指向当前进程的地址空间
unsigned long mm_start = mm->mmap->vm_start; //mm_start指当前进程地址空间的起始地址
unsigned long * src = NULL;
src = (unsigned long *)mm_start; //将源地址设置为用户空间的起始地址
printk("mm_start = 0x%lx\n", mm_start);
printk("*src = %lx\n", *src);
unsigned long * dst = NULL;
dst = (unsigned long *)kmalloc(sizeof(unsigned long), GFP_KERNEL);
// 目标地址为内核空间的地址
*dst = 5;
printk("*dst = %ld\n", *dst);
long ret = probe_kernel_read(dst, src, sizeof(unsigned long));
// 调用函数实现源地址到目标地址内容的拷贝
printk("ret = %ld\n", ret);
printk("after probe_kernel_read, *dst = %lx\n", *dst);
kfree(dst);
return 0;
}
模块退出函数:
void __exit probe_kernel_read_exit(void)
{
printk("exit! \n");
}
模块初始化及退出函数调用:
module_init(probe_kernel_read_init);
module_exit(probe_kernel_read_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod probe_kernel_read.ko插入模块,然后执行命令dmesg-c,会出现如图所示的结果。
结果分析:
该测试程序中先获取用户空间的某一地址当作待拷贝的源地址src,这里取当前进程首地址,由输出结果可知为0x7fa3dc336000,输出其内容为*src = 0x10102464c457f
。然后开辟一个内核地址dst,将该地址开始的一个字节内容设置为5(*dst=5)
。为了使程序简单,测试时令参数size=sizeof(unsigned long)
,即拷贝一定字节内容,调用函数probe_kernel_read(dst, src, sizeof(unsigned long))
,由输出结果可知返回值ret = 0(即拷贝成功),并且*dst =0x10102464c457f = *src
。