You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux内核态直接写入用户内存失败问题排查与解决

问题原因分析
  1. stdio缓冲区的误导:你在用户态使用的fwrite是C标准库的带缓冲IO函数。调用fwrite时,数据不会直接传递给内核的proc write回调,而是先写入stdio库维护的用户态临时缓冲区。内核回调中拿到的ubuf是这个临时缓冲区的地址,而非你用posix_memalign分配的buffer。因此你在内核中修改的是临时缓冲区,而非目标内存,用户态的buffer自然不会有变化。

  2. 内核代码的潜在健壮性问题:你的内核代码未检查pin_user_pages的返回值,若该调用失败(如用户态地址非法),后续操作会触发崩溃;另外,现代内核中更推荐用kmap_local_page替代kmap(无全局锁,更安全),不过这不是当前问题的核心。

解决方法

1. 用户态绕过stdio缓冲区,直接使用系统调用

将用户态的fwrite替换为write系统调用,这样内核拿到的ubuf就是你自己分配的buffer地址:

char *buffer;
const size_t PAGE_SIZE = getpagesize();
posix_memalign(&buffer,PAGE_SIZE,PAGE_SIZE);
*buffer = 89;
    
int fd = open("/proc/dt/alloc", O_WRONLY);
write(fd, buffer, 100);
close(fd);

2. 修复内核代码的健壮性(可选但推荐)

添加错误检查,并使用更安全的kmap_local_page:

static ssize_t write_proc_alloc(struct file *file, const char __user *ubuf, size_t count, loff_t *data)
{
    struct page *pages[1];
    int ret;

    mmap_read_lock(current->mm);
    ret = pin_user_pages((unsigned long)ubuf, 1, FOLL_WRITE, pages, NULL);
    if (ret != 1) {
        mmap_read_unlock(current->mm);
        return -EFAULT;
    }

    char *buf = kmap_local_page(pages[0]);
    *buf = 123;
    kunmap_local(buf);

    set_page_dirty(pages[0]);
    unpin_user_pages(pages, 1);
    mmap_read_unlock(current->mm);

    return count; // 需返回正确的写入字节数
}

关键说明

  • 直接修改用户态内存的前提是:内核拿到的ubuf确实是目标进程的有效用户态地址,write系统调用能保证这一点(直接传递用户缓冲区地址给内核)。
  • FOLL_WRITE标志确保页面被标记为可写,set_page_dirty确保修改被刷回用户态(多数情况下内核会自动处理脏页回写,但显式标记更稳妥)。

内容的提问来源于stack exchange,提问作者Segmented

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 12:07:13