Linux access kernel memory

How to access user space memory from the Linux kernel?

I know that copy_to_user / copy_from_user , get_user / put_user functions are for this purpose. My question is that, given a user space address/pointer, how can I access the data pointed to by the address from the kernel in general? I can imagine that first I have to make sure the containing page should be in physical memory (instead of in disk). What is the next step? Can I use *p , where p is the pointer pointing to some user space data, directly to refer to the data? Or do I have to first invoke kmap to map the containing physical page frame to the kernel virtual address space? Why?

4 Answers 4

  • Depending on which architecture your driver is running on, and how the kernel was configured, the user-space pointer may not be valid while running in kernel mode at all. There may be no mapping for that address, or it could point to some other, random data.
  • Even if the pointer does mean the same thing in kernel space, user-space memory is paged, and the memory in question might not be resident in RAM when the system call is made. Attempting to reference the user-space memory directly could generate a page fault, which is something that kernel code is not allowed to do. The result would be an «oops,» which would result in the death of the process that made the system call.
  • The pointer in question has been supplied by a user program, which could be buggy or malicious. If your driver ever blindly dereferences a user-supplied pointer, it provides an open doorway allowing a user-space program to access or overwrite memory anywhere in the system. If you do not wish to be responsible for compromising the security of your users’ systems, you cannot ever dereference a user-space pointer directly.

That said, I am myself curious to know what happens if the user-space address is indeed valid, and none of the above conditions apply.

The pointer alone is not enough! You need to know which process that pointer «belongs» to.

When the process gets preempted, the pointer points into the address space of another process. The address may not be mapped any more, yadda yadda,

If that process will be the current process when you access the data, then you should use the copy_to_user/copy_from_user functions.

If the process may be scheduled out, you can try to mlock() the page in RAM and find out which is the physical ram address of the page. Whenever you want to access it, you map that physical page into a kernel virtual address.

  • A malicious process can munlock() the page and trick you into accessing a wrong RAM page.
  • I’m not sure mlock() semantics demand the underlining RAM page MUSTN’T change.
  • the kernel should be able to lock a page into RAM, I’m not familiar with the mm subsystem.
Читайте также:  Steam wallpaper engine linux

Источник

How to access physical addresses from user space in Linux?

On a ARM based system running Linux, I have a device that’s memory mapped to a physical address. From a user space program where all addresses are virtual, how can I read content from this address?

2 Answers 2

busybox devmem

busybox devmem is a tiny CLI utility that mmaps /dev/mem .

You can get it in Ubuntu with: sudo apt-get install busybox

Usage: read 4 bytes from the physical address 0x12345678 :

sudo busybox devmem 0x12345678 

Write 0x9abcdef0 to that address:

sudo busybox devmem 0x12345678 w 0x9abcdef0 

mmap MAP_SHARED

When mmapping /dev/mem , you likely want to use:

open("/dev/mem", O_RDWR | O_SYNC); mmap(. PROT_READ | PROT_WRITE, MAP_SHARED, . ) 

MAP_SHARED makes writes go to physical memory immediately, which makes it easier to observe, and makes more sense for hardware register writes.

CONFIG_STRICT_DEVMEM and nopat

To use /dev/mem to view and modify regular RAM on kernel v4.9, you must fist:

  • disable CONFIG_STRICT_DEVMEM (set by default on Ubuntu 17.04)
  • pass the nopat kernel command line option for x86

IO ports still work without those.

Cache flushing

If you try to write to RAM instead of a register, the memory may be cached by the CPU: How to flush the CPU cache for a region of address space in Linux? and I don’t see a very portable / easy way to flush it or mark the region as uncacheable:

So maybe /dev/mem can’t be used reliably to pass memory buffers to devices?

This can’t be observed in QEMU unfortunately, since QEMU does not simulate caches.

How to test it out

