如何在arm64中捕获对read_only页面的写入尝试

时间:2016-03-21 07:45:43

标签: c memory-management linux-kernel kernel-module arm64

我试图在以下代码的帮助下写入 RDONLY 页面:

#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/dma-mapping.h>
#include <linux/debugfs.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <linux/of.h>
#include <linux/of_platform.h>

#define SIZE sizeof(int)

// to print the pud/pmd/pte entries..
static void show_pte(struct mm_struct *mm, unsigned long addr)
{
    pgd_t *pgd;

    if (!mm)
            mm = &init_mm;

    pr_alert("pgd = %p\n", mm->pgd);
    pgd = pgd_offset(mm, addr);
    pr_alert("[%08lx] *pgd=%016llx", addr, pgd_val(*pgd));

    do {
            pud_t *pud;
            pmd_t *pmd;
            pte_t *pte;

            if (pgd_none(*pgd) || pgd_bad(*pgd))
                    break;

            pud = pud_offset(pgd, addr);
            printk(", *pud=%016llx", pud_val(*pud));
            if (pud_none(*pud) || pud_bad(*pud))
                    break;

            pmd = pmd_offset(pud, addr);
            printk(", *pmd=%016llx", pmd_val(*pmd));
            if (pmd_none(*pmd) || pmd_bad(*pmd))
                    break;

            pte = pte_offset_map(pmd, addr);
            printk(", *pte=%016llx", pte_val(*pte));
            pte_unmap(pte);
    } while(0);

    printk("\n");
}

static noinline void rodata_test(int *test_data)
{
    int result;
    unsigned long flag;

    pr_info("%s: attempting to write to read-only section:\n", __func__);

    printk(">>>>>> %x \n", *(volatile int *)test_data);
    if (*(volatile int *)test_data != 0xC3) {
           pr_err("read only data changed before test\n");
           return;
    }

        local_irq_save(flag);

    /*
* Attempt to write to test_data, trappint the expected
* data abort. If the trap executer, result will be 1. If it didn't,
* result will be oxFF.
*/

// This should trap the kernel panic
asm volatile(
    "0:     str     %[zero], [%[test_data]]\n"
    "       mov     %[result], #0xFF\n"
    "       b       2f\n"
    "1:     mov     %[result], #1\n"
    "2:\n"

    ".pushsection __ex_table,\"a\"\n"
    "       .quad 0b, 1b\n"
    ".popsection\n"

    : [result] "=r" (result)
    : [test_data] "r" (&test_data), [zero] "r" (0)
    : "memory"
);

local_irq_restore(flag);

    if (result == 1)
           pr_info("write to read-only section trapped, success\n");
    else
           pr_err("write to read-only section NOT trapped, test failed\n");

     //        if (*(volatile int *)test_data != 0xC3)
     //             pr_err("read only data changed during write\n");
}


static int pte_check_init(void)
{
    void *vaddr;
    unsigned long addr;
    pgd_t *pgd;
    pte_t pte, *ptep = NULL;

    //allocate a page
    vaddr = vmalloc(SIZE);
    if (!vaddr) {
            pr_err("vmalloc fail, size=%d", SIZE);
            return -ENOMEM;
    }

    *(int *)vaddr = 0xC3;
    printk("##### %x #####\n", *(int *)vaddr);
    addr = (unsigned long) vaddr;
    pgd = pgd_offset_k(addr);

    VIRTUAL_BUG_ON(!is_vmalloc_or_module_addr(vaddr));

    if (!pgd_none(*pgd)) {
            pud_t *pud = pud_offset(pgd, addr);
            if (!pud_none(*pud)) {
                    pmd_t *pmd = pmd_offset(pud, addr);
                    if (!pmd_none(*pmd)) {
                            ptep = pte_offset_map(pmd, addr);
                            pte = *ptep;
                    }
            }
    }

    // Mark Pte as read only this will set the 7th bit to 1
    pte_val(pte) |= PTE_RDONLY;
    //      pte_val(pte) &= ~PTE_WRITE;
    //      pte_val(pte) &= ~PTE_DIRTY;
    if (!ptep) {
            vfree(vaddr);
            return -EINVAL;
    }

    *ptep = pte;

    show_pte(&init_mm, vaddr);
    __flush_tlb_pgtable(&init_mm, vaddr);
    rodata_test((int *)vaddr);

    free_addr:
        vfree(vaddr);
    return 0;
}

void pte_check_exit(void)
{
}
module_init(pte_check_init);
module_exit(pte_check_exit);

根据这段代码,内核恐慌应该被捕获,变量结果应该有值1.但是我得到的结果值为0xFF。这意味着内核恐慌并未被困。

如何捕获此内核恐慌? 我在做错了什么?

**注意:**如果我用* test_data = X(X:某个值)替换陷阱函数,那么我面临内核恐慌。但是我想陷入这种恐慌,怎么办呢? 这澄清了PTE_RDONLY位设置为1的一件事。是否可能由于其他pte位这个陷阱不起作用?

0 个答案:

没有答案