内存管理 – Linux内核API probe_kernel_read

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,会出现如图所示的结果。

Linux内核API probe_kernel_read

结果分析:

该测试程序中先获取用户空间的某一地址当作待拷贝的源地址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

以上是内存管理 – Linux内核API probe_kernel_read的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>