Correct way of doing a safe copy from a range of kernel addresses that could contain invalid addresses? - linux-kernel

I need to read from a kernel address called myKernelAddress to myKernelAddress + size and copy it to my buffer.
But the problem is that some addresses between myKernelAddress to myKernelAddress + size could be invalid. So my question is what is proper and safe way of doing this copy, which also saves me from a kernel panic? Do I need to manually check every address between myKernelAddress to myKernelAddress + size with virt_addr_valid, or is there a better way?

Related

What is difference between moving location counter in a linker script and making empty space

I have a question about linker script "vmlinux.lds.S" in the Linux kernel, v4.6. Since its code is quite long, I post a link for it: https://android.googlesource.com/kernel/msm/+/android-wear-5.1.1_r0.6/arch/arm64/kernel/vmlinux.lds.S?autodive=0%2F%2F%2F%2F
As far as I know, moving location counter(.) in a linker script makes empty space. For instance, by saying ". += 1000" one gets 1000 bytes of empty space.
However, the linker script starts with:
. = PAGE_OFFSET + TEXT_OFFSET;
Here, page offset is a (virtual) start address of the kernel space.(i.e. 0xFF...FF00...00)
Ofcourse, assigning this large value to location counter doesn't mean that we get such big empty space. Only VMA is assigned, and LMA is someting like 0x8000.
Why this code doesn't generate large empty space? Is there any exceptional rule about moving location counter?
What determines actual LMA of the kernel code(starting with _stext section)?
Thank you.

What is the best way to reserve a very large virtual address space (TBs) in the kernel?

I'm trying to manually update TLB to translate new virtual memory pages into a certain set of physical pages in the kernel space. I want to do this in do_page_fault so that whenever a load/store instruction happens in a particular virtual address range (not already assigned), it put a page table entry in TLB in advance. The translation is simple. For example, I would like the following piece of code work properly:
int d;
int *pd = (int*)(&d + 0xffff000000000000);
*pd = 25; // A page fault occurs and TLB is updated
printk("d = %d\n", *pd); // No page fault (TLB is already up-to-date)
So, the translation is just a subtraction by 0xffff000000000000. I was wondering what is the best way to implement the TLB update functionality?
Edit: The main reason for doing that is to be able to reserve a large virtual memory space in the kernel. I just want to handle page faults in a particular address range in the kernel. So, first I have to reserve the address range (maybe exceeds the 100TB limitation). Then, I have to implement a page cache for that particular range. If it is not possible, what is the best solution for that?

How device name is copied in ip_rt_ioctl in fib_frontend.c

I have one doubt in ip_rt_ioctl function
In case of route addition, first a copy_from_user is made for the structure struct rtentry and then the copied data from is subsequently used in rtentry_to_fib_config function, including the rtentry.rt_dev field which usually is the device name.
My understanding is copy_from_user does a shallow copy. So since the rtentry.rt_dev field is again a character pointer. So likely the contents of the pointer will not get copied.
Hence even after copy the device name will be pointer to the user space address.
So is it right to access the user space address from kernel space ?
It's OK to refer to user-space address from kernel-space while kernel is bound to that process' context (this is true for syscall handlers). In that case, proper page table is set and it's safe to refer to user process' memory.
However, you should always check validity of address or use copy_from_user() that does that.

User space mmap and driver space mmap point to different addresses..?

[I am a newbie to device driver programming, so requesting people to be patient]
I am writing a character device driver, and I am trying to mmap some portion of the allocated memory in the driver to the user space.
In the init_module() function, I allocate the some buffer space like this -
buf = (char*)vmalloc_user(SIZE_OF_BUFFER);
buf now points to some address.
Now, in the driver's mmap function, I set the VM_RESERVED flag, and call
remap_vmalloc_range(vma, (void*)buf, 0);
Then I create a character device file in /dev with the correct major number.
Now I create a simple program in the user space to open the character device file, then call mmap() and read data from this mmap'ed memory.
In the call to mmap() in userspace, I know there is an option where we can pass the start address of the area. But is there a way the user space mmap can point to the same address as done by the buf in the driver space?
I think that because the address of buf in the driver space is different from the one returned by mmap() in the user space, my user space program ends up reading junk values. Is there any other way than actually entering the address in the mmap() in the user space to solve this problem?
You pretty much have to design your driver interface so that the userspace map address doesn't matter. This means, for example, not storing pointers in an mmap region that's accessed outside of a single userspace process.
Typically, you'd store offsets from the base mapped address instead of full pointers. The kernel driver and userspace code can both add these offsets to their base pointers, and get to the virtual address that's right for their respective contexts.

How can I access memory at known physical address inside a kernel module?

I am trying to work on this problem: A user spaces program keeps polling a buffer to get requests from a kernel module and serves it and then responses to the kernel.
I want to make the solution much faster, so instead of creating a device file and communicating via it, I allocate a memory buffer from the user space and mark it as pinned, so the memory pages never get swapped out. Then the user space invokes a special syscall to tell the kernel about the memory buffer so that the kernel module can get the physical address of that buffer. (because the user space program may be context-switched out and hence the virtual address means nothing if the kernel module accesses the buffer at that time.)
When the module wants to send request, it needs put the request to the buffer via physical address. The question is: How can I access the buffer inside the kernel module via its physical address.
I noticed there is get_user_pages, but don't know how to use it, or maybe there are other better methods?
Thanks.
You are better off doing this the other way around - have the kernel allocate the buffer, then allow the userspace program to map it into its address space using mmap().
Finally I figured out how to handle this problem...
Quite simple but may be not safe.
use phys_to_virt, which calls __va(pa), to get the virtual address in kernel and I can access that buffer. And because the buffer is pinned, that can guarantee the physical location is available.
What's more, I don't need s special syscall to tell the kernel the buffer's info. Instead, a proc file is enough because I just need tell the kernel once.

Resources