I’d like to allocate a user space buffer in a kernel module (linux kernel v5.4.0). According to this post, this should be doable by using do_mmap()
.
I’ve written the following code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/fcntl.h>
#include <linux/uio.h>
#include <linux/mm.h>
#include <linux/kallsyms.h>
#include <linux/mman.h>
#include <linux/string.h>
unsigned long (*orig_do_mmap)(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flags, vm_flags_t vm_flags,
unsigned long pgoff, unsigned long *populate,
struct list_head *uf);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chibi Gwen");
MODULE_DESCRIPTION("a simple module");
MODULE_VERSION("0.1");
static int __init start(void)
{
printk(KERN_INFO, "module installedn");
unsigned long populate;
orig_do_mmap = kallsyms_lookup_name("do_mmap");
if (orig_do_mmap == NULL)
{
printk("cannot find do_mmap() via kallsyms_lookup_name()n");
return -EINVAL;
}
struct mm_struct *mm = current->mm;
down_write(&mm->mmap_sem);
unsigned char *buf= (unsigned char *)orig_do_mmap(NULL, 0, 0x2000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_LOCKED, 0, 0, &populate, NULL);
up_write(&mm->mmap_sem);
memset(buf, 0x0, 0x2000);
return 0;
}
static void __exit end(void)
{
printk(KERN_INFO, "module uninstalledn");
}
module_init(start);
module_exit(end);
However, when executing memset()
, the kernel complains:
[ 74.674862] BUG: unable to handle page fault for address: 00007f8945966000
[ 74.674864] #PF: supervisor write access in kernel mode
[ 74.674865] #PF: error_code(0x0002) - not-present page
Indeed do_mmap()
successfully returns, and 00007f8945966000 happens to be the address of buf
. My guess is that my code hasn’t initialized the corresponding page table entry.
What is the correct way to allocate a buffer in user space from a kernel module?
Any ideas?