Linux内核 probe_kernel_address()

宏:probe_kernel_address( )

文件包含:

#include<linux/uaccess.h>

宏定义:

在内核源码中的位置: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中。

输入参数说明:

  • addr:是源地址,数据从该地址读入变量retval中,它的类型与变量retval的类型一致。

  • retval:接收从地址单元addr读出的数据。

返回值说明:

  • 该宏返回一个长整型:

  • 如果操作成功,函数返回0,即该长整型值为0。

  • 如果操作失败(或发生内核错误),函数返回-EFAULT,其值为-14。

实例解析:

编写测试文件: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,会出现如图所示的结果。

Linux内核 probe_kernel_address()

结果分析:

该测试程序中首先获取用户空间的某一地址当作为实参赋值给addr,这里取当前进程首地址,由输出结果可知为0x7f56ab853000,输出其内容为*addr = 0x10102464c457f。然后定义变量long retval = 0,将它作为接收数据块的参数,再调用宏probe_kernel_address( )以实现将地址addr的内容读入到变量retval中,由输出结果retval = 0x10102464c457f可知它正确接收地址单元addr开始的内容。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!