Now for the fun part. Here are a few cool setups:

  • Userland memory
    • allocate volatile variable on an userland process
    • get the physical address with /proc//maps + /proc//pagemap
    • modify the value at the physical address with devmem , and watch the userland process react
    • allocate kernel memory with kmalloc
    • get the physical address with virt_to_phys and pass it back to userland
    • modify the physical address with devmem
    • query the value from the kernel module
    • create a platform device with known physical register addresses
    • use devmem to write to the register
    • watch printf s come out of the virtual device in response

    Bonus: determine the physical address for a virtual address

    Источник

    Reading kernel memory using a module

    As part of my project I need to read the kernel to get the memory address of system call table and system call address. Or in effect i need to extract the contents of the system call table and all the system calls. Till now I use GDB for this purpose. Is there any way so that I could do it using a kernel module. I am new the kernel module programming. Looking for advice from experts here.

    1 Answer 1

    Let me first start by saying reading arbitrary kernel memory is tricky business! And there are many ways to do it, which vary in their degree of complexity and flexability.

    1) Hard-code the address.

    Search for it in your kernel version’s System.map file:

    # grep sys_call_table /boot/System.map-2.6.18-238.12.1.el5 c06254e0 R sys_call_table 

    With this, hard-code the address:

    unsigned long *syscall_table = (unsigned long *)0xc06254e0; 

    Then, assuming you #include , you can use the __NR_syscall definitions to grab the addresses of those syscalls within the code:

    This is the easiest method, but by far the least flexible. This module will only work on that exact kernel. If you insmod it into a different kernel, you’re liable to get a kernel OOPs.

    2) Brute-force scan for the table

    He uses a method to brute force the kernel memory address range to find the sys_call_stable. As-is, it only works on 32bit (64bit has a different memory address range for the kernel).

    This method is somewhat flexible, but may break down the road as the kernel semantics change.

    3) Dynamically search System.map load time

    You can read your kernel’s System.map file when you load the module. I demonstrate this in the tpe-lkm module I wrote. The project is hosted on github.

    Have a look at the find_symbol_address_from_file() from this file:

    Very flexible, as you can find any symbol you want, but reading files from kernel space is a big ‘no no’. Don’t ask me why, but people are always telling me that. You also run the risk that the System.map it looks at is invalid, and could cause a kernel OOPs. Also, the code is. messy.

    4) Use kallsyms_on_each_symbol()

    As of around kernel version 2.6.30, the kernel exports kallsyms_on_each_symbol(). We can thank the ksplice folks for that. With this you can’t find the sys_call_table (it isn’t in there for some reason), but you can find most other symbols.

    Very flexible, very stable method of finding addresses of symbols, but somewhat complicated to understand 😉

    I demonstrate this in my tpe-lkm project. Have a look at the find_symbol_callback() and find_symbol_address() function in this file:

    Источник

    accessing physical memory from linux kernel

    Can we access any physical memory via some kernel code.? Because, i wrote a device driver which only had init_module and exit_module.. the code is following.

    and a dummy exit_module.. the problem is the computer gets hung when i do lsmod.. What happens? Should i get some kinda permission to access the mem location? kindly explain.. I’m a beginner!

    This is a very complicated programming area and you’re not likely to get the answer you need in such limited space. Have you read any documentation in this area?

    yeah, i know the basics.. the question is i know i can access physical memory as a device driver. Bu why does my PC freeze.. after all i’m just reading ; not writing. ?

    It’s likely that the address 0x10 is a special register that you can’t just read. You’re treading in dangerous waters here. Arbitrary memory accesses can be hazardous to your health.

    Even the kernel has no direct access to physical memory in the way your are thinking. Basically the kind of memory you seem to imagine (linear memory with flat addressing) is something that is constructed by the kernel (from physical memory banks) and exported, it doesn’t «exist». To know about these things and on how to access the different kind of addresses the kernel can handle you really would have to look deeper into the kernel documentation. (Also a value that is not divisible by 4 is certainly a bad choice to expect an unsigned ).

    This code is not attempting to access physical memory. It’s attempting to access an invalid (unmapped) address in virtual memory. This is rather bad. 🙂

    3 Answers 3

    To access real physical memory you should use phys_to_virt function. In case it is io memory (e.g. PCI memory) you should have a closer look at ioremap.

    This whole topic is very complex, if you are a beginner I would suggest some kernel/driver development books/doc.

    I suggest reading the chapter about memory in this book:

    It’s available online for free. Good stuff!

    Inside the kernel, memory is still mapped virtually, just not the same way as in userspace.

    The chances are that 0x10 is in a guard page or something, to catch null pointers, so it generates an unhandled page fault in the kernel when you touch it.

    Normally this causes an OOPS not a hang (but it can be configured to cause a panic). OOPS is an unexpected kernel condition which can be recovered from in some cases, and does not necessarily bring down the whole system. Normally it kills the task (in this case, insmod)

    Did you do this on a desktop Linux system with a GUI loaded? I recommend that you set up a Linux VM (Vmware, virtualbox etc) with a simple (i.e. quick to reboot) text-based distribution if you want to hack around with the kernel. You’re going to crash it a bit and you want it to reboot as quickly as possible. Also by using a text-based distribution, it is easier to see kernel crash messages (Oops or panic)

    Источник

Оцените статью
Adblock
detector