我试图在以下代码的帮助下写入 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位这个陷阱不起作用?