kernel_pwn中uffd机制的利用

kernel_pwn中uffd机制的利用

如何利用 Linux 的 userfaultfd 机制,在用户空间处理缺页异常(page fault)。


1. 整体概述

代码主要流程如下:

  1. 内存映射
    main() 中使用 mmap 分配了 2 页内存(每页 4KB)。
  2. 注册 userfaultfd
    调用 register_uffd() 将映射区域注册到 userfaultfd,使得对这些区域的访问触发缺页异常。
  3. 缺页处理线程
    启动一个专门处理缺页事件的线程(fault_handler_thread),该线程通过 poll()read() 捕获缺页事件,然后利用 UFFDIO_COPY 将预先准备的数据填充到缺页区域。
  4. 触发缺页
    main() 中通过读取映射内存触发缺页事件,最终观察到填充的数据。

2. main() 函数解析

int main() {
   
    void *page;
    page = mmap(NULL, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (page == MAP_FAILED)
        fatal("mmap");

    printf("[+] mmap two pages at 0x%llx\n", (long long unsigned int)page);
    register_uffd(page, 0x2000);

    char buf[0x100];
    puts("[*] reading from page#1");
    strcpy(buf, (char *)(page));
    printf("[+] 0x0000: %s\n", buf);
    puts("[*] reading from page#2");
    strcpy(buf, (char *)(page + 0x1000));
    printf("[+] 0x1000: %s\n", buf);
    puts("[*] reading from page#1");
    strcpy(buf, (char *)(page));
    printf("[+] 0x0000: %s\n", buf);
    puts("[*] reading from page#2");
    strcpy(buf, (char *)(page + 0x1000));
    printf("[+] 0x1000: %s\n", buf);

    getchar();
    return 0;
}

主要步骤

  • 内存映射
    使用 mmap 分配了 0x2000 字节(2 页)的内存,设置了读写权限。映射类型为匿名且私有。
  • 打印映射地址
    打印分配内存的起始地址,便于调试。
  • 注册 userfaultfd
    调用 register_uffd(page, 0x2000) 将分配的 2 页内存区域注册到 userfaultfd。
  • 触发缺页
    通过对映射区域内存的读取(使用 strcpy 拷贝数据到缓冲区),第一次访问将触发缺页异常。代码中读取两次每个页面,借此观察缺页处理线程的填充行为(根据缺页次数返回不同的字符串)。
  • 暂停程序
    使用 getchar() 阻塞程序退出,以便观察程序运行过程中的输出。

3. register_uffd() 函数解析

int register_uffd(void *addr, size_t len) {
   
    struct uffdio_api uffdio_api;
    struct uffdio_register uffdio_register;
    long uffd;
    pthread_t th;

    puts("[*] registering userfaultfd");

    uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
    if (uffd == -1)
        fatal("userfaultfd");

    uffdio_api.api = UFFD_API;
    uffdio_api.features = 0;
    if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
        fatal("ioctl(UFFDIO_API)");

    uffdio_register.range.start = (unsigned long)addr;
    uffdio_register.range.len = len;
    uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值