Linux Memory Cheat Sheet, containing useful Tools and Concepts about Linux Kernel memory management.

Linux Virtual Memory Map: Virtual Addresses ranges

As we can see from the /Documentation/x86/x86_64/mm.txt kernel memory map documentation the following virtual addresses regions are available:

It is interesting to see that the addresses in the range ffff880000000000-ffffc7ffffffffff directly map the physical ram for up to 64TB of data, in fact in the (volatility)volshell of a RAM dump belonging to an emulator with 1.5Gb of RAM, the last read that is allowed in such virtual address range is

The direct mapping area is direct with respect to RAM itself, it doesn’t maps directly to address ranges shown in /proc/iomem for example. If I do have two sections of RAM physical addresses shown in /proc/iomem, one starting at 0x1000 and ending at 0x 1fff, the other starting at 0x3000 and ending at 0x3fff; when I read byte 0xffff880000000000 from direct mapping zone I will read physical address 0x1000; when I read 0xffff880000002000, the physical address 0x3000 will be accessed.

The kernel text mapping range ffffffff80000000-ffffffffa0000000 points to the same physical addresses of the first 512MB of the direct mapping range

The kernel most used data structures such as task_struct structures of running processes will be allocated into the direct mapping area.

Is it possible to translate pointer values into physical addresses by hand?

If you are dealing with kernel memory pointers, with values in the direct mapping or the kernel text region (see above) you can obtain the physical address with simple arithmetic. You subtract the virtual address of the start of the memory region and you get an offset in the physical memory. If you have a virtual memory address, hence it belongs to the virtual memory region of the kernel memory or to the lower half of the address space, that belongs to user space, you have to use the page table of the process that this address belongs to.

/proc/iomem

This file contains the mappings of physical addresses to devices’ memory. I’m interested in the ones mapped to System RAM. We can see that my 16GB of ram are mapped in the following physical address ranges:

/boot/System.map and /proc/kallsyms Files

These two files are important for memory forensic because they contain the addresses of all the global variables and exported methods of the currently running kernel. These symbols have addresses in the kernel text virtual memory region.

Kernel Linear Mapping and Kernel Virtual Memory Accesses

Even if the kernel would have all the rights of directly accessing RAM, with physical addresses (Kernel can do whatever it wants with the system!), it is forced to use virtual addresses because paging is enabled by default, to support “normal” processes virtual memory. Paging is the procedure that traduces virtual addresses into physical addresses. The CPU is configured to use the page table to translate addresses whenever memory is accessed. Disabling paging on each kernel memory access doesn’t worth it.

Thus, given that paging is enabled, the kernel uses a work around to keep the translation easy, that is called Linear Mapping: all kernel virtual addresses are mapped 1:1 to physical addresses, and the translation simply involves a subtraction of an offset. Furthermore the Linux Kernel memory region is not swappable, this means that it will always be in RAM.

Linux Kernel phys_to_virt() and virt_to_phys() macros (arch/x86/include/asm/io.h)are used for Kernel Addresses translation. The names are evocative enough: the first translates physical to virtual addresses and the second vice versa.

I don’t really know why in the virtual to physical kernel memory translation there is more logic than a simple arithmetic operation, and why x > y isn’t arithmetically resolved in __START_KERNEL_map>0 ( if anyone knows or can point out useful pointers please comment below!).

Tools Cheat Sheet

Convert LiME RAM Dump into raw format (position N in file is position N in physical memory) with volatility:

volatility -f memory.dmp --profile=<dump-profile> imagecopy -O memory.raw

Commands within VolShell:

Print Kernel Call Stack for a symbol (p.e. vfs_read) of a given pid with bcc-tools

Software Engineer, passionate about Cybersecurity.