linux-kernelkernel-modulekernel-mode

How do you write directly to user memory from kernel mode in Linux?


I am trying to write directly from a kernel module into a process that it creates without a copy. Note that I cannot simply allocate the memory in kernel mode and map it to userland like you would normally do, I need the memory to eventually originate from the process itself (eventually from a call to the CUDA runtime).

Right now I have a proc file setup with a write callback which I use to send the buffer from userland:

char *buffer;
const size_t PAGE_SIZE = getpagesize();
posix_memalign(&buffer,PAGE_SIZE,PAGE_SIZE);
*buffer = 89;
    
FILE *fp = fopen("/proc/dt/alloc", "w");
fwrite(buffer, 1, 100, fp);

In the kernel module I map the page to kernel memory and modify the first byte as follows:

static ssize_t write_proc_alloc(struct file *file, const char __user *ubuf, size_t count, loff_t *data)
{
    struct page *pages[1];
    mmap_read_lock(current->mm);
    pin_user_pages((unsigned long)ubuf,1, FOLL_WRITE, pages);
    char *buf = kmap(pages[0]);

    *buf = 123;

    kunmap(pages[0]);
    set_page_dirty(pages[0]);
    unpin_user_pages(pages, 1);
    mmap_read_unlock(current->mm);
}

I have made sure to set the page to dirty after, and yet still it remains unchanged after fwrite returns. Why is my modification not visible, and how do I directly modify the provided buffer without having to resort to copy_to_user and the like?


Solution

  • Thanks to Ian Abbott for leading me down the right path.

    The solution was to use a level of indirection, since the pointer passed to the kernel function write_proc_alloc is not the same one the user provides. Instead you write a pointer, copy that by value using get_user(ptr,(uintptr_t*)ubuf) and then from there map the memory and write as before.