在 x64 Ubuntu 14.04 上用另一个页面覆盖 table 条目
Override a page table entry with another on a x64 Ubuntu 14.04
我制作了一个内核模块,它获取两个变量的虚拟地址,将它们命名为 foo 和 bar,然后遍历第 table 页到它们的物理地址。
我想修改 foo 的页面 table 条目,使其与 的页面 table 条目相同]bar,从而使foo和bar在同一个页面框架中。你能帮我实现这个吗?
下面是我写的遍历页面tables的代码。
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *ptep, pte;
pgd = pgd_offset(mm, address);
if (pgd_none(*pgd) || pgd_bad(*pgd))
return -EINVAL;
pud = pud_offset(pgd, address);
if (pud_none(*pud) || pud_bad(*pud))
return -EINVAL;
pmd = pmd_offset(pud, address);
if (pmd_none(*pmd) || pmd_bad(*pmd))
return -EINVAL;
ptep = pte_offset(pmd, address);
if (!ptep)
return -EINVAL;
pte = *ptep;
我确定我需要刷新 TLB 并可能修改一些标志以实现我想要的,但我缺乏所需的知识。
非常感谢任何帮助!
我正在写这个答案,希望这对将来的人有用。
我已经设法修改了两个变量 foo 和 bar 的虚拟地址的页表,因此 mm 会将它们视为驻留在同一物理页面中。
执行此操作的代码如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/thread_info.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/tlbflush.h>
#include <asm/page.h>
#include <asm/pgtable.h>
pgd_t *foo_pgd, *bar_pgd;
pud_t *foo_pud, *bar_pud;
pmd_t *foo_pmd, *bar_pmd;
pte_t *foo_ptep, *bar_ptep, foo_pte, bar_pte;
/* We will step through the page tables until we reach the
* PTE for both foo and bar */
/* Get PGD */
foo_pgd = pgd_offset(current->mm, foo_address);
if (pgd_none(*foo_pgd) || pgd_bad(*foo_pgd))
return -EINVAL;
bar_pgd = pgd_offset(current->mm, bar_address);
if (pgd_none(*bar_pgd) || pgd_bad(*bar_pgd))
return -EINVAL;
/* Get PUD */
foo_pud = pud_offset(foo_pgd, foo_address);
if (pud_none(*foo_pud) || pud_bad(*foo_pud))
return -EINVAL;
bar_pud = pud_offset(bar_pgd, bar_address);
if (pud_none(*bar_pud) || pud_bad(*bar_pud))
return -EINVAL;
/* Get PMD */
foo_pmd = pmd_offset(foo_pud, foo_address);
if (pmd_none(*foo_pmd) || pmd_bad(*foo_pmd))
return -EINVAL;
bar_pmd = pmd_offset(bar_pud, bar_address);
if (pmd_none(*bar_pmd) || pmd_bad(*bar_pmd))
return -EINVAL;
/* Get PTE */
spin_lock(current->mm->page_table_lock);
foo_ptep = pte_offset_map(foo_pmd, foo_address);
if (!pte_present(*foo_ptep))
return -EINVAL;
bar_ptep = pte_offset_map(bar_pmd, bar_address);
if (!pte_present(*bar_ptep))
return -EINVAL;
/* Trick foo into thinking he resides in the same page as bar */
*foo_ptep = *bar_ptep;
spin_unlock(current->mm->page_table_lock);
/* We need to flush the tlb afterwards */
__native_flush_tlb();
这可能不像@GilHamilton 所想的那样稳健,但这帮我完成了工作。
我希望这会被证明是有用的!
爱德华
我制作了一个内核模块,它获取两个变量的虚拟地址,将它们命名为 foo 和 bar,然后遍历第 table 页到它们的物理地址。
我想修改 foo 的页面 table 条目,使其与 的页面 table 条目相同]bar,从而使foo和bar在同一个页面框架中。你能帮我实现这个吗?
下面是我写的遍历页面tables的代码。
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *ptep, pte;
pgd = pgd_offset(mm, address);
if (pgd_none(*pgd) || pgd_bad(*pgd))
return -EINVAL;
pud = pud_offset(pgd, address);
if (pud_none(*pud) || pud_bad(*pud))
return -EINVAL;
pmd = pmd_offset(pud, address);
if (pmd_none(*pmd) || pmd_bad(*pmd))
return -EINVAL;
ptep = pte_offset(pmd, address);
if (!ptep)
return -EINVAL;
pte = *ptep;
我确定我需要刷新 TLB 并可能修改一些标志以实现我想要的,但我缺乏所需的知识。
非常感谢任何帮助!
我正在写这个答案,希望这对将来的人有用。
我已经设法修改了两个变量 foo 和 bar 的虚拟地址的页表,因此 mm 会将它们视为驻留在同一物理页面中。
执行此操作的代码如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/thread_info.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/tlbflush.h>
#include <asm/page.h>
#include <asm/pgtable.h>
pgd_t *foo_pgd, *bar_pgd;
pud_t *foo_pud, *bar_pud;
pmd_t *foo_pmd, *bar_pmd;
pte_t *foo_ptep, *bar_ptep, foo_pte, bar_pte;
/* We will step through the page tables until we reach the
* PTE for both foo and bar */
/* Get PGD */
foo_pgd = pgd_offset(current->mm, foo_address);
if (pgd_none(*foo_pgd) || pgd_bad(*foo_pgd))
return -EINVAL;
bar_pgd = pgd_offset(current->mm, bar_address);
if (pgd_none(*bar_pgd) || pgd_bad(*bar_pgd))
return -EINVAL;
/* Get PUD */
foo_pud = pud_offset(foo_pgd, foo_address);
if (pud_none(*foo_pud) || pud_bad(*foo_pud))
return -EINVAL;
bar_pud = pud_offset(bar_pgd, bar_address);
if (pud_none(*bar_pud) || pud_bad(*bar_pud))
return -EINVAL;
/* Get PMD */
foo_pmd = pmd_offset(foo_pud, foo_address);
if (pmd_none(*foo_pmd) || pmd_bad(*foo_pmd))
return -EINVAL;
bar_pmd = pmd_offset(bar_pud, bar_address);
if (pmd_none(*bar_pmd) || pmd_bad(*bar_pmd))
return -EINVAL;
/* Get PTE */
spin_lock(current->mm->page_table_lock);
foo_ptep = pte_offset_map(foo_pmd, foo_address);
if (!pte_present(*foo_ptep))
return -EINVAL;
bar_ptep = pte_offset_map(bar_pmd, bar_address);
if (!pte_present(*bar_ptep))
return -EINVAL;
/* Trick foo into thinking he resides in the same page as bar */
*foo_ptep = *bar_ptep;
spin_unlock(current->mm->page_table_lock);
/* We need to flush the tlb afterwards */
__native_flush_tlb();
这可能不像@GilHamilton 所想的那样稳健,但这帮我完成了工作。
我希望这会被证明是有用的!
爱德华