0

Linux カーネルで、仮想アドレスと符号なし long ポインターを指定して、対応するページ テーブル エントリを見つけ、その内容を符号なし long ポインターにコピーするシステム コールを作成しています。システムコールは次のとおりです。

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 への呼び出しは、kernel_pte を pte にコピーしていないことを意味する 8 の戻り値で失敗しています。VERIFY_WRITE の access_ok で pte をチェックしたところ、1 が返されました。ただし、kernel_pte で VERIFY_READ を使用して acces_ok を呼び出したところ、0 が返されました。ユーザーポインターを再度チェックするだけのようです。そのため、通話が失敗する理由が少しわかりません。

4

1 に答える 1