Dumping page table entries of a process in Linux
I think /proc/pid/pagemap
and /proc/pid/maps
contain this info, but I am not aware of any tool dumping them in a more meaningful format.
You can always write it yourself using the kernel doc:
http://www.kernel.org/doc/Documentation/vm/pagemap.txt
Page Table Walk in Linux
I fixed the problem thanks to TonyTannous. The page table entry doesn't contain just the physical address, but also some other bits used for access rights and the like. The physical address can be obtained by masking it with PTE_PFN_MASK
:
addr = ptep->pte & PTE_PFN_MASK
I can then dereference it with __va
.
Override a page table entry with another on a x64 Ubuntu 14.04
I am writing this answer hoping that this will prove useful for someone in the future.
I have managed to modify the page tables for the virtual addresses of two variables foo and bar so the mm will see them as residing in the same physical page.
The code that does this is below:
#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();
This may not be as robust as what @GilHamilton had in mind, but this got the job done for me.
I hope this will prove to be useful!
Eduard
Related Topics
Shifting from Windows to *Nix Programming Platform
Using Perf to Monitor Raw Event Counters
Grep String Inside Double Quotes
Export Variables Defined in Another File
Merge/Join Two Tables Fast Linux Command Line
How to Use Watir to Scrape Data from a Website on a Linux Server Without Monitor
I Cannot Get a Result from a Single Line Put into the Erlang Shell
How to Check If a Files Exists in a Specific Directory in a Bash Script
How to Detect a Buffer Over Run on Serial Port in Linux Using C++
File Size in Human Readable Format
How to Grep Exact Literal String (No Regex)
How to Calculate the Total Size of Certain Files Only, Recursive, in Linux
Git - Windows and Linux Line-Endings
Can't Install Freetds via Yum Package Manager