【问题标题】:copy_to_user failing with linux kernel page tablescopy_to_user 使用 linux 内核页表失败
【发布时间】:2015-12-04 20:57:22
【问题描述】:

我正在Linux内核中编写一个系统调用,它给出一个虚拟地址和一个无符号长指针,找到相应的页表条目,然后将其内容复制到无符号长指针中。这是系统调用:

SYSCALL_DEFINE2(readMMU, unsigned long, vaddr, unsigned long*, pte) {
    unsigned long* kernel_pte;
    unsigned char* page_table;
    struct task_struct *pid_task;
    pgd_t *pgd;
    pud_t *pud;
    pmd_t *pmd;
    pte_t *page_te;
    unsigned long n;


    kernel_pte = kmalloc(sizeof(unsigned long), GFP_KERNEL);

    if (copy_from_user(kernel_pte, pte, sizeof(unsigned long)) > 0) {
        printk("Error: copy from user returned more than 0\n");
        return -1;
    }

    //System call implementation in between here
    printk("Getting Task\n");

    pid_task = get_pid_task(find_get_pid(current->pid), PIDTYPE_PID);

    printk("Getting pgd\n");
    pgd = pgd_offset(pid_task->mm, vaddr);

    printk("Getting pud\n");
    pud = pud_offset(pgd, vaddr);

    printk("Getting pmd\n");
    pmd = pmd_offset(pud, vaddr);

    printk("Getting pte\n");
    page_te = pte_offset_kernel(pmd, vaddr);

    *kernel_pte = pte_val(*page_te);

    printk("Can we access pte?: %d\n", access_ok(VERIFY_WRITE, pte, sizeof(unsigned long)));
    printk("Can we acces kernel_pte?: %d\n", access_ok(VERIFY_READ, kernel_pte, sizeof(unsigned long)));

    if ((n = copy_to_user(pte, kernel_pte, sizeof pte)) > 0) {
        printk("Error: copy to user returned more than 0\n");
        printk("copy to user failed to copy this many bits: %ld\n", n);
        return -1;
    }

    kfree(kernel_pte);
    return 0;
}

这是调用系统调用的测试程序:

int
main (int argc, char ** argv) {
    unsigned long vaddr;
    unsigned long *pte;
    vaddr = (size_t) malloc(sizeof(unsigned long));



    /* Print a friendly message */
    printf ("Hello from User Space!\n");



    /* Call our new system call */
    syscall (181, vaddr, pte);

    /* Exit the program */
    return 0;
}

目前对 copy_to_user 的调用失败,返回值为 8,这意味着它没有将任何 kernel_pte 复制到 pte。我用 access_ok 检查了 pte 的 VERIFY_WRITE,它返回 1。但是,用 VERIFY_READ 在 kernel_pte 上调用的 acces_ok 返回 0。我不确定这是否是导致 copy_to_user 失败的原因,但查看 copy_to_user 的源代码看起来它只再次检查用户指针。所以我有点茫然为什么通话失败了。

【问题讨论】:

  • access_ok 只检查地址不是内核地址。为了 copy_to_user 成功,地址应该属于当前进程的地址空间。您需要检查用户空间程序,该程序将地址传递给系统调用。
  • 在我看来pte 的地址空间应该是正确的,因为它是从测试程序传递到系统调用的。
  • 你没有在测试程序中初始化pte。或者你应该声明它unsigned long 并将它的地址传递给系统调用,
  • 就是这样,谢谢!愚蠢的我忽略了这一点。

标签: c linux-kernel page-tables


【解决方案1】:

您没有在测试程序中初始化pte。或者你应该声明它unsigned long 并将它的地址传递给系统调用, ——Tsyvarev

【讨论】:

    猜你喜欢
    • 2018-09-01
    • 2020-07-15
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    相关资源
    最近更新 更多