Linux内核API probe_kernel_address

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

Linux内核API probe_kernel_address

结果分析:

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

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程